From 3094c36c8199cd50f013d9efa6e9e372b7c9fc60 Mon Sep 17 00:00:00 2001 From: Charles Dick Date: Wed, 30 Nov 2016 12:43:43 -0800 Subject: [PATCH] remove old heap capture in preparation for pull from tracery-prerelease Reviewed By: bnham Differential Revision: D4250926 fbshipit-source-id: 7cfbb8d8aae5ef150f0260c92e946d569e41f7fb --- .../middleware/heapCapture/out/aggrow.js | 762 ------------------ .../middleware/heapCapture/out/heapCapture.js | 381 --------- .../middleware/heapCapture/out/table.js | 541 ------------- .../middleware/heapCapture/src/aggrow.js | 760 ----------------- .../middleware/heapCapture/src/heapCapture.js | 379 --------- .../middleware/heapCapture/src/table.js | 540 ------------- 6 files changed, 3363 deletions(-) delete mode 100644 local-cli/server/middleware/heapCapture/out/aggrow.js delete mode 100644 local-cli/server/middleware/heapCapture/out/heapCapture.js delete mode 100644 local-cli/server/middleware/heapCapture/out/table.js delete mode 100644 local-cli/server/middleware/heapCapture/src/aggrow.js delete mode 100644 local-cli/server/middleware/heapCapture/src/heapCapture.js delete mode 100644 local-cli/server/middleware/heapCapture/src/table.js diff --git a/local-cli/server/middleware/heapCapture/out/aggrow.js b/local-cli/server/middleware/heapCapture/out/aggrow.js deleted file mode 100644 index e5eec1099..000000000 --- a/local-cli/server/middleware/heapCapture/out/aggrow.js +++ /dev/null @@ -1,762 +0,0 @@ -/** - * Copyright (c) 2016-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; -/*eslint no-bitwise: "off"*/ -/*eslint no-console-disallow: "off"*/ - -// TODO: future features -// put in a module.exports -// filtering / search -// pivot around frames in the middle of a stack by callers / callees -// graphing? - -function StringInterner(){// eslint-disable-line no-unused-vars -var strings=[]; -var ids={}; -return{ -intern:function internString(s){ -var find=ids[s]; -if(find===undefined){ -var id=strings.length; -ids[s]=id; -strings.push(s); -return id; -}else{ -return find; -} -}, -get:function getString(id){ -return strings[id]; -}}; - -} - -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}; -this.nodeCount++; -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; -for(var frameId in tree){ -if(frameId!=='id'){ -leaf=countStacks(tree[frameId],depth+1); -} -} -if(leaf){ -stackFrameCount+=depth; -} -return false; -} -countStacks(this.root,0); -console.log('size needed to store stacks: '+(stackFrameCount*4).toString()+'B'); -var stackIdMap=new Array(this.nodeCount); -var stackArray=new Int32Array(stackFrameCount); -var maxStackDepth=0; -stackFrameCount=0; -function flattenStacksImpl(tree,stack){ -var childStack=void 0; -maxStackDepth=Math.max(maxStackDepth,stack.length); -for(var frameId in tree){ -if(frameId!=='id'){ -stack.push(Number(frameId)); -childStack=flattenStacksImpl(tree[frameId],stack); -stack.pop(); -} -} - -var id=tree.id; -if(id<0||id>=stackIdMap.length||stackIdMap[id]!==undefined){ -throw'invalid stack id!'; -} - -if(childStack!==undefined){ -// each child must have our stack as a prefix, so just use that -stackIdMap[id]=childStack.subarray(0,stack.length); -}else{ -var newStack=stackArray.subarray(stackFrameCount,stackFrameCount+stack.length); -stackFrameCount+=stack.length; -for(var i=0;i=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; -var STACK_EXPANDER_ID_MIN=0x8000; -var STACK_EXPANDER_ID_MAX=0xffff; - -// used for row.expander which reference state.activeExpanders (with frame index masked in) -var INVALID_ACTIVE_EXPANDER=-1; -var ACTIVE_EXPANDER_MASK=0xffff; -var ACTIVE_EXPANDER_FRAME_SHIFT=16; - -// aggregator ID definitions -var AGGREGATOR_ID_MAX=0xffff; - -// active aggragators can have sort order changed in the reference -var ACTIVE_AGGREGATOR_MASK=0xffff; -var ACTIVE_AGGREGATOR_ASC_BIT=0x10000; - -// tree node state definitions -var NODE_EXPANDED_BIT=0x0001;// this row is expanded -var NODE_REAGGREGATE_BIT=0x0002;// children need aggregates -var NODE_REORDER_BIT=0x0004;// children need to be sorted -var NODE_REPOSITION_BIT=0x0008;// children need position -var NODE_INDENT_SHIFT=16; - -function calleeFrameIdGetter(stack,depth){ -return stack[depth]; -} - -function callerFrameIdGetter(stack,depth){ -return stack[stack.length-depth-1]; -} - -function createStackComparers(stackGetter,frameIdGetter,maxStackDepth){ -var comparers=new Array(maxStackDepth);var _loop=function _loop( -depth){ -var captureDepth=depth;// NB: to capture depth per loop iteration -comparers[depth]=function calleeStackComparer(rowA,rowB){ -var a=stackGetter(rowA); -var b=stackGetter(rowB); -// NB: we put the stacks that are too short at the top, -// so they can be grouped into the '' bucket -if(a.length<=captureDepth&&b.length<=captureDepth){ -return 0; -}else if(a.length<=captureDepth){ -return-1; -}else if(b.length<=captureDepth){ -return 1; -} -return frameIdGetter(a,captureDepth)-frameIdGetter(b,captureDepth); -};};for(var depth=0;depth>>NODE_INDENT_SHIFT)+1; -var state=NODE_REPOSITION_BIT| -NODE_REAGGREGATE_BIT| -NODE_REORDER_BIT| -indent<',indices,INVALID_ACTIVE_EXPANDER)}; - - -function evaluateAggregate(row){ -var activeAggregators=state.activeAggregators; -var aggregates=new Array(activeAggregators.length); -for(var j=0;j=top&&row.top -var begin=0; -var beginStack=null; -row.children=[]; -while(begindepth){ -break; -} -begin++; -} -if(begin>0){ -row.children.push(createTreeNode( -row, -columnName+'', -rowIndices.subarray(0,begin), -nextActiveIndex)); -} -// aggregate the rest under frames -if(begin=FIELD_EXPANDER_ID_MAX){ -throw'too many field expanders!'; -} -state.fieldExpanders.push({ -name:name,// name for column -formatter:formatter,// row index -> display string -comparer:comparer}); - -return FIELD_EXPANDER_ID_MIN+state.fieldExpanders.length-1; -}, -addCalleeStackExpander:function addCalleeStackExpander(name,maxStackDepth,stackGetter,frameGetter){ -if(STACK_EXPANDER_ID_MIN+state.fieldExpanders.length>=STACK_EXPANDER_ID_MAX){ -throw'too many stack expanders!'; -} -state.stackExpanders.push({ -name:name,// name for column -stackGetter:stackGetter,// row index -> stack array -comparers:createStackComparers(stackGetter,calleeFrameIdGetter,maxStackDepth),// depth -> comparer -frameIdGetter:calleeFrameIdGetter,// (stack, depth) -> string id -frameGetter:frameGetter}); - -return STACK_EXPANDER_ID_MIN+state.stackExpanders.length-1; -}, -addCallerStackExpander:function addCallerStackExpander(name,maxStackDepth,stackGetter,frameGetter){ -if(STACK_EXPANDER_ID_MIN+state.fieldExpanders.length>=STACK_EXPANDER_ID_MAX){ -throw'too many stack expanders!'; -} -state.stackExpanders.push({ -name:name, -stackGetter:stackGetter, -comparers:createStackComparers(stackGetter,callerFrameIdGetter,maxStackDepth), -frameIdGetter:callerFrameIdGetter, -frameGetter:frameGetter}); - -return STACK_EXPANDER_ID_MIN+state.stackExpanders.length-1; -}, -getExpanders:function getExpanders(){ -var expanders=[]; -for(var _i7=0;_i7=FIELD_EXPANDER_ID_MIN&&id<=FIELD_EXPANDER_ID_MAX){ -return state.fieldExpanders[id-FIELD_EXPANDER_ID_MIN].name; -}else if(id>=STACK_EXPANDER_ID_MIN&&id<=STACK_EXPANDER_ID_MAX){ -return state.stackExpanders[id-STACK_EXPANDER_ID_MIN].name; -} -throw'Unknown expander ID '+id.toString(); -}, -setActiveExpanders:function setActiveExpanders(ids){ -for(var _i9=0;_i9=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!'; -} -}else if(id>=STACK_EXPANDER_ID_MIN&&id<=STACK_EXPANDER_ID_MAX){ -if(id-STACK_EXPANDER_ID_MIN>=state.stackExpanders.length){ -throw'stack expander for id '+id.toString()+' does not exist!'; -} -} -} -for(var _i10=0;_i10=AGGREGATOR_ID_MAX){ -throw'too many aggregators!'; -} -state.aggregators.push({ -name:name,// name for column -aggregator:aggregator,// index array -> aggregate value -formatter:formatter,// aggregate value -> display string -sorter:sorter}); - -return state.aggregators.length-1; -}, -getAggregators:function getAggregators(){ -var aggregators=[]; -for(var _i11=0;_i11state.aggregators.length){ -throw'aggregator id '+id.toString()+' not valid'; -} -} -state.activeAggregators=ids.slice(); -// NB: evaluate root here because dirty bit is for children -// 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( -_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=_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 _i13=ids.length-1;_i13>=0;_i13--){_loop2(_i13); -} -state.sorter=sorter; -state.root.state|=NODE_REORDER_BIT; -}, -getActiveAggregators:function getActiveAggregators(){ -return state.activeAggregators.slice(); -}, -getRows:function getRows(top,height){ -var result=new Array(height); -for(var _i14=0;_i14>>NODE_INDENT_SHIFT; -}, -getRowAggregate:function getRowAggregate(row,index){ -var aggregator=state.aggregators[state.activeAggregators[index]]; -return aggregator.formatter(row.aggregates[index]); -}, -getHeight:function getHeight(){ -return state.root.height; -}, -canExpand:function canExpand(row){ -return(row.state&NODE_EXPANDED_BIT)===0&&row.expander!==INVALID_ACTIVE_EXPANDER; -}, -canContract:function canContract(row){ -return(row.state&NODE_EXPANDED_BIT)!==0; -}, -expand:function expand(row){ -if((row.state&NODE_EXPANDED_BIT)!==0){ -throw'can not expand row, already expanded'; -} -if(row.height!==1){ -throw'unexpanded row has height '+row.height.toString()+' != 1'; -} -if(row.children===null){// first expand, generate children -var activeIndex=row.expander&ACTIVE_EXPANDER_MASK; -var nextActiveIndex=activeIndex+1;// NB: if next is stack, frame is 0 -if(nextActiveIndex>=state.activeExpanders.length){ -nextActiveIndex=INVALID_ACTIVE_EXPANDER; -} -if(activeIndex>=state.activeExpanders.length){ -throw'invalid active expander index '+activeIndex.toString(); -} -var exId=state.activeExpanders[activeIndex]; -if(exId>=FIELD_EXPANDER_ID_MIN&& -exId=STACK_EXPANDER_ID_MIN&& -exId>>ACTIVE_EXPANDER_FRAME_SHIFT; -var _expander=state.stackExpanders[exId-STACK_EXPANDER_ID_MIN]; -addChildrenWithStackExpander(row,_expander,activeIndex,depth,nextActiveIndex); -}else{ -throw'state.activeIndex '+activeIndex.toString()+ -' has invalid expander'+exId.toString(); -} -} -row.state|=NODE_EXPANDED_BIT| -NODE_REAGGREGATE_BIT|NODE_REORDER_BIT|NODE_REPOSITION_BIT; -var heightChange=0; -for(var _i15=0;_i150){_loop(); -} -} - -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. -var rowCount=0; -for(var id in capture.refs){// eslint-disable-line no-unused-vars -rowCount++; -} -for(var _id in capture.markedBlocks){// eslint-disable-line no-unused-vars -rowCount++; -} -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; -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]; -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'); - -} -inserter.done(); -} - -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}]; - -var data=new AggrowData(columns); -registerCapture(data,'trace',preLoadedCapture,stacks,strings); -preLoadedCapture=undefined;// let GG clean up the capture -var aggrow=new Aggrow(data); -aggrow.addPointerExpander('Id','id'); -var typeExpander=aggrow.addStringExpander('Type','type'); -aggrow.addNumberExpander('Size','size'); -aggrow.addStringExpander('Trace','trace'); -var pathExpander=aggrow.addStackExpander('Path','path',strings.get); -var reactExpander=aggrow.addStackExpander('React Tree','react',strings.get); -var valueExpander=aggrow.addStringExpander('Value','value'); -var moduleExpander=aggrow.addStringExpander('Module','module'); -aggrow.expander.setActiveExpanders([ -pathExpander, -reactExpander, -moduleExpander, -typeExpander, -valueExpander]); - -var sizeAggregator=aggrow.addSumAggregator('Size','size'); -var countAggregator=aggrow.addCountAggregator('Count'); -aggrow.expander.setActiveAggregators([ -sizeAggregator, -countAggregator]); - -ReactDOM.render(React.createElement(Table,{aggrow:aggrow.expander}),document.body); -} -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9oZWFwQ2FwdHVyZS5qcyJdLCJuYW1lcyI6WyJSZWZWaXNpdG9yIiwicmVmcyIsImlkIiwicHJvdG90eXBlIiwibW92ZVRvRWRnZSIsIm5hbWUiLCJyZWYiLCJlZGdlcyIsImVkZ2VJZCIsInVuZGVmaW5lZCIsIm1vdmVUb0ZpcnN0IiwiY2FsbGJhY2siLCJmb3JFYWNoRWRnZSIsInZpc2l0b3IiLCJnZXRUeXBlIiwidHlwZSIsImdldFJlZiIsImNsb25lIiwiaXNEZWZpbmVkIiwiZ2V0VmFsdWUiLCJ2YWx1ZSIsInJvcGUiLCJzdGFydHNXaXRoIiwiZW5kc1dpdGgiLCJpbmRleCIsInBhcnNlSW50Iiwic3Vic3RyaW5nIiwibGVuZ3RoIiwiam9pbiIsInVybCIsImxpbmUiLCJjb2wiLCJmdW5jdGlvbiIsImNvbnN0cnVjdG9yIiwiZXhlY3V0YWJsZSIsImZvckVhY2hSZWYiLCJmaXJzdFJlZiIsImdldEludGVybmFsSW5zdGFuY2VOYW1lIiwiZGlzcGxheU5hbWUiLCJidWlsZFJlYWN0Q29tcG9uZW50VHJlZSIsInJlZ2lzdHJ5Iiwic3RyaW5ncyIsInJlYWN0VHJlZSIsInJlYWN0UGFyZW50IiwicGFyZW50VmlzaXRvciIsImluc2VydCIsInJvb3QiLCJpbnRlcm4iLCJwYXJlbnRSZWYiLCJyZWxhdGl2ZU5hbWUiLCJyZWFjdEtleSIsIm1hcmtSZWFjdENvbXBvbmVudFRyZWUiLCJ2aXNpdG9yQ2xvbmUiLCJlZGdlTmFtZSIsImVkZ2VWaXNpdG9yIiwiZWRnZVJlZiIsImNoaWxkTmFtZSIsImNoaWxkVmlzaXRvciIsImNoaWxkUmVmIiwiaW5zdGFuY2VSZWYiLCJmdW5jdGlvblVybEZpbGVOYW1lIiwiZmlsZSIsImxhc3RJbmRleE9mIiwibWFya01vZHVsZXMiLCJtb2R1bGVzIiwibWVtYmVyTmFtZSIsIm1lbWJlciIsIm1vZHVsZSIsInJlZ2lzdGVyUGF0aFRvUm9vdCIsImJyZWFkdGgiLCJyb290UGF0aCIsInB1c2giLCJuZXh0QnJlYWR0aCIsImkiLCJwYXRoTmFtZSIsInJlZ2lzdGVyQ2FwdHVyZSIsImRhdGEiLCJjYXB0dXJlSWQiLCJjYXB0dXJlIiwic3RhY2tzIiwicm93Q291bnQiLCJtYXJrZWRCbG9ja3MiLCJpbnNlcnRlciIsInJvd0luc2VydGVyIiwibm9uZVN0cmluZyIsIm5vbmVTdGFjayIsImluc2VydFJvdyIsInNpemUiLCJibG9jayIsImNhcGFjaXR5IiwiY2VsbFNpemUiLCJkb25lIiwicHJlTG9hZGVkQ2FwdHVyZSIsIlN0cmluZ0ludGVybmVyIiwiU3RhY2tSZWdpc3RyeSIsImNvbHVtbnMiLCJBZ2dyb3dEYXRhIiwiYWdncm93IiwiQWdncm93IiwiYWRkUG9pbnRlckV4cGFuZGVyIiwidHlwZUV4cGFuZGVyIiwiYWRkU3RyaW5nRXhwYW5kZXIiLCJhZGROdW1iZXJFeHBhbmRlciIsInBhdGhFeHBhbmRlciIsImFkZFN0YWNrRXhwYW5kZXIiLCJnZXQiLCJyZWFjdEV4cGFuZGVyIiwidmFsdWVFeHBhbmRlciIsIm1vZHVsZUV4cGFuZGVyIiwiZXhwYW5kZXIiLCJzZXRBY3RpdmVFeHBhbmRlcnMiLCJzaXplQWdncmVnYXRvciIsImFkZFN1bUFnZ3JlZ2F0b3IiLCJjb3VudEFnZ3JlZ2F0b3IiLCJhZGRDb3VudEFnZ3JlZ2F0b3IiLCJzZXRBY3RpdmVBZ2dyZWdhdG9ycyIsIlJlYWN0RE9NIiwicmVuZGVyIiwiZG9jdW1lbnQiLCJib2R5Il0sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7QUFRQTtBQUNBO0FBQ0E7O0FBRUEsUUFBU0EsV0FBVCxDQUFvQkMsSUFBcEIsQ0FBMEJDLEVBQTFCLENBQThCO0FBQzVCLEtBQUtELElBQUwsQ0FBWUEsSUFBWjtBQUNBLEtBQUtDLEVBQUwsQ0FBVUEsRUFBVjtBQUNEOztBQUVERixXQUFXRyxTQUFYLENBQXVCO0FBQ3JCQyxXQUFZLFFBQVNBLFdBQVQsQ0FBb0JDLElBQXBCLENBQTBCO0FBQ3BDLEdBQU1DLEtBQU0sS0FBS0wsSUFBTCxDQUFVLEtBQUtDLEVBQWYsQ0FBWjtBQUNB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UCxDQUF5QixNQUF6QixDQUFpQyxNQUFqQztBQUNBTCxPQUFPSSxpQkFBUCxDQUF5QixPQUF6QixDQUFrQyxPQUFsQztBQUNBLEdBQU1FLGNBQWVOLE9BQU9PLGdCQUFQLENBQXdCLE1BQXhCLENBQWdDLE1BQWhDLENBQXdDL0QsUUFBUWdFLEdBQWhELENBQXJCO0FBQ0EsR0FBTUMsZUFBZ0JULE9BQU9PLGdCQUFQLENBQXdCLFlBQXhCLENBQXNDLE9BQXRDLENBQStDL0QsUUFBUWdFLEdBQXZELENBQXRCO0FBQ0EsR0FBTUUsZUFBZ0JWLE9BQU9JLGlCQUFQLENBQXlCLE9BQXpCLENBQWtDLE9BQWxDLENBQXRCO0FBQ0EsR0FBTU8sZ0JBQWlCWCxPQUFPSSxpQkFBUCxDQUF5QixRQUF6QixDQUFtQyxRQUFuQyxDQUF2QjtBQUNBSixPQUFPWSxRQUFQLENBQWdCQyxrQkFBaEIsQ0FBbUM7QUFDakNQLFlBRGlDO0FBRWpDRyxhQUZpQztBQUdqQ0UsY0FIaUM7QUFJakNSLFlBSmlDO0FBS2pDTyxhQUxpQyxDQUFuQzs7QUFPQSxHQUFNSSxnQkFBaUJkLE9BQU9lLGdCQUFQLENBQXdCLE1BQXhCLENBQWdDLE1BQWhDLENBQXZCO0FBQ0EsR0FBTUMsaUJBQWtCaEIsT0FBT2lCLGtCQUFQLENBQTBCLE9BQTFCLENBQXhCO0FBQ0FqQixPQUFPWSxRQUFQLENBQWdCTSxvQkFBaEIsQ0FBcUM7QUFDbkNKLGNBRG1DO0FBRW5DRSxlQUZtQyxDQUFyQzs7QUFJQUcsU0FBU0MsTUFBVCxDQUFnQixvQkFBQyxLQUFELEVBQU8sT0FBUXBCLE9BQU9ZLFFBQXRCLEVBQWhCLENBQW9EUyxTQUFTQyxJQUE3RDtBQUNEIiwiZmlsZSI6ImhlYXBDYXB0dXJlLmpzIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTYtcHJlc2VudCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICovXG4ndXNlIHN0cmljdCc7XG4vKmVzbGludCBuby1jb25zb2xlLWRpc2FsbG93OiBcIm9mZlwiKi9cbi8qZ2xvYmFsIFJlYWN0IFJlYWN0RE9NIFRhYmxlIFN0cmluZ0ludGVybmVyIFN0YWNrUmVnaXN0cnkgQWdncm93RGF0YSBBZ2dyb3cgcHJlTG9hZGVkQ2FwdHVyZTp0cnVlKi9cblxuZnVuY3Rpb24gUmVmVmlzaXRvcihyZWZzLCBpZCkge1xuICB0aGlzLnJlZnMgPSByZWZzO1xuICB0aGlzLmlkID0gaWQ7XG59XG5cblJlZlZpc2l0b3IucHJvdG90eXBlID0ge1xuICBtb3ZlVG9FZGdlOiBmdW5jdGlvbiBtb3ZlVG9FZGdlKG5hbWUpIHtcbiAgICBjb25zdCByZWYgPSB0aGlzLnJlZnNbdGhpcy5pZF07XG4gICAgaWYgKHJlZiAmJiByZWYuZWRnZXMpIHtcbiAgICAgIGNvbnN0IGVkZ2VzID0gcmVmLmVkZ2VzO1xuICAgICAgZm9yIChjb25zdCBlZGdlSWQgaW4gZWRnZXMpIHtcbiAgICAgICAgaWYgKGVkZ2VzW2VkZ2VJZF0gPT09IG5hbWUpIHtcbiAgICAgICAgICB0aGlzLmlkID0gZWRnZUlkO1xuICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMuaWQgPSB1bmRlZmluZWQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH0sXG4gIG1vdmVUb0ZpcnN0OiBmdW5jdGlvbiBtb3ZlVG9GaXJzdChjYWxsYmFjaykge1xuICAgIGNvbnN0IHJlZiA9IHRoaXMucmVmc1t0aGlzLmlkXTtcbiAgICBpZiAocmVmICYmIHJlZi5lZGdlcykge1xuICAgICAgY29uc3QgZWRnZXMgPSByZWYuZWRnZXM7XG4gICAgICBmb3IgKGNvbnN0IGVkZ2VJZCBpbiBlZGdlcykge1xuICAgICAgICB0aGlzLmlkID0gZWRnZUlkO1xuICAgICAgICBpZiAoY2FsbGJhY2soZWRnZXNbZWRnZUlkXSwgdGhpcykpIHtcbiAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICB0aGlzLmlkID0gdW5kZWZpbmVkO1xuICAgIHJldHVybiB0aGlzO1xuICB9LFxuICBmb3JFYWNoRWRnZTogZnVuY3Rpb24gZm9yRWFjaEVkZ2UoY2FsbGJhY2spIHtcbiAgICBjb25zdCByZWYgPSB0aGlzLnJlZnNbdGhpcy5pZF07XG4gICAgaWYgKHJlZiAmJiByZWYuZWRnZXMpIHtcbiAgICAgIGNvbnN0IGVkZ2VzID0gcmVmLmVkZ2VzO1xuICAgICAgY29uc3QgdmlzaXRvciA9IG5ldyBSZWZWaXNpdG9yKHRoaXMucmVmcywgdW5kZWZpbmVkKTtcbiAgICAgIGZvciAoY29uc3QgZWRnZUlkIGluIGVkZ2VzKSB7XG4gICAgICAgIHZpc2l0b3IuaWQgPSBlZGdlSWQ7XG4gICAgICAgIGNhbGxiYWNrKGVkZ2VzW2VkZ2VJZF0sIHZpc2l0b3IpO1xuICAgICAgfVxuICAgIH1cbiAgfSxcbiAgZ2V0VHlwZTogZnVuY3Rpb24gZ2V0VHlwZSgpIHtcbiAgICBjb25zdCByZWYgPSB0aGlzLnJlZnNbdGhpcy5pZF07XG4gICAgaWYgKHJlZikge1xuICAgICAgcmV0dXJuIHJlZi50eXBlO1xuICAgIH1cbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9LFxuICBnZXRSZWY6IGZ1bmN0aW9uIGdldFJlZigpIHtcbiAgICByZXR1cm4gdGhpcy5yZWZzW3RoaXMuaWRdO1xuICB9LFxuICBjbG9uZTogZnVuY3Rpb24gY2xvbmUoKSB7XG4gICAgcmV0dXJuIG5ldyBSZWZWaXNpdG9yKHRoaXMucmVmcywgdGhpcy5pZCk7XG4gIH0sXG4gIGlzRGVmaW5lZDogZnVuY3Rpb24gaXNEZWZpbmVkKCkge1xuICAgIHJldHVybiAhIXRoaXMuaWQ7XG4gIH0sXG4gIGdldFZhbHVlOiBmdW5jdGlvbiBnZXRWYWx1ZSgpIHtcbiAgICBjb25zdCByZWYgPSB0aGlzLnJlZnNbdGhpcy5pZF07XG4gICAgaWYgKHJlZikge1xuICAgICAgaWYgKHJlZi50eXBlID09PSAnc3RyaW5nJykge1xuICAgICAgICBpZiAocmVmLnZhbHVlKSB7XG4gICAgICAgICAgcmV0dXJuIHJlZi52YWx1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zdCByb3BlID0gW107XG4gICAgICAgICAgdGhpcy5mb3JFYWNoRWRnZSgobmFtZSwgdmlzaXRvcikgPT4ge1xuICAgICAgICAgICAgaWYgKG5hbWUgJiYgbmFtZS5zdGFydHNXaXRoKCdbJykgJiYgbmFtZS5lbmRzV2l0aCgnXScpKSB7XG4gICAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gcGFyc2VJbnQobmFtZS5zdWJzdHJpbmcoMSwgbmFtZS5sZW5ndGggLSAxKSwgMTApO1xuICAgICAgICAgICAgICByb3BlW2luZGV4XSA9IHZpc2l0b3IuZ2V0VmFsdWUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm4gcm9wZS5qb2luKCcnKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChyZWYudHlwZSA9PT0gJ1NjcmlwdEV4ZWN1dGFibGUnXG4gICAgICAgICAgICAgIHx8IHJlZi50eXBlID09PSAnRXZhbEV4ZWN1dGFibGUnXG4gICAgICAgICAgICAgIHx8IHJlZi50eXBlID09PSAnUHJvZ3JhbUV4ZWN1dGFibGUnKSB7XG4gICAgICAgIHJldHVybiByZWYudmFsdWUudXJsICsgJzonICsgcmVmLnZhbHVlLmxpbmUgKyAnOicgKyByZWYudmFsdWUuY29sO1xuICAgICAgfSBlbHNlIGlmIChyZWYudHlwZSA9PT0gJ0Z1bmN0aW9uRXhlY3V0YWJsZScpIHtcbiAgICAgICAgcmV0dXJuIHJlZi52YWx1ZS5uYW1lICsgJ0AnICsgcmVmLnZhbHVlLnVybCArICc6JyArIHJlZi52YWx1ZS5saW5lICsgJzonICsgcmVmLnZhbHVlLmNvbDtcbiAgICAgIH0gZWxzZSBpZiAocmVmLnR5cGUgPT09ICdOYXRpdmVFeGVjdXRhYmxlJykge1xuICAgICAgICByZXR1cm4gcmVmLnZhbHVlLmZ1bmN0aW9uICsgJyAnICsgcmVmLnZhbHVlLmNvbnN0cnVjdG9yICsgJyAnICsgcmVmLnZhbHVlLm5hbWU7XG4gICAgICB9IGVsc2UgaWYgKHJlZi50eXBlID09PSAnRnVuY3Rpb24nKSB7XG4gICAgICAgIGNvbnN0IGV4ZWN1dGFibGUgPSB0aGlzLmNsb25lKCkubW92ZVRvRWRnZSgnQEV4ZWN1dGFibGUnKTtcbiAgICAgICAgaWYgKGV4ZWN1dGFibGUuaWQpIHtcbiAgICAgICAgICByZXR1cm4gZXhlY3V0YWJsZS5nZXRSZWYoKS50eXBlICsgJyAnICsgZXhlY3V0YWJsZS5nZXRWYWx1ZSgpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiAnI25vbmUnO1xuICB9XG59O1xuXG5mdW5jdGlvbiBmb3JFYWNoUmVmKHJlZnMsIGNhbGxiYWNrKSB7XG4gIGNvbnN0IHZpc2l0b3IgPSBuZXcgUmVmVmlzaXRvcihyZWZzLCB1bmRlZmluZWQpO1xuICBmb3IgKGNvbnN0IGlkIGluIHJlZnMpIHtcbiAgICB2aXNpdG9yLmlkID0gaWQ7XG4gICAgY2FsbGJhY2sodmlzaXRvcik7XG4gIH1cbn1cblxuZnVuY3Rpb24gZmlyc3RSZWYocmVmcywgY2FsbGJhY2spIHtcbiAgZm9yIChjb25zdCBpZCBpbiByZWZzKSB7XG4gICAgY29uc3QgcmVmID0gcmVmc1tpZF07XG4gICAgaWYgKGNhbGxiYWNrKGlkLCByZWYpKSB7XG4gICAgICByZXR1cm4gbmV3IFJlZlZpc2l0b3IocmVmcywgaWQpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gbmV3IFJlZlZpc2l0b3IocmVmcywgdW5kZWZpbmVkKTtcbn1cblxuZnVuY3Rpb24gZ2V0SW50ZXJuYWxJbnN0YW5jZU5hbWUodmlzaXRvcikge1xuICBjb25zdCB0eXBlID0gdmlzaXRvci5jbG9uZSgpLm1vdmVUb0VkZ2UoJ19jdXJyZW50RWxlbWVudCcpLm1vdmVUb0VkZ2UoJ3R5cGUnKTtcbiAgaWYgKHR5cGUuZ2V0VHlwZSgpID09PSAnc3RyaW5nJykgeyAvLyBlbGVtZW50LnR5cGUgaXMgc3RyaW5nXG4gICAgcmV0dXJuIHR5cGUuZ2V0VmFsdWUoKTtcbiAgfSBlbHNlIGlmICh0eXBlLmdldFR5cGUoKSA9PT0gJ0Z1bmN0aW9uJykgeyAvLyBlbGVtZW50LnR5cGUgaXMgZnVuY3Rpb25cbiAgICBjb25zdCBkaXNwbGF5TmFtZSA9IHR5cGUuY2xvbmUoKS5tb3ZlVG9FZGdlKCdkaXNwbGF5TmFtZScpO1xuICAgIGlmIChkaXNwbGF5TmFtZS5pc0RlZmluZWQoKSkge1xuICAgICAgcmV0dXJuIGRpc3BsYXlOYW1lLmdldFZhbHVlKCk7IC8vIGVsZW1lbnQudHlwZS5kaXNwbGF5TmFtZVxuICAgIH1cbiAgICBjb25zdCBuYW1lID0gdHlwZS5jbG9uZSgpLm1vdmVUb0VkZ2UoJ25hbWUnKTtcbiAgICBpZiAobmFtZS5pc0RlZmluZWQoKSkge1xuICAgICAgcmV0dXJuIG5hbWUuZ2V0VmFsdWUoKTsgLy8gZWxlbWVudC50eXBlLm5hbWVcbiAgICB9XG4gICAgdHlwZS5tb3ZlVG9FZGdlKCdARXhlY3V0YWJsZScpO1xuICAgIGlmICh0eXBlLmdldFR5cGUoKSA9PT0gJ0Z1bmN0aW9uRXhlY3V0YWJsZScpIHtcbiAgICAgIHJldHVybiB0eXBlLmdldFJlZigpLnZhbHVlLm5hbWU7ICAvLyBlbGVtZW50LnR5cGUgc3ltYm9saWNhdGVkIG5hbWVcbiAgICB9XG4gIH1cbiAgcmV0dXJuICcjdW5rbm93bic7XG59XG5cbmZ1bmN0aW9uIGJ1aWxkUmVhY3RDb21wb25lbnRUcmVlKHZpc2l0b3IsIHJlZ2lzdHJ5LCBzdHJpbmdzKSB7XG4gIGNvbnN0IHJlZiA9IHZpc2l0b3IuZ2V0UmVmKCk7XG4gIGlmIChyZWYucmVhY3RUcmVlIHx8IHJlZi5yZWFjdFBhcmVudCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuOyAvLyBoYXMgb25lIG9yIGRvZXNuJ3QgbmVlZCBvbmVcbiAgfVxuICBjb25zdCBwYXJlbnRWaXNpdG9yID0gcmVmLnJlYWN0UGFyZW50O1xuICBpZiAocGFyZW50VmlzaXRvciA9PT0gbnVsbCkge1xuICAgIHJlZi5yZWFjdFRyZWUgPSByZWdpc3RyeS5pbnNlcnQocmVnaXN0cnkucm9vdCwgc3RyaW5ncy5pbnRlcm4oZ2V0SW50ZXJuYWxJbnN0YW5jZU5hbWUodmlzaXRvcikpKTtcbiAgfSBlbHNlIGlmIChwYXJlbnRWaXNpdG9yKSB7XG4gICAgY29uc3QgcGFyZW50UmVmID0gcGFyZW50VmlzaXRvci5nZXRSZWYoKTtcbiAgICBidWlsZFJlYWN0Q29tcG9uZW50VHJlZShwYXJlbnRWaXNpdG9yLCByZWdpc3RyeSwgc3RyaW5ncyk7XG4gICAgbGV0IHJlbGF0aXZlTmFtZSA9IGdldEludGVybmFsSW5zdGFuY2VOYW1lKHZpc2l0b3IpO1xuICAgIGlmIChyZWYucmVhY3RLZXkpIHtcbiAgICAgIHJlbGF0aXZlTmFtZSA9IHJlZi5yZWFjdEtleSArICc6ICcgKyByZWxhdGl2ZU5hbWU7XG4gICAgfVxuICAgIHJlZi5yZWFjdFRyZWUgPSByZWdpc3RyeS5pbnNlcnQocGFyZW50UmVmLnJlYWN0VHJlZSwgc3RyaW5ncy5pbnRlcm4ocmVsYXRpdmVOYW1lKSk7XG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgJ25vbiByZWFjdCBpbnN0YW5jZSBwYXJlbnQgb2YgcmVhY3QgaW5zdGFuY2UnO1xuICB9XG59XG5cbmZ1bmN0aW9uIG1hcmtSZWFjdENvbXBvbmVudFRyZWUocmVmcywgcmVnaXN0cnksIHN0cmluZ3MpIHtcbiAgLy8gYW5ub3RhdGUgYWxsIHJlZnMgdGhhdCBhcmUgcmVhY3QgaW50ZXJuYWwgaW5zdGFuY2VzIHdpdGggdGhlaXIgcGFyZW50IGFuZCBuYW1lXG4gIC8vIHJlZi5yZWFjdFBhcmVudCA9IHZpc2l0b3IgdGhhdCBwb2ludHMgdG8gcGFyZW50IGluc3RhbmNlLFxuICAvLyAgIG51bGwgaWYgd2Uga25vdyBpdCdzIGFuIGluc3RhbmNlLCBidXQgZG9uJ3QgaGF2ZSBhIHBhcmVudCB5ZXRcbiAgLy8gcmVmLnJlYWN0S2V5ID0gaWYgYSBrZXkgaXMgdXNlZCB0byBkaXN0aW5ndWlzaCBzaWJsaW5nc1xuICBmb3JFYWNoUmVmKHJlZnMsICh2aXNpdG9yKSA9PiB7XG4gICAgY29uc3QgdmlzaXRvckNsb25lID0gdmlzaXRvci5jbG9uZSgpOyAvLyB2aXNpdG9yIHdpbGwgZ2V0IHN0b21wZWQgb24gbmV4dCBpdGVyYXRpb25cbiAgICBjb25zdCByZWYgPSB2aXNpdG9yLmdldFJlZigpO1xuICAgIHZpc2l0b3IuZm9yRWFjaEVkZ2UoKGVkZ2VOYW1lLCBlZGdlVmlzaXRvcikgPT4ge1xuICAgICAgY29uc3QgZWRnZVJlZiA9IGVkZ2VWaXNpdG9yLmdldFJlZigpO1xuICAgICAgaWYgKGVkZ2VSZWYpIHtcbiAgICAgICAgaWYgKGVkZ2VOYW1lID09PSAnX3JlbmRlcmVkQ2hpbGRyZW4nKSB7XG4gICAgICAgICAgaWYgKHJlZi5yZWFjdFBhcmVudCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAvLyByZWYgaXMgcmVhY3QgY29tcG9uZW50LCBldmVuIGlmIHdlIGRvbid0IGhhdmUgYSBwYXJlbnQgeWV0XG4gICAgICAgICAgICByZWYucmVhY3RQYXJlbnQgPSBudWxsO1xuICAgICAgICAgIH1cbiAgICAgICAgICBlZGdlVmlzaXRvci5mb3JFYWNoRWRnZSgoY2hpbGROYW1lLCBjaGlsZFZpc2l0b3IpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGNoaWxkUmVmID0gY2hpbGRWaXNpdG9yLmdldFJlZigpO1xuICAgICAgICAgICAgaWYgKGNoaWxkUmVmICYmIGNoaWxkTmFtZS5zdGFydHNXaXRoKCcuJykpIHtcbiAgICAgICAgICAgICAgY2hpbGRSZWYucmVhY3RQYXJlbnQgPSB2aXNpdG9yQ2xvbmU7XG4gICAgICAgICAgICAgIGNoaWxkUmVmLnJlYWN0S2V5ID0gY2hpbGROYW1lO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKGVkZ2VOYW1lID09PSAnX3JlbmRlcmVkQ29tcG9uZW50Jykge1xuICAgICAgICAgIGlmIChyZWYucmVhY3RQYXJlbnQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgcmVmLnJlYWN0UGFyZW50ID0gbnVsbDtcbiAgICAgICAgICB9XG4gICAgICAgICAgZWRnZVJlZi5yZWFjdFBhcmVudCA9IHZpc2l0b3JDbG9uZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICB9KTtcbiAgLy8gYnVpbGQgdHJlZSBvZiByZWFjdCBpbnRlcm5hbCBpbnN0YW5jZXMgKHNpbmNlIHRoYXQncyB3aGF0IGhhcyB0aGUgc3RydWN0dXJlKVxuICAvLyBmaWxsIGluIHJlZi5yZWFjdFRyZWUgPSBwYXRoIHJlZ2lzdHJ5IG5vZGVcbiAgZm9yRWFjaFJlZihyZWZzLCAodmlzaXRvcikgPT4ge1xuICAgIGJ1aWxkUmVhY3RDb21wb25lbnRUcmVlKHZpc2l0b3IsIHJlZ2lzdHJ5LCBzdHJpbmdzKTtcbiAgfSk7XG4gIC8vIGhvb2sgaW4gY29tcG9uZW50cyBieSBsb29raW5nIGF0IHRoZWlyIF9yZWFjdEludGVybmFsSW5zdGFuY2UgZmllbGRzXG4gIGZvckVhY2hSZWYocmVmcywgKHZpc2l0b3IpID0+IHtcbiAgICBjb25zdCByZWYgPSB2aXNpdG9yLmdldFJlZigpO1xuICAgIGNvbnN0IGluc3RhbmNlUmVmID0gdmlzaXRvci5tb3ZlVG9FZGdlKCdfcmVhY3RJbnRlcm5hbEluc3RhbmNlJykuZ2V0UmVmKCk7XG4gICAgaWYgKGluc3RhbmNlUmVmKSB7XG4gICAgICByZWYucmVhY3RUcmVlID0gaW5zdGFuY2VSZWYucmVhY3RUcmVlO1xuICAgIH1cbiAgfSk7XG59XG5cbmZ1bmN0aW9uIGZ1bmN0aW9uVXJsRmlsZU5hbWUodmlzaXRvcikge1xuICBjb25zdCBleGVjdXRhYmxlID0gdmlzaXRvci5jbG9uZSgpLm1vdmVUb0VkZ2UoJ0BFeGVjdXRhYmxlJyk7XG4gIGNvbnN0IHJlZiA9IGV4ZWN1dGFibGUuZ2V0UmVmKCk7XG4gIGlmIChyZWYgJiYgcmVmLnZhbHVlICYmIHJlZi52YWx1ZS51cmwpIHtcbiAgICBjb25zdCB1cmwgPSByZWYudmFsdWUudXJsO1xuICAgIGxldCBmaWxlID0gdXJsLnN1YnN0cmluZyh1cmwubGFzdEluZGV4T2YoJy8nKSArIDEpO1xuICAgIGlmIChmaWxlLmVuZHNXaXRoKCcuanMnKSkge1xuICAgICAgZmlsZSA9IGZpbGUuc3Vic3RyaW5nKDAsIGZpbGUubGVuZ3RoIC0gMyk7XG4gICAgfVxuICAgIHJldHVybiBmaWxlO1xuICB9XG4gIHJldHVybiB1bmRlZmluZWQ7XG59XG5cbmZ1bmN0aW9uIG1hcmtNb2R1bGVzKHJlZnMpIHtcbiAgY29uc3QgbW9kdWxlcyA9IGZpcnN0UmVmKHJlZnMsIChpZCwgcmVmKSA9PiByZWYudHlwZSA9PT0gJ0NhbGxiYWNrR2xvYmFsT2JqZWN0Jyk7XG4gIG1vZHVsZXMubW92ZVRvRWRnZSgncmVxdWlyZScpO1xuICBtb2R1bGVzLm1vdmVUb0ZpcnN0KChuYW1lLCB2aXNpdG9yKSA9PiB2aXNpdG9yLmdldFR5cGUoKSA9PT0gJ0pTQWN0aXZhdGlvbicpO1xuICBtb2R1bGVzLm1vdmVUb0VkZ2UoJ21vZHVsZXMnKTtcbiAgbW9kdWxlcy5mb3JFYWNoRWRnZSgobmFtZSwgdmlzaXRvcikgPT4ge1xuICAgIGNvbnN0IHJlZiA9IHZpc2l0b3IuZ2V0UmVmKCk7XG4gICAgdmlzaXRvci5tb3ZlVG9FZGdlKCdleHBvcnRzJyk7XG4gICAgaWYgKHZpc2l0b3IuZ2V0VHlwZSgpID09PSAnT2JqZWN0Jykge1xuICAgICAgdmlzaXRvci5tb3ZlVG9GaXJzdCgobWVtYmVyTmFtZSwgbWVtYmVyKSA9PiBtZW1iZXIuZ2V0VHlwZSgpID09PSAnRnVuY3Rpb24nKTtcbiAgICAgIGlmICh2aXNpdG9yLmlzRGVmaW5lZCgpKSB7XG4gICAgICAgIHJlZi5tb2R1bGUgPSBmdW5jdGlvblVybEZpbGVOYW1lKHZpc2l0b3IpO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAodmlzaXRvci5nZXRUeXBlKCkgPT09ICdGdW5jdGlvbicpIHtcbiAgICAgIGNvbnN0IGRpc3BsYXlOYW1lID0gdmlzaXRvci5jbG9uZSgpLm1vdmVUb0VkZ2UoJ2Rpc3BsYXlOYW1lJyk7XG4gICAgICBpZiAoZGlzcGxheU5hbWUuaXNEZWZpbmVkKCkpIHtcbiAgICAgICAgcmVmLm1vZHVsZSA9IGRpc3BsYXlOYW1lLmdldFZhbHVlKCk7XG4gICAgICB9XG4gICAgICByZWYubW9kdWxlID0gZnVuY3Rpb25VcmxGaWxlTmFtZSh2aXNpdG9yKTtcbiAgICB9XG4gICAgaWYgKHJlZiAmJiAhcmVmLm1vZHVsZSkge1xuICAgICAgcmVmLm1vZHVsZSA9ICcjdW5rbm93biAnICsgbmFtZTtcbiAgICB9XG4gIH0pO1xufVxuXG5mdW5jdGlvbiByZWdpc3RlclBhdGhUb1Jvb3QocmVmcywgcmVnaXN0cnksIHN0cmluZ3MpIHtcbiAgbWFya1JlYWN0Q29tcG9uZW50VHJlZShyZWZzLCByZWdpc3RyeSwgc3RyaW5ncyk7XG4gIG1hcmtNb2R1bGVzKHJlZnMpO1xuICBsZXQgYnJlYWR0aCA9IFtdO1xuICBmb3JFYWNoUmVmKHJlZnMsICh2aXNpdG9yKSA9PiB7XG4gICAgY29uc3QgcmVmID0gdmlzaXRvci5nZXRSZWYoKTtcbiAgICBpZiAocmVmLnR5cGUgPT09ICdDYWxsYmFja0dsb2JhbE9iamVjdCcpIHtcbiAgICAgIHJlZi5yb290UGF0aCA9IHJlZ2lzdHJ5Lmluc2VydChyZWdpc3RyeS5yb290LCBzdHJpbmdzLmludGVybihyZWYudHlwZSkpO1xuICAgICAgYnJlYWR0aC5wdXNoKHZpc2l0b3IuY2xvbmUoKSk7XG4gICAgfVxuICB9KTtcbiAgd2hpbGUgKGJyZWFkdGgubGVuZ3RoID4gMCkge1xuICAgIGNvbnN0IG5leHRCcmVhZHRoID0gW107XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBicmVhZHRoLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCB2aXNpdG9yID0gYnJlYWR0aFtpXTtcbiAgICAgIGNvbnN0IHJlZiA9IHZpc2l0b3IuZ2V0UmVmKCk7XG4gICAgICB2aXNpdG9yLmZvckVhY2hFZGdlKChlZGdlTmFtZSwgZWRnZVZpc2l0b3IpID0+IHtcbiAgICAgICAgY29uc3QgZWRnZVJlZiA9IGVkZ2VWaXNpdG9yLmdldFJlZigpO1xuICAgICAgICBpZiAoZWRnZVJlZiAmJiBlZGdlUmVmLnJvb3RQYXRoID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBsZXQgcGF0aE5hbWUgPSBlZGdlUmVmLnR5cGU7XG4gICAgICAgICAgaWYgKGVkZ2VOYW1lKSB7XG4gICAgICAgICAgICBwYXRoTmFtZSA9IGVkZ2VOYW1lICsgJzogJyArIHBhdGhOYW1lO1xuICAgICAgICAgIH1cbiAgICAgICAgICBlZGdlUmVmLnJvb3RQYXRoID0gcmVnaXN0cnkuaW5zZXJ0KHJlZi5yb290UGF0aCwgc3RyaW5ncy5pbnRlcm4ocGF0aE5hbWUpKTtcbiAgICAgICAgICBuZXh0QnJlYWR0aC5wdXNoKGVkZ2VWaXNpdG9yLmNsb25lKCkpO1xuICAgICAgICAgIC8vIGNvcHkgbW9kdWxlIGFuZCByZWFjdCB0cmVlIGZvcndhcmRcbiAgICAgICAgICBpZiAoZWRnZVJlZi5tb2R1bGUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgZWRnZVJlZi5tb2R1bGUgPSByZWYubW9kdWxlO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoZWRnZVJlZi5yZWFjdFRyZWUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgZWRnZVJlZi5yZWFjdFRyZWUgPSByZWYucmVhY3RUcmVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICAgIGJyZWFkdGggPSBuZXh0QnJlYWR0aDtcbiAgfVxufVxuXG5mdW5jdGlvbiByZWdpc3RlckNhcHR1cmUoZGF0YSwgY2FwdHVyZUlkLCBjYXB0dXJlLCBzdGFja3MsIHN0cmluZ3MpIHtcbiAgLy8gTkI6IGNhcHR1cmUucmVmcyBpcyBwb3RlbnRpYWxseSBWRVJZIGxhcmdlLCBzbyB3ZSB0cnkgdG8gYXZvaWQgbWFraW5nXG4gIC8vIGNvcGllcywgZXZlbiBpZiBpdGVyYXRpb24gaXMgYSBiaXQgbW9yZSBhbm5veWluZy5cbiAgbGV0IHJvd0NvdW50ID0gMDtcbiAgZm9yIChjb25zdCBpZCBpbiBjYXB0dXJlLnJlZnMpIHsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bnVzZWQtdmFyc1xuICAgIHJvd0NvdW50Kys7XG4gIH1cbiAgZm9yIChjb25zdCBpZCBpbiBjYXB0dXJlLm1hcmtlZEJsb2NrcykgeyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVudXNlZC12YXJzXG4gICAgcm93Q291bnQrKztcbiAgfVxuICBjb25zdCBpbnNlcnRlciA9IGRhdGEucm93SW5zZXJ0ZXIocm93Q291bnQpO1xuICByZWdpc3RlclBhdGhUb1Jvb3QoY2FwdHVyZS5yZWZzLCBzdGFja3MsIHN0cmluZ3MpO1xuICBjb25zdCBub25lU3RyaW5nID0gc3RyaW5ncy5pbnRlcm4oJyNub25lJyk7XG4gIGNvbnN0IG5vbmVTdGFjayA9IHN0YWNrcy5pbnNlcnQoc3RhY2tzLnJvb3QsIG5vbmVTdHJpbmcpO1xuICBmb3JFYWNoUmVmKGNhcHR1cmUucmVmcywgKHZpc2l0b3IpID0+IHtcbiAgICAvLyB3YW50IHRvIGRhdGEuYXBwZW5kKHZhbHVlLCB2YWx1ZSwgdmFsdWUpLCBub3QgSURzXG4gICAgY29uc3QgcmVmID0gdmlzaXRvci5nZXRSZWYoKTtcbiAgICBjb25zdCBpZCA9IHZpc2l0b3IuaWQ7XG4gICAgaW5zZXJ0ZXIuaW5zZXJ0Um93KFxuICAgICAgcGFyc2VJbnQoaWQsIDE2KSxcbiAgICAgIHJlZi50eXBlLFxuICAgICAgcmVmLnNpemUsXG4gICAgICBjYXB0dXJlSWQsXG4gICAgICByZWYucm9vdFBhdGggPT09IHVuZGVmaW5lZCA/IG5vbmVTdGFjayA6IHJlZi5yb290UGF0aCxcbiAgICAgIHJlZi5yZWFjdFRyZWUgPT09IHVuZGVmaW5lZCA/IG5vbmVTdGFjayA6IHJlZi5yZWFjdFRyZWUsXG4gICAgICB2aXNpdG9yLmdldFZhbHVlKCksXG4gICAgICByZWYubW9kdWxlID09PSB1bmRlZmluZWQgPyAnI25vbmUnIDogcmVmLm1vZHVsZSxcbiAgICApO1xuICB9KTtcbiAgZm9yIChjb25zdCBpZCBpbiBjYXB0dXJlLm1hcmtlZEJsb2Nrcykge1xuICAgIGNvbnN0IGJsb2NrID0gY2FwdHVyZS5tYXJrZWRCbG9ja3NbaWRdO1xuICAgIGluc2VydGVyLmluc2VydFJvdyhcbiAgICAgIHBhcnNlSW50KGlkLCAxNiksXG4gICAgICAnTWFya2VkIEJsb2NrIE92ZXJoZWFkJyxcbiAgICAgIGJsb2NrLmNhcGFjaXR5IC0gYmxvY2suc2l6ZSxcbiAgICAgIGNhcHR1cmVJZCxcbiAgICAgIG5vbmVTdGFjayxcbiAgICAgIG5vbmVTdGFjayxcbiAgICAgICdjYXBhY2l0eTogJyArIGJsb2NrLmNhcGFjaXR5ICsgJywgc2l6ZTogJyArIGJsb2NrLnNpemUgKyAnLCBncmFudWxhcml0eTogJyArIGJsb2NrLmNlbGxTaXplLFxuICAgICAgJyNub25lJyxcbiAgICApO1xuICB9XG4gIGluc2VydGVyLmRvbmUoKTtcbn1cblxuaWYgKHByZUxvYWRlZENhcHR1cmUpIHtcbiAgY29uc3Qgc3RyaW5ncyA9IFN0cmluZ0ludGVybmVyKCk7XG4gIGNvbnN0IHN0YWNrcyA9ICBuZXcgU3RhY2tSZWdpc3RyeSgpO1xuICBjb25zdCBjb2x1bW5zID0gW1xuICAgIHsgbmFtZTogJ2lkJywgdHlwZTogJ2ludCcgfSxcbiAgICB7IG5hbWU6ICd0eXBlJywgdHlwZTogJ3N0cmluZycsIHN0cmluZ3M6IHN0cmluZ3MgfSxcbiAgICB7IG5hbWU6ICdzaXplJywgdHlwZTogJ2ludCcgfSxcbiAgICB7IG5hbWU6ICd0cmFjZScsIHR5cGU6ICdzdHJpbmcnLCBzdHJpbmdzOiBzdHJpbmdzIH0sXG4gICAgeyBuYW1lOiAncGF0aCcsIHR5cGU6ICdzdGFjaycsIHN0YWNrczogc3RhY2tzIH0sXG4gICAgeyBuYW1lOiAncmVhY3QnLCB0eXBlOiAnc3RhY2snLCBzdGFja3M6IHN0YWNrcyB9LFxuICAgIHsgbmFtZTogJ3ZhbHVlJywgdHlwZTogJ3N0cmluZycsIHN0cmluZ3M6IHN0cmluZ3MgfSxcbiAgICB7IG5hbWU6ICdtb2R1bGUnLCB0eXBlOiAnc3RyaW5nJywgc3RyaW5nczogc3RyaW5ncyB9LFxuICBdO1xuICBjb25zdCBkYXRhID0gbmV3IEFnZ3Jvd0RhdGEoY29sdW1ucyk7XG4gIHJlZ2lzdGVyQ2FwdHVyZShkYXRhLCAndHJhY2UnLCBwcmVMb2FkZWRDYXB0dXJlLCBzdGFja3MsIHN0cmluZ3MpO1xuICBwcmVMb2FkZWRDYXB0dXJlID0gdW5kZWZpbmVkOyAvLyBsZXQgR0cgY2xlYW4gdXAgdGhlIGNhcHR1cmVcbiAgY29uc3QgYWdncm93ID0gbmV3IEFnZ3JvdyhkYXRhKTtcbiAgYWdncm93LmFkZFBvaW50ZXJFeHBhbmRlcignSWQnLCAnaWQnKTtcbiAgY29uc3QgdHlwZUV4cGFuZGVyID0gYWdncm93LmFkZFN0cmluZ0V4cGFuZGVyKCdUeXBlJywgJ3R5cGUnKTtcbiAgYWdncm93LmFkZE51bWJlckV4cGFuZGVyKCdTaXplJywgJ3NpemUnKTtcbiAgYWdncm93LmFkZFN0cmluZ0V4cGFuZGVyKCdUcmFjZScsICd0cmFjZScpO1xuICBjb25zdCBwYXRoRXhwYW5kZXIgPSBhZ2dyb3cuYWRkU3RhY2tFeHBhbmRlcignUGF0aCcsICdwYXRoJywgc3RyaW5ncy5nZXQpO1xuICBjb25zdCByZWFjdEV4cGFuZGVyID0gYWdncm93LmFkZFN0YWNrRXhwYW5kZXIoJ1JlYWN0IFRyZWUnLCAncmVhY3QnLCBzdHJpbmdzLmdldCk7XG4gIGNvbnN0IHZhbHVlRXhwYW5kZXIgPSBhZ2dyb3cuYWRkU3RyaW5nRXhwYW5kZXIoJ1ZhbHVlJywgJ3ZhbHVlJyk7XG4gIGNvbnN0IG1vZHVsZUV4cGFuZGVyID0gYWdncm93LmFkZFN0cmluZ0V4cGFuZGVyKCdNb2R1bGUnLCAnbW9kdWxlJyk7XG4gIGFnZ3Jvdy5leHBhbmRlci5zZXRBY3RpdmVFeHBhbmRlcnMoW1xuICAgIHBhdGhFeHBhbmRlcixcbiAgICByZWFjdEV4cGFuZGVyLFxuICAgIG1vZHVsZUV4cGFuZGVyLFxuICAgIHR5cGVFeHBhbmRlcixcbiAgICB2YWx1ZUV4cGFuZGVyLFxuICBdKTtcbiAgY29uc3Qgc2l6ZUFnZ3JlZ2F0b3IgPSBhZ2dyb3cuYWRkU3VtQWdncmVnYXRvcignU2l6ZScsICdzaXplJyk7XG4gIGNvbnN0IGNvdW50QWdncmVnYXRvciA9IGFnZ3Jvdy5hZGRDb3VudEFnZ3JlZ2F0b3IoJ0NvdW50Jyk7XG4gIGFnZ3Jvdy5leHBhbmRlci5zZXRBY3RpdmVBZ2dyZWdhdG9ycyhbXG4gICAgc2l6ZUFnZ3JlZ2F0b3IsXG4gICAgY291bnRBZ2dyZWdhdG9yLFxuICBdKTtcbiAgUmVhY3RET00ucmVuZGVyKDxUYWJsZSBhZ2dyb3c9e2FnZ3Jvdy5leHBhbmRlcn0gLz4sIGRvY3VtZW50LmJvZHkpO1xufVxuIl19 -// @generated diff --git a/local-cli/server/middleware/heapCapture/out/table.js b/local-cli/server/middleware/heapCapture/out/table.js deleted file mode 100644 index ed3141cdc..000000000 --- a/local-cli/server/middleware/heapCapture/out/table.js +++ /dev/null @@ -1,541 +0,0 @@ -/** - * Copyright (c) 2016-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -'use strict'; -/*eslint no-console-disallow: "off"*/ -/*global React:true*/ - -// TODO: -// selection and arrow keys for navigating -var _createClass=function(){function defineProperties(target,props){for(var i=0;i>':'<<'; -var aggrow=this.props.aggrow; -var config=[]; -if(this.state.expanded){ -config=aggrow.getExpanders().map(function(ex){return _this5.renderExpander(ex);}); -} -return( -React.createElement('div',{style:{ -width:this.state.expanded?'512px':'26px', -height:'100%', -display:'flex', -flexDirection:'column', -overflow:'hidden', -borderLeft:'2px solid black'}}, - -React.createElement('div',{style:{ -width:'100%', -height:'26px', -border:'1px solid darkGray'}, - -onClick:function onClick(e){return _this5.setState({expanded:!_this5.state.expanded});}}, -expanderText), - -config)); - - -}}]);return TableConfiguration;}(React.Component); - - -TableConfiguration.propTypes={ -aggrow:React.PropTypes.object.isRequired};var - - -TableHeader=function(_React$Component5){_inherits(TableHeader,_React$Component5); -function TableHeader(props){_classCallCheck(this,TableHeader);return _possibleConstructorReturn(this,(TableHeader.__proto__||Object.getPrototypeOf(TableHeader)).call(this, -props)); -}_createClass(TableHeader,[{key:'render',value:function render() -{ -var aggrow=this.props.aggrow; -var aggregators=aggrow.getActiveAggregators(); -var expanders=aggrow.getActiveExpanders(); -var headers=[]; -for(var i=0;i':'...'; -headers.push( -React.createElement(DropTarget,{ -id:'expander:insert:'+(_i+1).toString(), -dropAction:this.props.dropAction}, - -React.createElement('div',{style:{ -height:'inherit', -backgroundColor:'darkGray', -flexShrink:'0'}}, - -sep))); - - - -} -return( -React.createElement('div',{style:{ -width:'100%', -height:'26px', -display:'flex', -flexDirection:'row', -alignItems:'center', -borderBottom:'2px solid black'}}, - -headers)); - - -}}]);return TableHeader;}(React.Component); - - -TableHeader.propTypes={ -aggrow:React.PropTypes.object.isRequired, -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,(Table.__proto__||Object.getPrototypeOf(Table)).call(this, -props)); -_this7.state={ -aggrow:props.aggrow, -viewport:{top:0,height:100}, -cursor:0};return _this7; - -}_createClass(Table,[{key:'scroll',value:function scroll( - -e){ -var viewport=e.target; -var top=Math.floor((viewport.scrollTop-viewport.clientHeight*1.0)/rowHeight); -var height=Math.ceil(viewport.clientHeight*3.0/rowHeight); -if(top!==this.state.viewport.top||height!==this.state.viewport.height){ -this.setState({viewport:{top:top,height:height}}); -} -}},{key:'_contractRow',value:function _contractRow( - -row){ -var newCursor=this.state.cursor; -if(newCursor>row.top&&newCursor=row.top+row.height){// below contracted section -newCursor-=row.height-1; -} -this.state.aggrow.contract(row); -this.setState({cursor:newCursor}); -console.log('-'+row.top); -}},{key:'_expandRow',value:function _expandRow( - -row){ -var newCursor=this.state.cursor; -this.state.aggrow.expand(row); -if(newCursor>row.top){// below expanded section -newCursor+=row.height-1; -} -this.setState({cursor:newCursor}); -console.log('+'+row.top); -}},{key:'_keepCursorInViewport',value:function _keepCursorInViewport() - - - -{ -if(this._scrollDiv){ -var cursor=this.state.cursor; -var scrollDiv=this._scrollDiv; -if(cursor*rowHeightscrollDiv.scrollTop+scrollDiv.clientHeight*0.9){ -scrollDiv.scrollTop=(cursor+1)*rowHeight-scrollDiv.clientHeight*0.9; -} -} -}},{key:'keydown',value:function keydown( - -e){ -var aggrow=this.state.aggrow; -var cursor=this.state.cursor; -var row=aggrow.getRows(cursor,1)[0]; -switch(e.keyCode){ -case 38:// up -if(cursor>0){ -this.setState({cursor:cursor-1}); -this._keepCursorInViewport(); -} -e.preventDefault(); -break; -case 40:// down -if(cursor0){ -var indent=aggrow.getRowIndent(row)-1; -while(aggrow.getRowIndent(row)>indent){ -cursor--; -row=aggrow.getRows(cursor,1)[0]; -} -this.setState({cursor:cursor}); -this._keepCursorInViewport(); -} -e.preventDefault(); -break; -case 39:// right -if(aggrow.canExpand(row)){ -this._expandRow(row); -}else if(cursorsIndex){ -dIndex--; -} -active.splice(sIndex,1); -active.splice(dIndex,0,dragged); -aggrow.setActiveAggregators(active); -this.setState({cursor:0}); -}else if(s.startsWith('expander:active:')){ -var _sIndex=parseInt(s.substr(16),10); -var _dIndex=-1; -var _active=aggrow.getActiveExpanders(); -var _dragged=_active[_sIndex]; -if(d.startsWith('expander:insert:')){ -_dIndex=parseInt(d.substr(16),10); -}else if(d==='divider:insert'){ -_dIndex=0; -}else{ -throw'not allowed to drag '+s+' to '+d; -} -if(_dIndex>_sIndex){ -_dIndex--; -} -_active.splice(_sIndex,1); -_active.splice(_dIndex,0,_dragged); -aggrow.setActiveExpanders(_active); -this.setState({cursor:0}); -}else if(s.startsWith('expander:add:')){ -var _dIndex2=-1; -var sExpander=parseInt(s.substring(13),10); -if(d.startsWith('expander:insert:')){ -_dIndex2=parseInt(d.substr(16),10); -}else if(d==='divider:insert'){ -_dIndex2=0; -}else{ -throw'not allowed to drag '+s+' to '+d; -} -var _active2=aggrow.getActiveExpanders(); -_active2.splice(_dIndex2,0,sExpander); -aggrow.setActiveExpanders(_active2); -this.setState({cursor:0}); -} -}},{key:'render',value:function render() - -{var _this8=this; -return( -React.createElement('div',{style:{width:'100%',height:'100%',display:'flex',flexDirection:'row'}}, -React.createElement('div',{style:{width:'100%',height:'100%',display:'flex',flexDirection:'column',overflow:'hidden'}}, -React.createElement(TableHeader,{aggrow:this.state.aggrow,dropAction:function dropAction(s,d){return _this8.dropAction(s,d);}}), -React.createElement('div',{ -style:{ -width:'100%', -flexGrow:'1', -overflow:'scroll'}, - -onScroll:function onScroll(e){return _this8.scroll(e);}, -ref:function ref(div){_this8._scrollDiv=div;}}, -React.createElement('div',{style:{position:'relative'}}, -this.renderVirtualizedRows()))), - - - -React.createElement(TableConfiguration,{aggrow:this.state.aggrow}))); - - -}},{key:'renderVirtualizedRows',value:function renderVirtualizedRows() - -{var _this9=this; -var aggrow=this.state.aggrow; -var viewport=this.state.viewport; -var rows=aggrow.getRows(viewport.top,viewport.height); -return( -React.createElement('div',{style:{ -position:'absolute', -width:'100%', -height:(rowHeight*(aggrow.getHeight()+20)).toString()+'px'}}, - -rows.map(function(child){return _this9.renderRow(child);}))); - - -}},{key:'renderRow',value:function renderRow( - -row){var _this10=this; -if(row===null){ -return null; -} -var bg='lightGray'; -var aggrow=this.state.aggrow; -var columns=[]; -var rowText=''; -var indent=4+aggrow.getRowIndent(row)*treeIndent; -var aggregates=aggrow.getActiveAggregators(); -if(row.parent!==null&&row.parent.expander%2===0){ -bg='white'; -} -if(row.top===this.state.cursor){ -bg='lightblue'; -} -for(var i=0;i= stackIdMap.length || stackIdMap[id] !== undefined) { - throw 'invalid stack id!'; - } - - if (childStack !== undefined) { - // each child must have our stack as a prefix, so just use that - stackIdMap[id] = childStack.subarray(0, stack.length); - } else { - const newStack = stackArray.subarray(stackFrameCount, stackFrameCount + stack.length); - stackFrameCount += stack.length; - for (let i = 0; i < stack.length; i++) { - newStack[i] = stack[i]; - } - stackIdMap[id] = newStack; - } - return stackIdMap[id]; - } - flattenStacksImpl(this.root, []); - this.root = null; - this.stackIdMap = stackIdMap; - this.maxDepth = maxStackDepth; - }, - }; -} - -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; - const STACK_EXPANDER_ID_MIN = 0x8000; - const STACK_EXPANDER_ID_MAX = 0xffff; - - // used for row.expander which reference state.activeExpanders (with frame index masked in) - const INVALID_ACTIVE_EXPANDER = -1; - const ACTIVE_EXPANDER_MASK = 0xffff; - const ACTIVE_EXPANDER_FRAME_SHIFT = 16; - - // aggregator ID definitions - const AGGREGATOR_ID_MAX = 0xffff; - - // active aggragators can have sort order changed in the reference - const ACTIVE_AGGREGATOR_MASK = 0xffff; - const ACTIVE_AGGREGATOR_ASC_BIT = 0x10000; - - // tree node state definitions - const NODE_EXPANDED_BIT = 0x0001; // this row is expanded - const NODE_REAGGREGATE_BIT = 0x0002; // children need aggregates - const NODE_REORDER_BIT = 0x0004; // children need to be sorted - const NODE_REPOSITION_BIT = 0x0008; // children need position - const NODE_INDENT_SHIFT = 16; - - function calleeFrameIdGetter(stack, depth) { - return stack[depth]; - } - - function callerFrameIdGetter(stack, depth) { - return stack[stack.length - depth - 1]; - } - - function createStackComparers(stackGetter, frameIdGetter, maxStackDepth) { - const comparers = new Array(maxStackDepth); - for (let depth = 0; depth < maxStackDepth; depth++) { - const captureDepth = depth; // NB: to capture depth per loop iteration - comparers[depth] = function calleeStackComparer(rowA, rowB) { - const a = stackGetter(rowA); - const b = stackGetter(rowB); - // NB: we put the stacks that are too short at the top, - // so they can be grouped into the '' bucket - if (a.length <= captureDepth && b.length <= captureDepth) { - return 0; - } else if (a.length <= captureDepth) { - return -1; - } else if (b.length <= captureDepth) { - return 1; - } - return frameIdGetter(a, captureDepth) - frameIdGetter(b, captureDepth); - }; - } - return comparers; - } - - function createTreeNode(parent, label, indices, expander) { - const indent = parent === null ? 0 : (parent.state >>> NODE_INDENT_SHIFT) + 1; - const state = NODE_REPOSITION_BIT | - NODE_REAGGREGATE_BIT | - NODE_REORDER_BIT | - (indent << NODE_INDENT_SHIFT); - return { - parent: parent, // null if root - children: null, // array of children nodes - label: label, // string to show in UI - indices: indices, // row indices under this node - aggregates: null, // result of aggregate on indices - expander: expander, // index into state.activeExpanders - top: 0, // y position of top row (in rows) - height: 1, // number of rows including children - state: state, // see NODE_* definitions above - }; - } - - function noSortOrder(a, b) { - return 0; - } - - const indices = new Int32Array(numRows); - for (let i = 0; i < numRows; i++) { - indices[i] = i; - } - - const state = { - fieldExpanders: [], // tree expanders that expand on simple values - stackExpanders: [], // tree expanders that expand stacks - activeExpanders: [], // index into field or stack expanders, hierarchy of tree - aggregators: [], // all available aggregators, might not be used - activeAggregators: [], // index into aggregators, to actually compute - sorter: noSortOrder, // compare function that uses sortOrder to sort row.children - root: createTreeNode(null, '', indices, INVALID_ACTIVE_EXPANDER), - }; - - function evaluateAggregate(row) { - const activeAggregators = state.activeAggregators; - const aggregates = new Array(activeAggregators.length); - for (let j = 0; j < activeAggregators.length; j++) { - const aggregator = state.aggregators[activeAggregators[j]]; - aggregates[j] = aggregator.aggregator(row.indices); - } - row.aggregates = aggregates; - row.state |= NODE_REAGGREGATE_BIT; - } - - function evaluateAggregates(row) { - if ((row.state & NODE_EXPANDED_BIT) !== 0) { - const children = row.children; - for (let i = 0; i < children.length; i++) { - evaluateAggregate(children[i]); - } - row.state |= NODE_REORDER_BIT; - } - row.state ^= NODE_REAGGREGATE_BIT; - } - - function evaluateOrder(row) { - if ((row.state & NODE_EXPANDED_BIT) !== 0) { - const children = row.children; - for (let i = 0; i < children.length; i++) { - const child = children[i]; - child.state |= NODE_REORDER_BIT; - } - children.sort(state.sorter); - row.state |= NODE_REPOSITION_BIT; - } - row.state ^= NODE_REORDER_BIT; - } - - function evaluatePosition(row) { - if ((row.state & NODE_EXPANDED_BIT) !== 0) { - const children = row.children; - let childTop = row.top + 1; - for (let i = 0; i < children.length; i++) { - const child = children[i]; - if (child.top !== childTop) { - child.top = childTop; - child.state |= NODE_REPOSITION_BIT; - } - childTop += child.height; - } - } - row.state ^= NODE_REPOSITION_BIT; - } - - function getRowsImpl(row, top, height, result) { - if ((row.state & NODE_REAGGREGATE_BIT) !== 0) { - evaluateAggregates(row); - } - if ((row.state & NODE_REORDER_BIT) !== 0) { - evaluateOrder(row); - } - if ((row.state & NODE_REPOSITION_BIT) !== 0) { - evaluatePosition(row); - } - - if (row.top >= top && row.top < top + height) { - if (result[row.top - top] != null) { - throw 'getRows put more than one row at position ' + row.top + ' into result'; - } - result[row.top - top] = row; - } - if ((row.state & NODE_EXPANDED_BIT) !== 0) { - const children = row.children; - for (let i = 0; i < children.length; i++) { - const child = children[i]; - if (child.top < top + height && top < child.top + child.height) { - getRowsImpl(child, top, height, result); - } - } - } - } - - function updateHeight(row, heightChange) { - while (row !== null) { - row.height += heightChange; - row.state |= NODE_REPOSITION_BIT; - row = row.parent; - } - } - - function addChildrenWithFieldExpander(row, expander, nextActiveIndex) { - const rowIndices = row.indices; - const comparer = expander.comparer; - rowIndices.sort(comparer); - let begin = 0; - let end = 1; - row.children = []; - while (end < rowIndices.length) { - if (comparer(rowIndices[begin], rowIndices[end]) !== 0) { - row.children.push(createTreeNode( - row, - expander.name + ': ' + expander.formatter(rowIndices[begin]), - rowIndices.subarray(begin, end), - nextActiveIndex)); - begin = end; - } - end++; - } - row.children.push(createTreeNode( - row, - expander.name + ': ' + expander.formatter(rowIndices[begin]), - rowIndices.subarray(begin, end), - nextActiveIndex)); - } - - function addChildrenWithStackExpander(row, expander, activeIndex, depth, nextActiveIndex) { - const rowIndices = row.indices; - const stackGetter = expander.stackGetter; - const frameIdGetter = expander.frameIdGetter; - const frameGetter = expander.frameGetter; - const comparer = expander.comparers[depth]; - const expandNextFrame = activeIndex | ((depth + 1) << ACTIVE_EXPANDER_FRAME_SHIFT); - rowIndices.sort(comparer); - let columnName = ''; - if (depth === 0) { - columnName = expander.name + ': '; - } - - // put all the too-short stacks under - let begin = 0; - let beginStack = null; - row.children = []; - while (begin < rowIndices.length) { - beginStack = stackGetter(rowIndices[begin]); - if (beginStack.length > depth) { - break; - } - begin++; - } - if (begin > 0) { - row.children.push(createTreeNode( - row, - columnName + '', - rowIndices.subarray(0, begin), - nextActiveIndex)); - } - // aggregate the rest under frames - if (begin < rowIndices.length) { - let end = begin + 1; - while (end < rowIndices.length) { - const endStack = stackGetter(rowIndices[end]); - if (frameIdGetter(beginStack, depth) !== frameIdGetter(endStack, depth)) { - row.children.push(createTreeNode( - row, - columnName + frameGetter(frameIdGetter(beginStack, depth)), - rowIndices.subarray(begin, end), - expandNextFrame)); - begin = end; - beginStack = endStack; - } - end++; - } - row.children.push(createTreeNode( - row, - columnName + frameGetter(frameIdGetter(beginStack, depth)), - rowIndices.subarray(begin, end), - expandNextFrame)); - } - } - - function contractRow(row) { - if ((row.state & NODE_EXPANDED_BIT) === 0) { - throw 'can not contract row, already contracted'; - } - row.state ^= NODE_EXPANDED_BIT; - const heightChange = 1 - row.height; - updateHeight(row, heightChange); - } - - function pruneExpanders(row, oldExpander, newExpander) { - row.state |= NODE_REPOSITION_BIT; - if (row.expander === oldExpander) { - row.state |= NODE_REAGGREGATE_BIT | NODE_REORDER_BIT | NODE_REPOSITION_BIT; - if ((row.state & NODE_EXPANDED_BIT) !== 0) { - contractRow(row); - } - row.children = null; - row.expander = newExpander; - } else { - row.state |= NODE_REPOSITION_BIT; - const children = row.children; - if (children != null) { - for (let i = 0; i < children.length; i++) { - const child = children[i]; - pruneExpanders(child, oldExpander, newExpander); - } - } - } - } - - return { - addFieldExpander: function addFieldExpander(name, formatter, comparer) { - if (FIELD_EXPANDER_ID_MIN + state.fieldExpanders.length >= FIELD_EXPANDER_ID_MAX) { - throw 'too many field expanders!'; - } - state.fieldExpanders.push({ - name: name, // name for column - formatter: formatter, // row index -> display string - comparer: comparer, // compares by two row indices - }); - return FIELD_EXPANDER_ID_MIN + state.fieldExpanders.length - 1; - }, - addCalleeStackExpander: function addCalleeStackExpander(name, maxStackDepth, stackGetter, frameGetter) { - if (STACK_EXPANDER_ID_MIN + state.fieldExpanders.length >= STACK_EXPANDER_ID_MAX) { - throw 'too many stack expanders!'; - } - state.stackExpanders.push({ - name: name, // name for column - stackGetter: stackGetter, // row index -> stack array - comparers: createStackComparers(stackGetter, calleeFrameIdGetter, maxStackDepth), // depth -> comparer - frameIdGetter: calleeFrameIdGetter, // (stack, depth) -> string id - frameGetter: frameGetter, - }); - return STACK_EXPANDER_ID_MIN + state.stackExpanders.length - 1; - }, - addCallerStackExpander: function addCallerStackExpander(name, maxStackDepth, stackGetter, frameGetter) { - if (STACK_EXPANDER_ID_MIN + state.fieldExpanders.length >= STACK_EXPANDER_ID_MAX) { - throw 'too many stack expanders!'; - } - state.stackExpanders.push({ - name: name, - stackGetter: stackGetter, - comparers: createStackComparers(stackGetter, callerFrameIdGetter, maxStackDepth), - frameIdGetter: callerFrameIdGetter, - frameGetter: frameGetter, - }); - return STACK_EXPANDER_ID_MIN + state.stackExpanders.length - 1; - }, - getExpanders: function getExpanders() { - const expanders = []; - for (let i = 0; i < state.fieldExpanders.length; i++) { - expanders.push(FIELD_EXPANDER_ID_MIN + i); - } - for (let i = 0; i < state.stackExpanders.length; i++) { - expanders.push(STACK_EXPANDER_ID_MIN + i); - } - return expanders; - }, - getExpanderName: function getExpanderName(id) { - if (id >= FIELD_EXPANDER_ID_MIN && id <= FIELD_EXPANDER_ID_MAX) { - return state.fieldExpanders[id - FIELD_EXPANDER_ID_MIN].name; - } else if (id >= STACK_EXPANDER_ID_MIN && id <= STACK_EXPANDER_ID_MAX) { - return state.stackExpanders[id - STACK_EXPANDER_ID_MIN].name; - } - throw 'Unknown expander ID ' + id.toString(); - }, - setActiveExpanders: function setActiveExpanders(ids) { - for (let i = 0; i < ids.length; i++) { - const id = ids[i]; - if (id >= 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!'; - } - } else if (id >= STACK_EXPANDER_ID_MIN && id <= STACK_EXPANDER_ID_MAX) { - if (id - STACK_EXPANDER_ID_MIN >= state.stackExpanders.length) { - throw 'stack expander for id ' + id.toString() + ' does not exist!'; - } - } - } - for (let i = 0; i < ids.length; i++) { - if (state.activeExpanders.length <= i) { - pruneExpanders(state.root, INVALID_ACTIVE_EXPANDER, i); - break; - } else if (ids[i] !== state.activeExpanders[i]) { - pruneExpanders(state.root, i, i); - break; - } - } - // TODO: if ids is prefix of activeExpanders, we need to make an expander invalid - state.activeExpanders = ids.slice(); - }, - getActiveExpanders: function getActiveExpanders() { - return state.activeExpanders.slice(); - }, - addAggregator: function addAggregator(name, aggregator, formatter, sorter) { - if (state.aggregators.length >= AGGREGATOR_ID_MAX) { - throw 'too many aggregators!'; - } - state.aggregators.push({ - name: name, // name for column - aggregator: aggregator, // index array -> aggregate value - formatter: formatter, // aggregate value -> display string - sorter: sorter, // compare two aggregate values - }); - return state.aggregators.length - 1; - }, - getAggregators: function getAggregators() { - const aggregators = []; - for (let i = 0; i < state.aggregators.length; i++) { - aggregators.push(i); - } - return aggregators; - }, - getAggregatorName: function getAggregatorName(id) { - return state.aggregators[id & ACTIVE_AGGREGATOR_MASK].name; - }, - setActiveAggregators: function setActiveAggregators(ids) { - for (let i = 0; i < ids.length; i++) { - const id = ids[i] & ACTIVE_AGGREGATOR_MASK; - if (id < 0 || id > state.aggregators.length) { - throw 'aggregator id ' + id.toString() + ' not valid'; - } - } - state.activeAggregators = ids.slice(); - // NB: evaluate root here because dirty bit is for children - // so someone has to start with root, and it might as well be right away - evaluateAggregate(state.root); - let sorter = noSortOrder; - for (let i = ids.length - 1; i >= 0; i--) { - const ascending = (ids[i] & ACTIVE_AGGREGATOR_ASC_BIT) !== 0; - const id = ids[i] & ACTIVE_AGGREGATOR_MASK; - const comparer = state.aggregators[id].sorter; - const captureSorter = sorter; - const captureIndex = i; - sorter = function (a, b) { - const c = comparer(a.aggregates[captureIndex], b.aggregates[captureIndex]); - if (c === 0) { - return captureSorter(a, b); - } - return ascending ? -c : c; - }; - } - state.sorter = sorter; - state.root.state |= NODE_REORDER_BIT; - }, - getActiveAggregators: function getActiveAggregators() { - return state.activeAggregators.slice(); - }, - getRows: function getRows(top, height) { - const result = new Array(height); - for (let i = 0; i < height; i++) { - result[i] = null; - } - getRowsImpl(state.root, top, height, result); - return result; - }, - getRowLabel: function getRowLabel(row) { - return row.label; - }, - getRowIndent: function getRowIndent(row) { - return row.state >>> NODE_INDENT_SHIFT; - }, - getRowAggregate: function getRowAggregate(row, index) { - const aggregator = state.aggregators[state.activeAggregators[index]]; - return aggregator.formatter(row.aggregates[index]); - }, - getHeight: function getHeight() { - return state.root.height; - }, - canExpand: function canExpand(row) { - return (row.state & NODE_EXPANDED_BIT) === 0 && (row.expander !== INVALID_ACTIVE_EXPANDER); - }, - canContract: function canContract(row) { - return (row.state & NODE_EXPANDED_BIT) !== 0; - }, - expand: function expand(row) { - if ((row.state & NODE_EXPANDED_BIT) !== 0) { - throw 'can not expand row, already expanded'; - } - if (row.height !== 1) { - throw 'unexpanded row has height ' + row.height.toString() + ' != 1'; - } - if (row.children === null) { // first expand, generate children - const activeIndex = row.expander & ACTIVE_EXPANDER_MASK; - let nextActiveIndex = activeIndex + 1; // NB: if next is stack, frame is 0 - if (nextActiveIndex >= state.activeExpanders.length) { - nextActiveIndex = INVALID_ACTIVE_EXPANDER; - } - if (activeIndex >= state.activeExpanders.length) { - throw 'invalid active expander index ' + activeIndex.toString(); - } - const exId = state.activeExpanders[activeIndex]; - if (exId >= FIELD_EXPANDER_ID_MIN && - exId < FIELD_EXPANDER_ID_MIN + state.fieldExpanders.length) { - const expander = state.fieldExpanders[exId - FIELD_EXPANDER_ID_MIN]; - addChildrenWithFieldExpander(row, expander, nextActiveIndex); - } else if (exId >= STACK_EXPANDER_ID_MIN && - exId < STACK_EXPANDER_ID_MIN + state.stackExpanders.length) { - const depth = row.expander >>> ACTIVE_EXPANDER_FRAME_SHIFT; - const expander = state.stackExpanders[exId - STACK_EXPANDER_ID_MIN]; - addChildrenWithStackExpander(row, expander, activeIndex, depth, nextActiveIndex); - } else { - throw 'state.activeIndex ' + activeIndex.toString() - + ' has invalid expander' + exId.toString(); - } - } - row.state |= NODE_EXPANDED_BIT - | NODE_REAGGREGATE_BIT | NODE_REORDER_BIT | NODE_REPOSITION_BIT; - let heightChange = 0; - for (let i = 0; i < row.children.length; i++) { - heightChange += row.children[i].height; - } - updateHeight(row, heightChange); - // if children only contains one node, then expand it as well - if (row.children.length === 1 && this.canExpand(row.children[0])) { - this.expand(row.children[0]); - } - }, - contract: function contract(row) { - contractRow(row); - }, - }; -} diff --git a/local-cli/server/middleware/heapCapture/src/heapCapture.js b/local-cli/server/middleware/heapCapture/src/heapCapture.js deleted file mode 100644 index 4d4099b19..000000000 --- a/local-cli/server/middleware/heapCapture/src/heapCapture.js +++ /dev/null @@ -1,379 +0,0 @@ -/** - * Copyright (c) 2016-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -'use strict'; -/*eslint no-console-disallow: "off"*/ -/*global React ReactDOM Table StringInterner StackRegistry AggrowData Aggrow preLoadedCapture:true*/ - -function RefVisitor(refs, id) { - this.refs = refs; - this.id = id; -} - -RefVisitor.prototype = { - moveToEdge: function moveToEdge(name) { - const ref = this.refs[this.id]; - if (ref && ref.edges) { - const edges = ref.edges; - for (const edgeId in edges) { - if (edges[edgeId] === name) { - this.id = edgeId; - return this; - } - } - } - this.id = undefined; - return this; - }, - moveToFirst: function moveToFirst(callback) { - const ref = this.refs[this.id]; - if (ref && ref.edges) { - const edges = ref.edges; - for (const edgeId in edges) { - this.id = edgeId; - if (callback(edges[edgeId], this)) { - return this; - } - } - } - this.id = undefined; - return this; - }, - forEachEdge: function forEachEdge(callback) { - const ref = this.refs[this.id]; - if (ref && ref.edges) { - const edges = ref.edges; - const visitor = new RefVisitor(this.refs, undefined); - for (const edgeId in edges) { - visitor.id = edgeId; - callback(edges[edgeId], visitor); - } - } - }, - getType: function getType() { - const ref = this.refs[this.id]; - if (ref) { - return ref.type; - } - return undefined; - }, - getRef: function getRef() { - return this.refs[this.id]; - }, - clone: function clone() { - return new RefVisitor(this.refs, this.id); - }, - isDefined: function isDefined() { - return !!this.id; - }, - getValue: function getValue() { - const ref = this.refs[this.id]; - if (ref) { - if (ref.type === 'string') { - if (ref.value) { - return ref.value; - } else { - const rope = []; - this.forEachEdge((name, visitor) => { - if (name && name.startsWith('[') && name.endsWith(']')) { - const index = parseInt(name.substring(1, name.length - 1), 10); - rope[index] = visitor.getValue(); - } - }); - return rope.join(''); - } - } else if (ref.type === 'ScriptExecutable' - || ref.type === 'EvalExecutable' - || ref.type === 'ProgramExecutable') { - return ref.value.url + ':' + ref.value.line + ':' + ref.value.col; - } else if (ref.type === 'FunctionExecutable') { - return ref.value.name + '@' + ref.value.url + ':' + ref.value.line + ':' + ref.value.col; - } else if (ref.type === 'NativeExecutable') { - return ref.value.function + ' ' + ref.value.constructor + ' ' + ref.value.name; - } else if (ref.type === 'Function') { - const executable = this.clone().moveToEdge('@Executable'); - if (executable.id) { - return executable.getRef().type + ' ' + executable.getValue(); - } - } - } - return '#none'; - } -}; - -function forEachRef(refs, callback) { - const visitor = new RefVisitor(refs, undefined); - for (const id in refs) { - visitor.id = id; - callback(visitor); - } -} - -function firstRef(refs, callback) { - for (const id in refs) { - const ref = refs[id]; - if (callback(id, ref)) { - return new RefVisitor(refs, id); - } - } - return new RefVisitor(refs, undefined); -} - -function getInternalInstanceName(visitor) { - const type = visitor.clone().moveToEdge('_currentElement').moveToEdge('type'); - if (type.getType() === 'string') { // element.type is string - return type.getValue(); - } else if (type.getType() === 'Function') { // element.type is function - const displayName = type.clone().moveToEdge('displayName'); - if (displayName.isDefined()) { - return displayName.getValue(); // element.type.displayName - } - const name = type.clone().moveToEdge('name'); - if (name.isDefined()) { - return name.getValue(); // element.type.name - } - type.moveToEdge('@Executable'); - if (type.getType() === 'FunctionExecutable') { - return type.getRef().value.name; // element.type symbolicated name - } - } - return '#unknown'; -} - -function buildReactComponentTree(visitor, registry, strings) { - const ref = visitor.getRef(); - if (ref.reactTree || ref.reactParent === undefined) { - return; // has one or doesn't need one - } - const parentVisitor = ref.reactParent; - if (parentVisitor === null) { - ref.reactTree = registry.insert(registry.root, strings.intern(getInternalInstanceName(visitor))); - } else if (parentVisitor) { - const parentRef = parentVisitor.getRef(); - buildReactComponentTree(parentVisitor, registry, strings); - let relativeName = getInternalInstanceName(visitor); - if (ref.reactKey) { - relativeName = ref.reactKey + ': ' + relativeName; - } - ref.reactTree = registry.insert(parentRef.reactTree, strings.intern(relativeName)); - } else { - throw 'non react instance parent of react instance'; - } -} - -function markReactComponentTree(refs, registry, strings) { - // annotate all refs that are react internal instances with their parent and name - // ref.reactParent = visitor that points to parent instance, - // null if we know it's an instance, but don't have a parent yet - // ref.reactKey = if a key is used to distinguish siblings - forEachRef(refs, (visitor) => { - const visitorClone = visitor.clone(); // visitor will get stomped on next iteration - const ref = visitor.getRef(); - visitor.forEachEdge((edgeName, edgeVisitor) => { - const edgeRef = edgeVisitor.getRef(); - if (edgeRef) { - if (edgeName === '_renderedChildren') { - if (ref.reactParent === undefined) { - // ref is react component, even if we don't have a parent yet - ref.reactParent = null; - } - edgeVisitor.forEachEdge((childName, childVisitor) => { - const childRef = childVisitor.getRef(); - if (childRef && childName.startsWith('.')) { - childRef.reactParent = visitorClone; - childRef.reactKey = childName; - } - }); - } else if (edgeName === '_renderedComponent') { - if (ref.reactParent === undefined) { - ref.reactParent = null; - } - edgeRef.reactParent = visitorClone; - } - } - }); - }); - // build tree of react internal instances (since that's what has the structure) - // fill in ref.reactTree = path registry node - forEachRef(refs, (visitor) => { - buildReactComponentTree(visitor, registry, strings); - }); - // hook in components by looking at their _reactInternalInstance fields - forEachRef(refs, (visitor) => { - const ref = visitor.getRef(); - const instanceRef = visitor.moveToEdge('_reactInternalInstance').getRef(); - if (instanceRef) { - ref.reactTree = instanceRef.reactTree; - } - }); -} - -function functionUrlFileName(visitor) { - const executable = visitor.clone().moveToEdge('@Executable'); - const ref = executable.getRef(); - if (ref && ref.value && ref.value.url) { - const url = ref.value.url; - let file = url.substring(url.lastIndexOf('/') + 1); - if (file.endsWith('.js')) { - file = file.substring(0, file.length - 3); - } - return file; - } - return undefined; -} - -function markModules(refs) { - const modules = firstRef(refs, (id, ref) => ref.type === 'CallbackGlobalObject'); - modules.moveToEdge('require'); - modules.moveToFirst((name, visitor) => visitor.getType() === 'JSActivation'); - modules.moveToEdge('modules'); - modules.forEachEdge((name, visitor) => { - const ref = visitor.getRef(); - visitor.moveToEdge('exports'); - if (visitor.getType() === 'Object') { - visitor.moveToFirst((memberName, member) => member.getType() === 'Function'); - if (visitor.isDefined()) { - ref.module = functionUrlFileName(visitor); - } - } else if (visitor.getType() === 'Function') { - const displayName = visitor.clone().moveToEdge('displayName'); - if (displayName.isDefined()) { - ref.module = displayName.getValue(); - } - ref.module = functionUrlFileName(visitor); - } - if (ref && !ref.module) { - ref.module = '#unknown ' + name; - } - }); -} - -function registerPathToRoot(refs, registry, strings) { - markReactComponentTree(refs, registry, strings); - markModules(refs); - let breadth = []; - forEachRef(refs, (visitor) => { - const ref = visitor.getRef(); - if (ref.type === 'CallbackGlobalObject') { - ref.rootPath = registry.insert(registry.root, strings.intern(ref.type)); - breadth.push(visitor.clone()); - } - }); - while (breadth.length > 0) { - const nextBreadth = []; - for (let i = 0; i < breadth.length; i++) { - const visitor = breadth[i]; - const ref = visitor.getRef(); - visitor.forEachEdge((edgeName, edgeVisitor) => { - const edgeRef = edgeVisitor.getRef(); - if (edgeRef && edgeRef.rootPath === undefined) { - let pathName = edgeRef.type; - if (edgeName) { - pathName = edgeName + ': ' + pathName; - } - edgeRef.rootPath = registry.insert(ref.rootPath, strings.intern(pathName)); - nextBreadth.push(edgeVisitor.clone()); - // copy module and react tree forward - if (edgeRef.module === undefined) { - edgeRef.module = ref.module; - } - if (edgeRef.reactTree === undefined) { - edgeRef.reactTree = ref.reactTree; - } - } - }); - } - breadth = nextBreadth; - } -} - -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 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 - 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 deleted file mode 100644 index f8c0921e7..000000000 --- a/local-cli/server/middleware/heapCapture/src/table.js +++ /dev/null @@ -1,540 +0,0 @@ -/** - * Copyright (c) 2016-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -'use strict'; -/*eslint no-console-disallow: "off"*/ -/*global React:true*/ - -// TODO: -// selection and arrow keys for navigating - -const rowHeight = 20; -const treeIndent = 16; - -class Draggable extends React.Component { // eslint-disable-line no-unused-vars - constructor(props) { - super(props); - } - - render() { - const id = this.props.id; - return React.cloneElement( - this.props.children, - { - draggable: 'true', - onDragStart: (e) => { - e.dataTransfer.setData('text', id); - }, - } - ); - } -} -Draggable.propTypes = { - children: React.PropTypes.element.isRequired, - id: React.PropTypes.string.isRequired, -}; - -class DropTarget extends React.Component { // eslint-disable-line no-unused-vars - constructor(props) { - super(props); - } - - render() { - const thisId = this.props.id; - const dropAction = this.props.dropAction; - return React.cloneElement( - this.props.children, - { - onDragOver: (e) => e.preventDefault(), - onDrop: (e) => { - const sourceId = e.dataTransfer.getData('text'); - e.preventDefault(); - dropAction(sourceId, thisId); - }, - } - ); - } -} - -DropTarget.propTypes = { - children: React.PropTypes.element.isRequired, - id: React.PropTypes.string.isRequired, - dropAction: React.PropTypes.func.isRequired, -}; - -class ExpanderConfiguration extends React.Component { - constructor(props) { - super(props); - } - render() { - const aggrow = this.props.aggrow; - const expander = this.props.expander; - return ( - -
- {aggrow.getExpanderName(expander)} -
-
- ); - } -} - -class TableConfiguration extends React.Component { - constructor(props) { - super(props); - this.state = { - expanded: false, - }; - } - renderExpander(ex) { - return (); - } - render() { - const expanderText = this.state.expanded ? '>>' : '<<'; - const aggrow = this.props.aggrow; - let config = []; - if (this.state.expanded) { - config = aggrow.getExpanders().map((ex) => this.renderExpander(ex)); - } - return ( -
-
this.setState({expanded: !this.state.expanded}) }> - { expanderText } -
- { config } -
- ); - } -} - -TableConfiguration.propTypes = { - aggrow: React.PropTypes.object.isRequired, -}; - -class TableHeader extends React.Component { - constructor(props) { - super(props); - } - render() { - const aggrow = this.props.aggrow; - const aggregators = aggrow.getActiveAggregators(); - const expanders = aggrow.getActiveExpanders(); - const headers = []; - for (let i = 0; i < aggregators.length; i++) { - const name = aggrow.getAggregatorName(aggregators[i]); - headers.push(( - -
-
)); - headers.push(( -
{name}
-
)); - } - headers.push(( - -
-
)); - for (let i = 0; i < expanders.length; i++) { - const name = aggrow.getExpanderName(expanders[i]); - const bg = (i % 2 === 0) ? 'white' : 'lightGray'; - headers.push(( -
- {name} -
-
)); - const sep = i + 1 < expanders.length ? '->' : '...'; - headers.push(( - -
- {sep} -
-
) - ); - } - return ( -
- {headers} -
- ); - } -} - -TableHeader.propTypes = { - aggrow: React.PropTypes.object.isRequired, - dropAction: React.PropTypes.func.isRequired, -}; - -class Table extends React.Component { // eslint-disable-line no-unused-vars - constructor(props) { - super(props); - this.state = { - aggrow: props.aggrow, - viewport: { top: 0, height: 100 }, - cursor: 0, - }; - } - - scroll(e) { - const viewport = e.target; - const top = Math.floor((viewport.scrollTop - viewport.clientHeight * 1.0) / rowHeight); - const height = Math.ceil(viewport.clientHeight * 3.0 / rowHeight); - if (top !== this.state.viewport.top || height !== this.state.viewport.height) { - this.setState({viewport: {top, height}}); - } - } - - _contractRow(row) { - let newCursor = this.state.cursor; - if (newCursor > row.top && newCursor < row.top + row.height) { // in contracted section - newCursor = row.top; - } else if (newCursor >= row.top + row.height) { // below contracted section - newCursor -= row.height - 1; - } - this.state.aggrow.contract(row); - this.setState({cursor: newCursor}); - console.log('-' + row.top); - } - - _expandRow(row) { - let newCursor = this.state.cursor; - this.state.aggrow.expand(row); - if (newCursor > row.top) { // below expanded section - newCursor += row.height - 1; - } - this.setState({cursor: newCursor}); - console.log('+' + row.top); - } - - _scrollDiv: null; - - _keepCursorInViewport() { - if (this._scrollDiv) { - const cursor = this.state.cursor; - const scrollDiv = this._scrollDiv; - if (cursor * rowHeight < scrollDiv.scrollTop + scrollDiv.clientHeight * 0.1) { - scrollDiv.scrollTop = cursor * rowHeight - scrollDiv.clientHeight * 0.1; - } else if ((cursor + 1) * rowHeight > scrollDiv.scrollTop + scrollDiv.clientHeight * 0.9) { - scrollDiv.scrollTop = (cursor + 1) * rowHeight - scrollDiv.clientHeight * 0.9; - } - } - } - - keydown(e) { - const aggrow = this.state.aggrow; - let cursor = this.state.cursor; - let row = aggrow.getRows(cursor, 1)[0]; - switch (e.keyCode) { - case 38: // up - if (cursor > 0) { - this.setState({cursor: cursor - 1}); - this._keepCursorInViewport(); - } - e.preventDefault(); - break; - case 40: // down - if (cursor < aggrow.getHeight() - 1) { - this.setState({cursor: cursor + 1}); - this._keepCursorInViewport(); - } - e.preventDefault(); - break; - case 37: // left - if (aggrow.canContract(row)) { - this._contractRow(row); - } else if (aggrow.getRowIndent(row) > 0) { - const indent = aggrow.getRowIndent(row) - 1; - while (aggrow.getRowIndent(row) > indent) { - cursor--; - row = aggrow.getRows(cursor, 1)[0]; - } - this.setState({cursor: cursor}); - this._keepCursorInViewport(); - } - e.preventDefault(); - break; - case 39: // right - if (aggrow.canExpand(row)) { - this._expandRow(row); - } else if (cursor < aggrow.getHeight() - 1) { - this.setState({cursor: cursor + 1}); - this._keepCursorInViewport(); - } - e.preventDefault(); - break; - } - } - - dropAction(s, d) { - const aggrow = this.state.aggrow; - console.log('dropped ' + s + ' to ' + d); - if (s.startsWith('aggregate:active:')) { - const sIndex = parseInt(s.substr(17), 10); - let dIndex = -1; - const active = aggrow.getActiveAggregators(); - const dragged = active[sIndex]; - if (d.startsWith('aggregate:insert:')) { - dIndex = parseInt(d.substr(17), 10); - } else if (d === 'divider:insert') { - dIndex = active.length; - } else { - throw 'not allowed to drag ' + s + ' to ' + d; - } - if (dIndex > sIndex) { - dIndex--; - } - active.splice(sIndex, 1); - active.splice(dIndex, 0, dragged); - aggrow.setActiveAggregators(active); - this.setState({cursor:0}); - } else if (s.startsWith('expander:active:')) { - const sIndex = parseInt(s.substr(16), 10); - let dIndex = -1; - const active = aggrow.getActiveExpanders(); - const dragged = active[sIndex]; - if (d.startsWith('expander:insert:')) { - dIndex = parseInt(d.substr(16), 10); - } else if (d === 'divider:insert') { - dIndex = 0; - } else { - throw 'not allowed to drag ' + s + ' to ' + d; - } - if (dIndex > sIndex) { - dIndex--; - } - active.splice(sIndex, 1); - active.splice(dIndex, 0, dragged); - aggrow.setActiveExpanders(active); - this.setState({cursor:0}); - } else if (s.startsWith('expander:add:')) { - let dIndex = -1; - const sExpander = parseInt(s.substring(13), 10); - if (d.startsWith('expander:insert:')) { - dIndex = parseInt(d.substr(16), 10); - } else if (d === 'divider:insert') { - dIndex = 0; - } else { - throw 'not allowed to drag ' + s + ' to ' + d; - } - const active = aggrow.getActiveExpanders(); - active.splice(dIndex, 0, sExpander); - aggrow.setActiveExpanders(active); - this.setState({cursor:0}); - } - } - - render() { - return ( -
-
- this.dropAction(s, d)} /> -
this.scroll(e) } - ref={(div) => { this._scrollDiv = div; } }> -
- { this.renderVirtualizedRows() } -
-
-
- -
- ); - } - - renderVirtualizedRows() { - const aggrow = this.state.aggrow; - const viewport = this.state.viewport; - const rows = aggrow.getRows(viewport.top, viewport.height); - return ( -
- { rows.map(child => this.renderRow(child)) } -
- ); - } - - renderRow(row) { - if (row === null) { - return null; - } - let bg = 'lightGray'; - const aggrow = this.state.aggrow; - const columns = []; - let rowText = ''; - const indent = 4 + aggrow.getRowIndent(row) * treeIndent; - const aggregates = aggrow.getActiveAggregators(); - if (row.parent !== null && (row.parent.expander % 2 === 0)) { - bg = 'white'; - } - if (row.top === this.state.cursor) { - bg = 'lightblue'; - } - for (let i = 0; i < aggregates.length; i++) { - var aggregate = aggrow.getRowAggregate(row, i); - columns.push(( -
- )); - columns.push(( -
- {aggregate} -
- )); - } - columns.push(( -
- )); - if (aggrow.canExpand(row)) { - columns.push(( -
this._expandRow(row) } - >+
- )); - } else if (aggrow.canContract(row)) { - columns.push(( -
this._contractRow(row) } - >-
- )); - } else { - columns.push(( -
- )); - } - rowText += aggrow.getRowLabel(row); - columns.push(( -
- {rowText} -
- )); - return ( -
{ - this.setState({cursor: row.top}); - }}> - {columns} -
- ); - } - - componentDidMount() { - this.keydown = this.keydown.bind(this); - document.body.addEventListener('keydown', this.keydown); - } - - componentWillUnmount() { - document.body.removeEventListener('keydown', this.keydown); - } -}