1d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelvar notify = []; 2d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelvar experimentIdCounter = 0; 3d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel/** 4d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel * The questions above are answered by running a bunch of experiments 5d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel * exhaustively for all combinations of HTML element names. 6d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel * 7d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel * @param makeHtmlString takes one or more element names. 8d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel * Its {@code length} property specifies its arity, and runExperiment 9d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel * calls it iteratively with every permutation of length element names. 10d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel * @param checkDom receives the element names passed to makeHtmlString, 11d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel * an HTML document body created by parsing the HTML from makeHtmlString 12d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel * and initialResult/return value from last call to checkDom. 13d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel * @param initialResult the first result value to pass to checkDom. 14d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel * @param opt_elementNames an array of element names which defaults to 15d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel * window.elementNames. 16d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel */ 17d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelfunction runExperiment(makeHtmlString, checkDom, initialResult, onResult, 18d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel opt_elementNames) { 19d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var experimentIndex = ++experimentIdCounter; 20d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var iframes = document.getElementById('experiment-iframes'); 21d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var iframe = document.createElement('iframe'); 22d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel iframes.appendChild(iframe); 23d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 24d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var elementNames = opt_elementNames || window.elementNames; 25d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 26d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var nElements = elementNames.length; 27d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var arity = makeHtmlString.length; 28d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var nRuns = Math.pow(nElements, arity); 29d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var runIndex = 0; 30d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var paramIndices = new Array(arity); 31d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var paramValues = new Array(arity); 32d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel for (var i = 0; i < arity; ++i) { 33d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel paramIndices[i] = 0; 34d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel paramValues[i] = elementNames[0]; 35d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 36d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var exhausted = nRuns === 0; 37d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 38d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var progressCounterContainer = 39d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel document.getElementById('experiment-progress-counter'); 40d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 41d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var startTime = Date.now(); 42d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var lastProgressUpdateTime = startTime; 43d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 44d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var result = initialResult; 45d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 46d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var progressCounter; 47d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (progressCounterContainer) { 48d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel progressCounter = document.createElement('li'); 49d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel progressCounter.style.width = '0'; 50d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel progressCounterContainer.appendChild(progressCounter); 51d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 52d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 53d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel function advance() { 54d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel // Advance to next permutation. 55d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var i; 56d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel for (i = arity; --i >= 0;) { 57d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (++paramIndices[i] < nElements) { 58d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel paramValues[i] = elementNames[paramIndices[i]]; 59d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel break; 60d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 61d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel paramIndices[i] = 0; 62d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel paramValues [i] = elementNames[0]; 63d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 64d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel ++runIndex; 65d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (progressCounter) { 66d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var now = Date.now(); 67d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (now - lastProgressUpdateTime > 250 ) { 68d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var ratio = runIndex / nRuns; 69d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel progressCounter.style.width = (100 * ratio).toFixed(2) + '%'; 70d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel lastProgressUpdateTime = now; 71d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var timeSoFar = now - startTime; 72d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (timeSoFar > 5000) { 73d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel // Assuming time per run is constant: 74d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel // total_time / nRuns = time_so_far / runIndex 75d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel // total_time = time_so_far * nRuns / runIndex 76d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel // = time_so_far / ratio 77d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel // eta = total_time - time_so_far 78d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel // = time_so_far / ratio - time_so_far 79d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel // = time_so_far * (1/ratio - 1) 80d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var eta = timeSoFar * (1 / ratio - 1); 81d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel progressCounter.innerHTML = eta > 250 82d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel ? 'ETA:' + (eta / 1000).toFixed(1) + 's' : ''; 83d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 84d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 85d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 86d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel exhausted = i < 0; 87d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 88d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 89d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel function step() { 90d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var htmlString = null; 91d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel // Try to generate an HTML string. 92d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel // The maker can return a nullish value to abort or punt on an experiment, 93d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel // so we loop until we find work to do. 94d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel while (!exhausted) { 95d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel paramValues.length = arity; 96d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel htmlString = makeHtmlString.apply(null, paramValues); 97d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (htmlString != null) { 98d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel break; 99d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 100d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel advance(); 101d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 102d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 103d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (htmlString == null) { 104d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var endTime = Date.now(); 105d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel console.log('experiment took %d millis for %d runs', 106d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel (endTime - startTime), nRuns); 107d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (progressCounter) { 108d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel setTimeout(function () { 109d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel iframes.removeChild(iframe); 110d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel progressCounterContainer.removeChild(progressCounter); 111d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel }, 250); 112d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 113d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel onResult(result); 114d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } else { 115d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var notifyIndex = notify.indexOf(void 0); 116d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (notifyIndex < 0) { notifyIndex = notify.length; } 117d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel notify[notifyIndex] = function () { 118d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel notify[notifyIndex] = void 0; 119d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 120d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel // Process result 121d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel paramValues[arity] = iframe.contentDocument.body; 122d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel paramValues[arity + 1] = result; 123d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel result = checkDom.apply(null, paramValues); 124d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel paramValues.length = arity; 125d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 126d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel // Requeue the next step on the parent frames event queue. 127d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel setTimeout(function () { advance(); step(); }, 0); 128d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel }; 129d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel // Start the iframe parsing its body. 130d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel iframe.srcdoc = ( 131d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel '<!doctype html><html><head></head>' 132d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel + '<body onload="parent.notify[' + notifyIndex + ']()">' 133d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel + htmlString 134d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel ); 135d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 136d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 137d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel step(); 138d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel} 139d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 140d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelfunction formatDataToJsonHTML(data) { 141d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var out = []; 142d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var htmlForNullValue = '<span class="json-kw">null</span>'; 143d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var htmlForErrorValue = '<span class="json-kw json-err">null</span>'; 144d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var depth = 0; 145d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var spaces = ' '; 146d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel format(data); 147d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel return out.join(''); 148d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 149d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel function format(v) { 150d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (v == null) { 151d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel out.push(htmlForNullValue); 152d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel return; 153d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 154d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var t = typeof v; 155d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (t === 'boolean') { 156d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel out.push('<span class="json-kw">', v, '</span>'); 157d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } else if (t === 'number') { 158d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (isFinite(v)) { 159d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel out.push('<span class="json-val">', v, '</span>'); 160d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } else { 161d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel out.push(htmlForErrorValue); 162d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 163d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } else if (t === 'string' || v instanceof String) { 164d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var token = JSON.stringify(String(v)); 165d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel token = token.replace(/&/g, '&').replace(/</g, '<'); 166d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel out.push('<span class="json-str">', token, '</span>'); 167d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } else { 168d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var length = v.length; 169d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var isSeries = ('number' === typeof length 170d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel && length === (length & 0x7fffffff)); 171d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel // Don't put properties on their own line if there are only a few. 172d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var inlinePropLimit = isSeries ? 8 : 4; 173d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var inline = true; 174d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var numProps = 0; 175d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel for (var k in v) { 176d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (!Object.hasOwnProperty.call(v, k)) { continue; } 177d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var propValue = v[k]; 178d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if ((propValue != null && typeof propValue == 'object') 179d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel || ++numProps > inlinePropLimit) { 180d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel inline = false; 181d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel break; 182d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 183d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 184d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel // Put the appropriate white-space inside brackets and after commas. 185d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel function maybeIndent(afterComma) { 186d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (inline) { 187d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (afterComma) { out.push(' '); } 188d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } else { 189d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel out.push('\n'); 190d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var nSpaces = depth * 2; 191d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel while (nSpaces > 0) { 192d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var nToPush = Math.min(nSpaces, spaces.length); 193d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel out.push(spaces.substring(0, nToPush)); 194d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel nSpaces -= nToPush; 195d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 196d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 197d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 198d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var onclick = depth 199d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel ? ' onclick="return toggleJsonBlock(this, event)"' 200d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel : ''; 201d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel // Mark blocks so that we can do expandos on collections. 202d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel out.push('<span class="json-ext json-block-', depth, 203d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel depth === 0 || inline ? ' json-nocollapse' : '', 204d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel '"', onclick, '>', 205d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel isSeries ? '[' : '{', 206d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel // Emit link-like ellipses that can serve as a button for 207d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel // expando-ness. 208d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel '<span class="json-ell">…</span>', 209d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel '<span class="json-int">'); 210d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel ++depth; 211d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (isSeries) { 212d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel for (var i = 0; i < length; ++i) { 213d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (i) { out.push(','); } 214d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel maybeIndent(i !== 0); 215d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel format(v[i]); 216d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 217d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } else { 218d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var needsComma = false; 219d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel for (var k in v) { 220d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (!Object.hasOwnProperty.call(v, k)) { continue; } 221d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (needsComma) { 222d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel out.push(','); 223d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 224d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel maybeIndent(needsComma); 225d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel out.push('<span class="json-prop">'); 226d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel format(String(k)); 227d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel out.push(': '); 228d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel format(v[k]); 229d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel out.push('</span>'); 230d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel needsComma = true; 231d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 232d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 233d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel --depth; 234d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel maybeIndent(false); 235d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel out.push('</span>', isSeries ? ']' : '}', '</span>'); 236d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 237d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 238d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel} 239d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 240d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelfunction displayJson(data, container) { 241d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel container.innerHTML = formatDataToJsonHTML(data); 242d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel} 243d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 244d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelfunction toggleJsonBlock(el, event) { 245d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel event && event.stopPropagation && event.stopPropagation(); 246d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var className = el.className; 247d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var classNameCollapsed = className.replace(/\bjson-expanded\b/g, ''); 248d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel className = className === classNameCollapsed 249d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel ? className + ' json-expanded' : classNameCollapsed; 250d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel className = className.replace(/^ +| +$| +( [^ ])/g, "$1"); 251d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel el.className = className; 252d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel return false; 253d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel} 254d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 255d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelfunction Promise() { 256d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (!(this instanceof Promise)) { return new Promise(); } 257d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel this.paused = []; 258d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel this.satisfy = function () { 259d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var paused = this.paused; 260d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelconsole.log('satisfying ' + paused.length); 261d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel for (var i = 0, n = paused.length; i < n; ++i) { 262d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel setTimeout(paused[i], 0); 263d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 264d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel this.paused.length = 0; 265d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel }; 266d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel} 267d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelPromise.prototype.toString = function () { return "Promise"; }; 268d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelfunction when(f, var_args) { 269d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var unsatisfied = []; 270d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel for (var i = 1, n = arguments.length; i < n; ++i) { 271d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var argument = arguments[i]; 272d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (argument instanceof Promise) { 273d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel unsatisfied.push(argument); 274d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 275d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 276d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var nToWaitFor = unsatisfied.length; 277d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (nToWaitFor) { 278d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var pauser = function pauser() { 279d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (!--nToWaitFor) { 280d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel setTimeout(f, 0); 281d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 282d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel }; 283d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel for (var j = 0; j < nToWaitFor; ++j) { 284d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel unsatisfied[j].paused.push(pauser); 285d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 286d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel unsatisfied = null; 287d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } else { 288d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel setTimeout(f, 0); 289d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 290d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel} 291d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 292d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelfunction newBlankObject() { 293d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel return (Object.create || Object)(null); 294d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel} 295d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 296d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelfunction getOwn(o, k, opt_default) { 297d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel return Object.hasOwnProperty.call(o, k) ? o[k] : opt_default; 298d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel} 299d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 300d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelfunction breadthFirstSearch(start, isEnd, eq, adjacent) { 301d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var stack = [{ node: start, next: null }]; 302d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel while (stack.length) { 303d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var candidate = stack.shift(); 304d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (isEnd(candidate.node)) { 305d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var path = [candidate.node]; 306d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel while (candidate.next) { 307d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel candidate = candidate.next; 308d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel path.push(candidate.node); 309d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 310d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel return path; 311d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 312d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var adjacentNodes = adjacent(candidate.node); 313d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel adj: 314d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel for (var i = 0, n = adjacentNodes.length; i < n; ++i) { 315d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var adjacentNode = adjacentNodes[i]; 316d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel for (var dupe = candidate; dupe; dupe = dupe.next) { 317d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (eq(dupe.node, adjacentNode)) { continue adj; } 318d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 319d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel stack.push({ node: adjacentNode, next: candidate }); 320d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 321d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 322d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel return null; 323d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel} 324d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 325d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelfunction reverseMultiMap(multimap) { 326d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var reverse = newBlankObject(); 327d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel for (var k in multimap) { 328d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (Object.hasOwnProperty.call(multimap, k)) { 329d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var values = multimap[k]; 330d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel for (var i = 0, n = values.length; i < n; ++i) { 331d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var value = values[i]; 332d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var reverseKeys = getOwn(reverse, value) || []; 333d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel reverse[value] = reverseKeys; 334d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel reverseKeys.push(k); 335d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 336d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 337d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 338d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel return reverse; 339d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel} 340d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 341d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelfunction innerTextOf(element) { 342d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel function appendTextOf(node, out) { 343d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel switch (node.nodeType) { 344d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel case 1: // Element 345d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel for (var c = node.firstChild; c; c = c.nextSibling) { 346d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel appendTextOf(c, out); 347d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 348d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel break; 349d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel case 3: case 4: case 6: // Text / CDATA / Entity 350d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel out.push(node.nodeValue); 351d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel break; 352d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 353d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 354d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var buf = []; 355d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (element) { appendTextOf(element, buf); } 356d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel return buf.join(''); 357d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel} 358d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 359d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelfunction sortedMultiMap(mm) { 360d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var props = []; 361d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel for (var k in mm) { 362d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (!Object.hasOwnProperty.call(mm, k)) { continue; } 363d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var v = mm[k]; 364d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (v instanceof Array) { 365d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel v = v.slice(); 366d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel v.sort(); 367d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 368d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel props.push([k, v]); 369d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 370d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel props.sort( 371d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel function (a, b) { 372d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel a = a[0]; 373d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel b = b[0]; 374d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (a < b) { return -1; } 375d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (b < a) { return 1; } 376d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel return 0; 377d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel }); 378d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var sorted = newBlankObject(); 379d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel for (var i = 0, n = props.length; i < n; ++i) { 380d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var prop = props[i]; 381d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel sorted[prop[0]] = prop[1]; 382d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 383d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel return sorted; 384d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel} 385d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 386d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelfunction makeSet(strs) { 387d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel var s = newBlankObject(); 388d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel for (var i = 0, n = strs.length; i < n; ++i) { 389d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel s[strs[i]] = s; 390d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 391d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel return s; 392d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel} 393d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 394d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelfunction inSet(s, str) { 395d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel return s[str] === s; 396d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel} 397d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 398d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelfunction elementContainsComment(el) { 399d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel return elementContainsNodeOfType(el, 8); 400d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel} 401d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 402d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelfunction elementContainsText(el) { 403d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel return elementContainsNodeOfType(el, 3); 404d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel} 405d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel 406d619c4a1a90430a4111eb71444350aa321a289dbmikesamuelfunction elementContainsNodeOfType(el, nodeType) { 407d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (el) { 408d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel for (var c = el.firstChild; c; c = c.nextSibling) { 409d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel if (c.nodeType === nodeType) { return true; } 410d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 411d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel return false; 412d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel } 413d619c4a1a90430a4111eb71444350aa321a289dbmikesamuel} 414