| // Copyright 2008 the V8 project authors. All rights reserved. | 
 | // Redistribution and use in source and binary forms, with or without | 
 | // modification, are permitted provided that the following conditions are | 
 | // met: | 
 | // | 
 | //     * Redistributions of source code must retain the above copyright | 
 | //       notice, this list of conditions and the following disclaimer. | 
 | //     * Redistributions in binary form must reproduce the above | 
 | //       copyright notice, this list of conditions and the following | 
 | //       disclaimer in the documentation and/or other materials provided | 
 | //       with the distribution. | 
 | //     * Neither the name of Google Inc. nor the names of its | 
 | //       contributors may be used to endorse or promote products derived | 
 | //       from this software without specific prior written permission. | 
 | // | 
 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
 |  | 
 | "use strict"; | 
 |  | 
 | String.prototype.startsWith = function (str) { | 
 |   if (str.length > this.length) { | 
 |     return false; | 
 |   } | 
 |   return this.substr(0, str.length) == str; | 
 | }; | 
 |  | 
 | function log10(num) { | 
 |   return Math.log(num)/Math.log(10); | 
 | } | 
 |  | 
 | function ToInspectableObject(obj) { | 
 |   if (!obj && typeof obj === 'object') { | 
 |     return void 0; | 
 |   } else { | 
 |     return Object(obj); | 
 |   } | 
 | } | 
 |  | 
 | function GetCompletions(global, last, full) { | 
 |   var full_tokens = full.split(); | 
 |   full = full_tokens.pop(); | 
 |   var parts = full.split('.'); | 
 |   parts.pop(); | 
 |   var current = global; | 
 |   for (var i = 0; i < parts.length; i++) { | 
 |     var part = parts[i]; | 
 |     var next = current[part]; | 
 |     if (!next) { | 
 |       return []; | 
 |     } | 
 |     current = next; | 
 |   } | 
 |   var result = []; | 
 |   current = ToInspectableObject(current); | 
 |   while (typeof current !== 'undefined') { | 
 |     var mirror = new $debug.ObjectMirror(current); | 
 |     var properties = mirror.properties(); | 
 |     for (var i = 0; i < properties.length; i++) { | 
 |       var name = properties[i].name(); | 
 |       if (typeof name === 'string' && name.startsWith(last)) { | 
 |         result.push(name); | 
 |       } | 
 |     } | 
 |     current = ToInspectableObject(current.__proto__); | 
 |   } | 
 |   return result; | 
 | } | 
 |  | 
 |  | 
 | // Global object holding debugger related constants and state. | 
 | var Debug = {}; | 
 |  | 
 |  | 
 | // Debug events which can occour in the V8 JavaScript engine. These originate | 
 | // from the API include file v8-debug.h. | 
 | Debug.DebugEvent = { Break: 1, | 
 |                      Exception: 2, | 
 |                      NewFunction: 3, | 
 |                      BeforeCompile: 4, | 
 |                      AfterCompile: 5 }; | 
 |  | 
 |  | 
 | // The different types of scripts matching enum ScriptType in objects.h. | 
 | Debug.ScriptType = { Native: 0, | 
 |                      Extension: 1, | 
 |                      Normal: 2 }; | 
 |  | 
 |  | 
 | // The different types of script compilations matching enum | 
 | // Script::CompilationType in objects.h. | 
 | Debug.ScriptCompilationType = { Host: 0, | 
 |                                 Eval: 1, | 
 |                                 JSON: 2 }; | 
 |  | 
 |  | 
 | // The different types of scopes matching constants runtime.cc. | 
 | Debug.ScopeType = { Global: 0, | 
 |                     Local: 1, | 
 |                     With: 2, | 
 |                     Closure: 3, | 
 |                     Catch: 4, | 
 |                     Block: 5 }; | 
 |  | 
 |  | 
 | // Current debug state. | 
 | var kNoFrame = -1; | 
 | Debug.State = { | 
 |   currentFrame: kNoFrame, | 
 |   displaySourceStartLine: -1, | 
 |   displaySourceEndLine: -1, | 
 |   currentSourceLine: -1 | 
 | }; | 
 | var trace_compile = false;  // Tracing all compile events? | 
 | var trace_debug_json = false; // Tracing all debug json packets? | 
 | var last_cmd = ''; | 
 | //var lol_is_enabled;  // Set to true in d8.cc if LIVE_OBJECT_LIST is defined. | 
 | var lol_next_dump_index = 0; | 
 | var kDefaultLolLinesToPrintAtATime = 10; | 
 | var kMaxLolLinesToPrintAtATime = 1000; | 
 | var repeat_cmd_line = ''; | 
 | var is_running = true; | 
 | // Global variable used to store whether a handle was requested. | 
 | var lookup_handle = null; | 
 |  | 
 | // Copied from debug-delay.js.  This is needed below: | 
 | function ScriptTypeFlag(type) { | 
 |   return (1 << type); | 
 | } | 
 |  | 
 |  | 
 | // Process a debugger JSON message into a display text and a running status. | 
 | // This function returns an object with properties "text" and "running" holding | 
 | // this information. | 
 | function DebugMessageDetails(message) { | 
 |   if (trace_debug_json) { | 
 |     print("received: '" + message + "'"); | 
 |   } | 
 |   // Convert the JSON string to an object. | 
 |   var response = new ProtocolPackage(message); | 
 |   is_running = response.running(); | 
 |  | 
 |   if (response.type() == 'event') { | 
 |     return DebugEventDetails(response); | 
 |   } else { | 
 |     return DebugResponseDetails(response); | 
 |   } | 
 | } | 
 |  | 
 | function DebugEventDetails(response) { | 
 |   var details = {text:'', running:false}; | 
 |  | 
 |   // Get the running state. | 
 |   details.running = response.running(); | 
 |  | 
 |   var body = response.body(); | 
 |   var result = ''; | 
 |   switch (response.event()) { | 
 |     case 'break': | 
 |       if (body.breakpoints) { | 
 |         result += 'breakpoint'; | 
 |         if (body.breakpoints.length > 1) { | 
 |           result += 's'; | 
 |         } | 
 |         result += ' #'; | 
 |         for (var i = 0; i < body.breakpoints.length; i++) { | 
 |           if (i > 0) { | 
 |             result += ', #'; | 
 |           } | 
 |           result += body.breakpoints[i]; | 
 |         } | 
 |       } else { | 
 |         result += 'break'; | 
 |       } | 
 |       result += ' in '; | 
 |       result += body.invocationText; | 
 |       result += ', '; | 
 |       result += SourceInfo(body); | 
 |       result += '\n'; | 
 |       result += SourceUnderline(body.sourceLineText, body.sourceColumn); | 
 |       Debug.State.currentSourceLine = body.sourceLine; | 
 |       Debug.State.displaySourceStartLine = -1; | 
 |       Debug.State.displaySourceEndLine = -1; | 
 |       Debug.State.currentFrame = 0; | 
 |       details.text = result; | 
 |       break; | 
 |  | 
 |     case 'exception': | 
 |       if (body.uncaught) { | 
 |         result += 'Uncaught: '; | 
 |       } else { | 
 |         result += 'Exception: '; | 
 |       } | 
 |       result += '"'; | 
 |       result += body.exception.text; | 
 |       result += '"'; | 
 |       if (body.sourceLine >= 0) { | 
 |         result += ', '; | 
 |         result += SourceInfo(body); | 
 |         result += '\n'; | 
 |         result += SourceUnderline(body.sourceLineText, body.sourceColumn); | 
 |         Debug.State.currentSourceLine = body.sourceLine; | 
 |         Debug.State.displaySourceStartLine = -1; | 
 |         Debug.State.displaySourceEndLine = -1; | 
 |         Debug.State.currentFrame = 0; | 
 |       } else { | 
 |         result += ' (empty stack)'; | 
 |         Debug.State.currentSourceLine = -1; | 
 |         Debug.State.displaySourceStartLine = -1; | 
 |         Debug.State.displaySourceEndLine = -1; | 
 |         Debug.State.currentFrame = kNoFrame; | 
 |       } | 
 |       details.text = result; | 
 |       break; | 
 |  | 
 |     case 'afterCompile': | 
 |       if (trace_compile) { | 
 |         result = 'Source ' + body.script.name + ' compiled:\n'; | 
 |         var source = body.script.source; | 
 |         if (!(source[source.length - 1] == '\n')) { | 
 |           result += source; | 
 |         } else { | 
 |           result += source.substring(0, source.length - 1); | 
 |         } | 
 |       } | 
 |       details.text = result; | 
 |       break; | 
 |  | 
 |     case 'scriptCollected': | 
 |       details.text = result; | 
 |       break; | 
 |  | 
 |     default: | 
 |       details.text = 'Unknown debug event ' + response.event(); | 
 |   } | 
 |  | 
 |   return details; | 
 | } | 
 |  | 
 |  | 
 | function SourceInfo(body) { | 
 |   var result = ''; | 
 |  | 
 |   if (body.script) { | 
 |     if (body.script.name) { | 
 |       result += body.script.name; | 
 |     } else { | 
 |       result += '[unnamed]'; | 
 |     } | 
 |   } | 
 |   result += ' line '; | 
 |   result += body.sourceLine + 1; | 
 |   result += ' column '; | 
 |   result += body.sourceColumn + 1; | 
 |  | 
 |   return result; | 
 | } | 
 |  | 
 |  | 
 | function SourceUnderline(source_text, position) { | 
 |   if (!source_text) { | 
 |     return; | 
 |   } | 
 |  | 
 |   // Create an underline with a caret pointing to the source position. If the | 
 |   // source contains a tab character the underline will have a tab character in | 
 |   // the same place otherwise the underline will have a space character. | 
 |   var underline = ''; | 
 |   for (var i = 0; i < position; i++) { | 
 |     if (source_text[i] == '\t') { | 
 |       underline += '\t'; | 
 |     } else { | 
 |       underline += ' '; | 
 |     } | 
 |   } | 
 |   underline += '^'; | 
 |  | 
 |   // Return the source line text with the underline beneath. | 
 |   return source_text + '\n' + underline; | 
 | } | 
 |  | 
 |  | 
 | // Converts a text command to a JSON request. | 
 | function DebugCommandToJSONRequest(cmd_line) { | 
 |   var result = new DebugRequest(cmd_line).JSONRequest(); | 
 |   if (trace_debug_json && result) { | 
 |     print("sending: '" + result + "'"); | 
 |   } | 
 |   return result; | 
 | } | 
 |  | 
 |  | 
 | function DebugRequest(cmd_line) { | 
 |   // If the very first character is a { assume that a JSON request have been | 
 |   // entered as a command. Converting that to a JSON request is trivial. | 
 |   if (cmd_line && cmd_line.length > 0 && cmd_line.charAt(0) == '{') { | 
 |     this.request_ = cmd_line; | 
 |     return; | 
 |   } | 
 |  | 
 |   // Check for a simple carriage return to repeat the last command: | 
 |   var is_repeating = false; | 
 |   if (cmd_line == '\n') { | 
 |     if (is_running) { | 
 |       cmd_line = 'break'; // Not in debugger mode, break with a frame request. | 
 |     } else { | 
 |       cmd_line = repeat_cmd_line; // use command to repeat. | 
 |       is_repeating = true; | 
 |     } | 
 |   } | 
 |   if (!is_running) { // Only save the command if in debugger mode. | 
 |     repeat_cmd_line = cmd_line;   // save last command. | 
 |   } | 
 |  | 
 |   // Trim string for leading and trailing whitespace. | 
 |   cmd_line = cmd_line.replace(/^\s+|\s+$/g, ''); | 
 |  | 
 |   // Find the command. | 
 |   var pos = cmd_line.indexOf(' '); | 
 |   var cmd; | 
 |   var args; | 
 |   if (pos == -1) { | 
 |     cmd = cmd_line; | 
 |     args = ''; | 
 |   } else { | 
 |     cmd = cmd_line.slice(0, pos); | 
 |     args = cmd_line.slice(pos).replace(/^\s+|\s+$/g, ''); | 
 |   } | 
 |  | 
 |   if ((cmd === undefined) || !cmd) { | 
 |     this.request_ = void 0; | 
 |     return; | 
 |   } | 
 |  | 
 |   last_cmd = cmd; | 
 |  | 
 |   // Switch on command. | 
 |   switch (cmd) { | 
 |     case 'continue': | 
 |     case 'c': | 
 |       this.request_ = this.continueCommandToJSONRequest_(args); | 
 |       break; | 
 |  | 
 |     case 'step': | 
 |     case 's': | 
 |       this.request_ = this.stepCommandToJSONRequest_(args, 'in'); | 
 |       break; | 
 |  | 
 |     case 'stepi': | 
 |     case 'si': | 
 |       this.request_ = this.stepCommandToJSONRequest_(args, 'min'); | 
 |       break; | 
 |  | 
 |     case 'next': | 
 |     case 'n': | 
 |       this.request_ = this.stepCommandToJSONRequest_(args, 'next'); | 
 |       break; | 
 |  | 
 |     case 'finish': | 
 |     case 'fin': | 
 |       this.request_ = this.stepCommandToJSONRequest_(args, 'out'); | 
 |       break; | 
 |  | 
 |     case 'backtrace': | 
 |     case 'bt': | 
 |       this.request_ = this.backtraceCommandToJSONRequest_(args); | 
 |       break; | 
 |  | 
 |     case 'frame': | 
 |     case 'f': | 
 |       this.request_ = this.frameCommandToJSONRequest_(args); | 
 |       break; | 
 |  | 
 |     case 'scopes': | 
 |       this.request_ = this.scopesCommandToJSONRequest_(args); | 
 |       break; | 
 |  | 
 |     case 'scope': | 
 |       this.request_ = this.scopeCommandToJSONRequest_(args); | 
 |       break; | 
 |  | 
 |     case 'disconnect': | 
 |     case 'exit': | 
 |     case 'quit': | 
 |       this.request_ = this.disconnectCommandToJSONRequest_(args); | 
 |       break; | 
 |  | 
 |     case 'up': | 
 |       this.request_ = | 
 |           this.frameCommandToJSONRequest_('' + | 
 |                                           (Debug.State.currentFrame + 1)); | 
 |       break; | 
 |  | 
 |     case 'down': | 
 |     case 'do': | 
 |       this.request_ = | 
 |           this.frameCommandToJSONRequest_('' + | 
 |                                           (Debug.State.currentFrame - 1)); | 
 |       break; | 
 |  | 
 |     case 'set': | 
 |     case 'print': | 
 |     case 'p': | 
 |       this.request_ = this.printCommandToJSONRequest_(args); | 
 |       break; | 
 |  | 
 |     case 'dir': | 
 |       this.request_ = this.dirCommandToJSONRequest_(args); | 
 |       break; | 
 |  | 
 |     case 'references': | 
 |       this.request_ = this.referencesCommandToJSONRequest_(args); | 
 |       break; | 
 |  | 
 |     case 'instances': | 
 |       this.request_ = this.instancesCommandToJSONRequest_(args); | 
 |       break; | 
 |  | 
 |     case 'list': | 
 |     case 'l': | 
 |       this.request_ = this.listCommandToJSONRequest_(args); | 
 |       break; | 
 |     case 'source': | 
 |       this.request_ = this.sourceCommandToJSONRequest_(args); | 
 |       break; | 
 |  | 
 |     case 'scripts': | 
 |     case 'script': | 
 |     case 'scr': | 
 |       this.request_ = this.scriptsCommandToJSONRequest_(args); | 
 |       break; | 
 |  | 
 |     case 'break': | 
 |     case 'b': | 
 |       this.request_ = this.breakCommandToJSONRequest_(args); | 
 |       break; | 
 |  | 
 |     case 'breakpoints': | 
 |     case 'bb': | 
 |       this.request_ = this.breakpointsCommandToJSONRequest_(args); | 
 |       break; | 
 |  | 
 |     case 'clear': | 
 |     case 'delete': | 
 |     case 'd': | 
 |       this.request_ = this.clearCommandToJSONRequest_(args); | 
 |       break; | 
 |  | 
 |     case 'threads': | 
 |       this.request_ = this.threadsCommandToJSONRequest_(args); | 
 |       break; | 
 |  | 
 |     case 'cond': | 
 |       this.request_ = this.changeBreakpointCommandToJSONRequest_(args, 'cond'); | 
 |       break; | 
 |  | 
 |     case 'enable': | 
 |     case 'en': | 
 |       this.request_ = | 
 |           this.changeBreakpointCommandToJSONRequest_(args, 'enable'); | 
 |       break; | 
 |  | 
 |     case 'disable': | 
 |     case 'dis': | 
 |       this.request_ = | 
 |           this.changeBreakpointCommandToJSONRequest_(args, 'disable'); | 
 |       break; | 
 |  | 
 |     case 'ignore': | 
 |       this.request_ = | 
 |           this.changeBreakpointCommandToJSONRequest_(args, 'ignore'); | 
 |       break; | 
 |  | 
 |     case 'info': | 
 |     case 'inf': | 
 |       this.request_ = this.infoCommandToJSONRequest_(args); | 
 |       break; | 
 |  | 
 |     case 'flags': | 
 |       this.request_ = this.v8FlagsToJSONRequest_(args); | 
 |       break; | 
 |  | 
 |     case 'gc': | 
 |       this.request_ = this.gcToJSONRequest_(args); | 
 |       break; | 
 |  | 
 |     case 'trace': | 
 |     case 'tr': | 
 |       // Return undefined to indicate command handled internally (no JSON). | 
 |       this.request_ = void 0; | 
 |       this.traceCommand_(args); | 
 |       break; | 
 |  | 
 |     case 'help': | 
 |     case '?': | 
 |       this.helpCommand_(args); | 
 |       // Return undefined to indicate command handled internally (no JSON). | 
 |       this.request_ = void 0; | 
 |       break; | 
 |  | 
 |     case 'liveobjectlist': | 
 |     case 'lol': | 
 |       if (lol_is_enabled) { | 
 |         this.request_ = this.lolToJSONRequest_(args, is_repeating); | 
 |         break; | 
 |       } | 
 |  | 
 |     default: | 
 |       throw new Error('Unknown command "' + cmd + '"'); | 
 |   } | 
 | } | 
 |  | 
 | DebugRequest.prototype.JSONRequest = function() { | 
 |   return this.request_; | 
 | }; | 
 |  | 
 |  | 
 | function RequestPacket(command) { | 
 |   this.seq = 0; | 
 |   this.type = 'request'; | 
 |   this.command = command; | 
 | } | 
 |  | 
 |  | 
 | RequestPacket.prototype.toJSONProtocol = function() { | 
 |   // Encode the protocol header. | 
 |   var json = '{'; | 
 |   json += '"seq":' + this.seq; | 
 |   json += ',"type":"' + this.type + '"'; | 
 |   if (this.command) { | 
 |     json += ',"command":' + StringToJSON_(this.command); | 
 |   } | 
 |   if (this.arguments) { | 
 |     json += ',"arguments":'; | 
 |     // Encode the arguments part. | 
 |     if (this.arguments.toJSONProtocol) { | 
 |       json += this.arguments.toJSONProtocol(); | 
 |     } else { | 
 |       json += SimpleObjectToJSON_(this.arguments); | 
 |     } | 
 |   } | 
 |   json += '}'; | 
 |   return json; | 
 | }; | 
 |  | 
 |  | 
 | DebugRequest.prototype.createRequest = function(command) { | 
 |   return new RequestPacket(command); | 
 | }; | 
 |  | 
 |  | 
 | // Note: we use detected command repetition as a signal for continuation here. | 
 | DebugRequest.prototype.createLOLRequest = function(command, | 
 |                                                    start_index, | 
 |                                                    lines_to_dump, | 
 |                                                    is_continuation) { | 
 |   if (is_continuation) { | 
 |     start_index = lol_next_dump_index; | 
 |   } | 
 |  | 
 |   if (lines_to_dump) { | 
 |     lines_to_dump = parseInt(lines_to_dump); | 
 |   } else { | 
 |     lines_to_dump = kDefaultLolLinesToPrintAtATime; | 
 |   } | 
 |   if (lines_to_dump > kMaxLolLinesToPrintAtATime) { | 
 |     lines_to_dump = kMaxLolLinesToPrintAtATime; | 
 |   } | 
 |  | 
 |   // Save the next start_index to dump from: | 
 |   lol_next_dump_index = start_index + lines_to_dump; | 
 |  | 
 |   var request = this.createRequest(command); | 
 |   request.arguments = {}; | 
 |   request.arguments.start = start_index; | 
 |   request.arguments.count = lines_to_dump; | 
 |  | 
 |   return request; | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the evaluation command. | 
 | DebugRequest.prototype.makeEvaluateJSONRequest_ = function(expression) { | 
 |   lookup_handle = null; | 
 |  | 
 |   if (lol_is_enabled) { | 
 |     // Check if the expression is a obj id in the form @<obj id>. | 
 |     var obj_id_match = expression.match(/^@([0-9]+)$/); | 
 |     if (obj_id_match) { | 
 |       var obj_id = parseInt(obj_id_match[1]); | 
 |       // Build a dump request. | 
 |       var request = this.createRequest('getobj'); | 
 |       request.arguments = {}; | 
 |       request.arguments.obj_id = obj_id; | 
 |       return request.toJSONProtocol(); | 
 |     } | 
 |   } | 
 |  | 
 |   // Check if the expression is a handle id in the form #<handle>#. | 
 |   var handle_match = expression.match(/^#([0-9]*)#$/); | 
 |   if (handle_match) { | 
 |     // Remember the handle requested in a global variable. | 
 |     lookup_handle = parseInt(handle_match[1]); | 
 |     // Build a lookup request. | 
 |     var request = this.createRequest('lookup'); | 
 |     request.arguments = {}; | 
 |     request.arguments.handles = [ lookup_handle ]; | 
 |     return request.toJSONProtocol(); | 
 |   } else { | 
 |     // Build an evaluate request. | 
 |     var request = this.createRequest('evaluate'); | 
 |     request.arguments = {}; | 
 |     request.arguments.expression = expression; | 
 |     // Request a global evaluation if there is no current frame. | 
 |     if (Debug.State.currentFrame == kNoFrame) { | 
 |       request.arguments.global = true; | 
 |     } | 
 |     return request.toJSONProtocol(); | 
 |   } | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the references/instances command. | 
 | DebugRequest.prototype.makeReferencesJSONRequest_ = function(handle, type) { | 
 |   // Build a references request. | 
 |   var handle_match = handle.match(/^#([0-9]*)#$/); | 
 |   if (handle_match) { | 
 |     var request = this.createRequest('references'); | 
 |     request.arguments = {}; | 
 |     request.arguments.type = type; | 
 |     request.arguments.handle = parseInt(handle_match[1]); | 
 |     return request.toJSONProtocol(); | 
 |   } else { | 
 |     throw new Error('Invalid object id.'); | 
 |   } | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the continue command. | 
 | DebugRequest.prototype.continueCommandToJSONRequest_ = function(args) { | 
 |   var request = this.createRequest('continue'); | 
 |   return request.toJSONProtocol(); | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the step command. | 
 | DebugRequest.prototype.stepCommandToJSONRequest_ = function(args, type) { | 
 |   // Requesting a step is through the continue command with additional | 
 |   // arguments. | 
 |   var request = this.createRequest('continue'); | 
 |   request.arguments = {}; | 
 |  | 
 |   // Process arguments if any. | 
 |  | 
 |   // Only process args if the command is 'step' which is indicated by type being | 
 |   // set to 'in'.  For all other commands, ignore the args. | 
 |   if (args && args.length > 0) { | 
 |     args = args.split(/\s+/g); | 
 |  | 
 |     if (args.length > 2) { | 
 |       throw new Error('Invalid step arguments.'); | 
 |     } | 
 |  | 
 |     if (args.length > 0) { | 
 |       // Check if we have a gdb stype step command.  If so, the 1st arg would | 
 |       // be the step count.  If it's not a number, then assume that we're | 
 |       // parsing for the legacy v8 step command. | 
 |       var stepcount = Number(args[0]); | 
 |       if (stepcount == Number.NaN) { | 
 |         // No step count at arg 1.  Process as legacy d8 step command: | 
 |         if (args.length == 2) { | 
 |           var stepcount = parseInt(args[1]); | 
 |           if (isNaN(stepcount) || stepcount <= 0) { | 
 |             throw new Error('Invalid step count argument "' + args[0] + '".'); | 
 |           } | 
 |           request.arguments.stepcount = stepcount; | 
 |         } | 
 |  | 
 |         // Get the step action. | 
 |         switch (args[0]) { | 
 |           case 'in': | 
 |           case 'i': | 
 |             request.arguments.stepaction = 'in'; | 
 |             break; | 
 |  | 
 |           case 'min': | 
 |           case 'm': | 
 |             request.arguments.stepaction = 'min'; | 
 |             break; | 
 |  | 
 |           case 'next': | 
 |           case 'n': | 
 |             request.arguments.stepaction = 'next'; | 
 |             break; | 
 |  | 
 |           case 'out': | 
 |           case 'o': | 
 |             request.arguments.stepaction = 'out'; | 
 |             break; | 
 |  | 
 |           default: | 
 |             throw new Error('Invalid step argument "' + args[0] + '".'); | 
 |         } | 
 |  | 
 |       } else { | 
 |         // gdb style step commands: | 
 |         request.arguments.stepaction = type; | 
 |         request.arguments.stepcount = stepcount; | 
 |       } | 
 |     } | 
 |   } else { | 
 |     // Default is step of the specified type. | 
 |     request.arguments.stepaction = type; | 
 |   } | 
 |  | 
 |   return request.toJSONProtocol(); | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the backtrace command. | 
 | DebugRequest.prototype.backtraceCommandToJSONRequest_ = function(args) { | 
 |   // Build a backtrace request from the text command. | 
 |   var request = this.createRequest('backtrace'); | 
 |  | 
 |   // Default is to show top 10 frames. | 
 |   request.arguments = {}; | 
 |   request.arguments.fromFrame = 0; | 
 |   request.arguments.toFrame = 10; | 
 |  | 
 |   args = args.split(/\s*[ ]+\s*/g); | 
 |   if (args.length == 1 && args[0].length > 0) { | 
 |     var frameCount = parseInt(args[0]); | 
 |     if (frameCount > 0) { | 
 |       // Show top frames. | 
 |       request.arguments.fromFrame = 0; | 
 |       request.arguments.toFrame = frameCount; | 
 |     } else { | 
 |       // Show bottom frames. | 
 |       request.arguments.fromFrame = 0; | 
 |       request.arguments.toFrame = -frameCount; | 
 |       request.arguments.bottom = true; | 
 |     } | 
 |   } else if (args.length == 2) { | 
 |     var fromFrame = parseInt(args[0]); | 
 |     var toFrame = parseInt(args[1]); | 
 |     if (isNaN(fromFrame) || fromFrame < 0) { | 
 |       throw new Error('Invalid start frame argument "' + args[0] + '".'); | 
 |     } | 
 |     if (isNaN(toFrame) || toFrame < 0) { | 
 |       throw new Error('Invalid end frame argument "' + args[1] + '".'); | 
 |     } | 
 |     if (fromFrame > toFrame) { | 
 |       throw new Error('Invalid arguments start frame cannot be larger ' + | 
 |                       'than end frame.'); | 
 |     } | 
 |     // Show frame range. | 
 |     request.arguments.fromFrame = fromFrame; | 
 |     request.arguments.toFrame = toFrame + 1; | 
 |   } else if (args.length > 2) { | 
 |     throw new Error('Invalid backtrace arguments.'); | 
 |   } | 
 |  | 
 |   return request.toJSONProtocol(); | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the frame command. | 
 | DebugRequest.prototype.frameCommandToJSONRequest_ = function(args) { | 
 |   // Build a frame request from the text command. | 
 |   var request = this.createRequest('frame'); | 
 |   args = args.split(/\s*[ ]+\s*/g); | 
 |   if (args.length > 0 && args[0].length > 0) { | 
 |     request.arguments = {}; | 
 |     request.arguments.number = args[0]; | 
 |   } | 
 |   return request.toJSONProtocol(); | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the scopes command. | 
 | DebugRequest.prototype.scopesCommandToJSONRequest_ = function(args) { | 
 |   // Build a scopes request from the text command. | 
 |   var request = this.createRequest('scopes'); | 
 |   return request.toJSONProtocol(); | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the scope command. | 
 | DebugRequest.prototype.scopeCommandToJSONRequest_ = function(args) { | 
 |   // Build a scope request from the text command. | 
 |   var request = this.createRequest('scope'); | 
 |   args = args.split(/\s*[ ]+\s*/g); | 
 |   if (args.length > 0 && args[0].length > 0) { | 
 |     request.arguments = {}; | 
 |     request.arguments.number = args[0]; | 
 |   } | 
 |   return request.toJSONProtocol(); | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the print command. | 
 | DebugRequest.prototype.printCommandToJSONRequest_ = function(args) { | 
 |   // Build an evaluate request from the text command. | 
 |   if (args.length == 0) { | 
 |     throw new Error('Missing expression.'); | 
 |   } | 
 |   return this.makeEvaluateJSONRequest_(args); | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the dir command. | 
 | DebugRequest.prototype.dirCommandToJSONRequest_ = function(args) { | 
 |   // Build an evaluate request from the text command. | 
 |   if (args.length == 0) { | 
 |     throw new Error('Missing expression.'); | 
 |   } | 
 |   return this.makeEvaluateJSONRequest_(args); | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the references command. | 
 | DebugRequest.prototype.referencesCommandToJSONRequest_ = function(args) { | 
 |   // Build an evaluate request from the text command. | 
 |   if (args.length == 0) { | 
 |     throw new Error('Missing object id.'); | 
 |   } | 
 |  | 
 |   return this.makeReferencesJSONRequest_(args, 'referencedBy'); | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the instances command. | 
 | DebugRequest.prototype.instancesCommandToJSONRequest_ = function(args) { | 
 |   // Build an evaluate request from the text command. | 
 |   if (args.length == 0) { | 
 |     throw new Error('Missing object id.'); | 
 |   } | 
 |  | 
 |   // Build a references request. | 
 |   return this.makeReferencesJSONRequest_(args, 'constructedBy'); | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the list command. | 
 | DebugRequest.prototype.listCommandToJSONRequest_ = function(args) { | 
 |  | 
 |   // Default is ten lines starting five lines before the current location. | 
 |   if (Debug.State.displaySourceEndLine == -1) { | 
 |     // If we list forwards, we will start listing after the last source end | 
 |     // line.  Set it to start from 5 lines before the current location. | 
 |     Debug.State.displaySourceEndLine = Debug.State.currentSourceLine - 5; | 
 |     // If we list backwards, we will start listing backwards from the last | 
 |     // source start line.  Set it to start from 1 lines before the current | 
 |     // location. | 
 |     Debug.State.displaySourceStartLine = Debug.State.currentSourceLine + 1; | 
 |   } | 
 |  | 
 |   var from = Debug.State.displaySourceEndLine + 1; | 
 |   var lines = 10; | 
 |  | 
 |   // Parse the arguments. | 
 |   args = args.split(/\s*,\s*/g); | 
 |   if (args == '') { | 
 |   } else if ((args.length == 1) && (args[0] == '-')) { | 
 |     from = Debug.State.displaySourceStartLine - lines; | 
 |   } else if (args.length == 2) { | 
 |     from = parseInt(args[0]); | 
 |     lines = parseInt(args[1]) - from + 1; // inclusive of the ending line. | 
 |   } else { | 
 |     throw new Error('Invalid list arguments.'); | 
 |   } | 
 |   Debug.State.displaySourceStartLine = from; | 
 |   Debug.State.displaySourceEndLine = from + lines - 1; | 
 |   var sourceArgs = '' + from + ' ' + lines; | 
 |   return this.sourceCommandToJSONRequest_(sourceArgs); | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the source command. | 
 | DebugRequest.prototype.sourceCommandToJSONRequest_ = function(args) { | 
 |   // Build a evaluate request from the text command. | 
 |   var request = this.createRequest('source'); | 
 |  | 
 |   // Default is ten lines starting five lines before the current location. | 
 |   var from = Debug.State.currentSourceLine - 5; | 
 |   var lines = 10; | 
 |  | 
 |   // Parse the arguments. | 
 |   args = args.split(/\s*[ ]+\s*/g); | 
 |   if (args.length > 1 && args[0].length > 0 && args[1].length > 0) { | 
 |     from = parseInt(args[0]) - 1; | 
 |     lines = parseInt(args[1]); | 
 |   } else if (args.length > 0 && args[0].length > 0) { | 
 |     from = parseInt(args[0]) - 1; | 
 |   } | 
 |  | 
 |   if (from < 0) from = 0; | 
 |   if (lines < 0) lines = 10; | 
 |  | 
 |   // Request source arround current source location. | 
 |   request.arguments = {}; | 
 |   request.arguments.fromLine = from; | 
 |   request.arguments.toLine = from + lines; | 
 |  | 
 |   return request.toJSONProtocol(); | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the scripts command. | 
 | DebugRequest.prototype.scriptsCommandToJSONRequest_ = function(args) { | 
 |   // Build a evaluate request from the text command. | 
 |   var request = this.createRequest('scripts'); | 
 |  | 
 |   // Process arguments if any. | 
 |   if (args && args.length > 0) { | 
 |     args = args.split(/\s*[ ]+\s*/g); | 
 |  | 
 |     if (args.length > 1) { | 
 |       throw new Error('Invalid scripts arguments.'); | 
 |     } | 
 |  | 
 |     request.arguments = {}; | 
 |     switch (args[0]) { | 
 |       case 'natives': | 
 |         request.arguments.types = ScriptTypeFlag(Debug.ScriptType.Native); | 
 |         break; | 
 |  | 
 |       case 'extensions': | 
 |         request.arguments.types = ScriptTypeFlag(Debug.ScriptType.Extension); | 
 |         break; | 
 |  | 
 |       case 'all': | 
 |         request.arguments.types = | 
 |             ScriptTypeFlag(Debug.ScriptType.Normal) | | 
 |             ScriptTypeFlag(Debug.ScriptType.Native) | | 
 |             ScriptTypeFlag(Debug.ScriptType.Extension); | 
 |         break; | 
 |  | 
 |       default: | 
 |         // If the arg is not one of the know one aboves, then it must be a | 
 |         // filter used for filtering the results: | 
 |         request.arguments.filter = args[0]; | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   return request.toJSONProtocol(); | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the break command. | 
 | DebugRequest.prototype.breakCommandToJSONRequest_ = function(args) { | 
 |   // Build a evaluate request from the text command. | 
 |   // Process arguments if any. | 
 |   if (args && args.length > 0) { | 
 |     var target = args; | 
 |     var type = 'function'; | 
 |     var line; | 
 |     var column; | 
 |     var condition; | 
 |     var pos; | 
 |  | 
 |     var request = this.createRequest('setbreakpoint'); | 
 |  | 
 |     // Break the args into target spec and condition if appropriate. | 
 |  | 
 |     // Check for breakpoint condition. | 
 |     pos = args.indexOf(' '); | 
 |     if (pos > 0) { | 
 |       target = args.substring(0, pos); | 
 |       condition = args.substring(pos + 1, args.length); | 
 |     } | 
 |  | 
 |     // Check for script breakpoint (name:line[:column]). If no ':' in break | 
 |     // specification it is considered a function break point. | 
 |     pos = target.indexOf(':'); | 
 |     if (pos > 0) { | 
 |       var tmp = target.substring(pos + 1, target.length); | 
 |       target = target.substring(0, pos); | 
 |       if (target[0] == '/' && target[target.length - 1] == '/') { | 
 |         type = 'scriptRegExp'; | 
 |         target = target.substring(1, target.length - 1); | 
 |       } else { | 
 |         type = 'script'; | 
 |       } | 
 |  | 
 |       // Check for both line and column. | 
 |       pos = tmp.indexOf(':'); | 
 |       if (pos > 0) { | 
 |         column = parseInt(tmp.substring(pos + 1, tmp.length)) - 1; | 
 |         line = parseInt(tmp.substring(0, pos)) - 1; | 
 |       } else { | 
 |         line = parseInt(tmp) - 1; | 
 |       } | 
 |     } else if (target[0] == '#' && target[target.length - 1] == '#') { | 
 |       type = 'handle'; | 
 |       target = target.substring(1, target.length - 1); | 
 |     } else { | 
 |       type = 'function'; | 
 |     } | 
 |  | 
 |     request.arguments = {}; | 
 |     request.arguments.type = type; | 
 |     request.arguments.target = target; | 
 |     request.arguments.line = line; | 
 |     request.arguments.column = column; | 
 |     request.arguments.condition = condition; | 
 |   } else { | 
 |     var request = this.createRequest('suspend'); | 
 |   } | 
 |  | 
 |   return request.toJSONProtocol(); | 
 | }; | 
 |  | 
 |  | 
 | DebugRequest.prototype.breakpointsCommandToJSONRequest_ = function(args) { | 
 |   if (args && args.length > 0) { | 
 |     throw new Error('Unexpected arguments.'); | 
 |   } | 
 |   var request = this.createRequest('listbreakpoints'); | 
 |   return request.toJSONProtocol(); | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the clear command. | 
 | DebugRequest.prototype.clearCommandToJSONRequest_ = function(args) { | 
 |   // Build a evaluate request from the text command. | 
 |   var request = this.createRequest('clearbreakpoint'); | 
 |  | 
 |   // Process arguments if any. | 
 |   if (args && args.length > 0) { | 
 |     request.arguments = {}; | 
 |     request.arguments.breakpoint = parseInt(args); | 
 |   } else { | 
 |     throw new Error('Invalid break arguments.'); | 
 |   } | 
 |  | 
 |   return request.toJSONProtocol(); | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the change breakpoint command. | 
 | DebugRequest.prototype.changeBreakpointCommandToJSONRequest_ = | 
 |     function(args, command) { | 
 |  | 
 |   var request; | 
 |  | 
 |   // Check for exception breaks first: | 
 |   //   en[able] exc[eptions] [all|unc[aught]] | 
 |   //   en[able] [all|unc[aught]] exc[eptions] | 
 |   //   dis[able] exc[eptions] [all|unc[aught]] | 
 |   //   dis[able] [all|unc[aught]] exc[eptions] | 
 |   if ((command == 'enable' || command == 'disable') && | 
 |       args && args.length > 1) { | 
 |     var nextPos = args.indexOf(' '); | 
 |     var arg1 = (nextPos > 0) ? args.substring(0, nextPos) : args; | 
 |     var excType = null; | 
 |  | 
 |     // Check for: | 
 |     //   en[able] exc[eptions] [all|unc[aught]] | 
 |     //   dis[able] exc[eptions] [all|unc[aught]] | 
 |     if (arg1 == 'exc' || arg1 == 'exception' || arg1 == 'exceptions') { | 
 |  | 
 |       var arg2 = (nextPos > 0) ? | 
 |           args.substring(nextPos + 1, args.length) : 'all'; | 
 |       if (!arg2) { | 
 |         arg2 = 'all'; // if unspecified, set for all. | 
 |       } if (arg2 == 'unc') { // check for short cut. | 
 |         arg2 = 'uncaught'; | 
 |       } | 
 |       excType = arg2; | 
 |  | 
 |     // Check for: | 
 |     //   en[able] [all|unc[aught]] exc[eptions] | 
 |     //   dis[able] [all|unc[aught]] exc[eptions] | 
 |     } else if (arg1 == 'all' || arg1 == 'unc' || arg1 == 'uncaught') { | 
 |  | 
 |       var arg2 = (nextPos > 0) ? | 
 |           args.substring(nextPos + 1, args.length) : null; | 
 |       if (arg2 == 'exc' || arg1 == 'exception' || arg1 == 'exceptions') { | 
 |         excType = arg1; | 
 |         if (excType == 'unc') { | 
 |           excType = 'uncaught'; | 
 |         } | 
 |       } | 
 |     } | 
 |  | 
 |     // If we matched one of the command formats, then excType will be non-null: | 
 |     if (excType) { | 
 |       // Build a evaluate request from the text command. | 
 |       request = this.createRequest('setexceptionbreak'); | 
 |  | 
 |       request.arguments = {}; | 
 |       request.arguments.type = excType; | 
 |       request.arguments.enabled = (command == 'enable'); | 
 |  | 
 |       return request.toJSONProtocol(); | 
 |     } | 
 |   } | 
 |  | 
 |   // Build a evaluate request from the text command. | 
 |   request = this.createRequest('changebreakpoint'); | 
 |  | 
 |   // Process arguments if any. | 
 |   if (args && args.length > 0) { | 
 |     request.arguments = {}; | 
 |     var pos = args.indexOf(' '); | 
 |     var breakpointArg = args; | 
 |     var otherArgs; | 
 |     if (pos > 0) { | 
 |       breakpointArg = args.substring(0, pos); | 
 |       otherArgs = args.substring(pos + 1, args.length); | 
 |     } | 
 |  | 
 |     request.arguments.breakpoint = parseInt(breakpointArg); | 
 |  | 
 |     switch(command) { | 
 |       case 'cond': | 
 |         request.arguments.condition = otherArgs ? otherArgs : null; | 
 |         break; | 
 |       case 'enable': | 
 |         request.arguments.enabled = true; | 
 |         break; | 
 |       case 'disable': | 
 |         request.arguments.enabled = false; | 
 |         break; | 
 |       case 'ignore': | 
 |         request.arguments.ignoreCount = parseInt(otherArgs); | 
 |         break; | 
 |       default: | 
 |         throw new Error('Invalid arguments.'); | 
 |     } | 
 |   } else { | 
 |     throw new Error('Invalid arguments.'); | 
 |   } | 
 |  | 
 |   return request.toJSONProtocol(); | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the disconnect command. | 
 | DebugRequest.prototype.disconnectCommandToJSONRequest_ = function(args) { | 
 |   var request; | 
 |   request = this.createRequest('disconnect'); | 
 |   return request.toJSONProtocol(); | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the info command. | 
 | DebugRequest.prototype.infoCommandToJSONRequest_ = function(args) { | 
 |   var request; | 
 |   if (args && (args == 'break' || args == 'br')) { | 
 |     // Build a evaluate request from the text command. | 
 |     request = this.createRequest('listbreakpoints'); | 
 |     last_cmd = 'info break'; | 
 |   } else if (args && (args == 'locals' || args == 'lo')) { | 
 |     // Build a evaluate request from the text command. | 
 |     request = this.createRequest('frame'); | 
 |     last_cmd = 'info locals'; | 
 |   } else if (args && (args == 'args' || args == 'ar')) { | 
 |     // Build a evaluate request from the text command. | 
 |     request = this.createRequest('frame'); | 
 |     last_cmd = 'info args'; | 
 |   } else if (lol_is_enabled && | 
 |              args && (args == 'liveobjectlist' || args == 'lol')) { | 
 |     // Build a evaluate request from the text command. | 
 |     return this.liveObjectListToJSONRequest_(null); | 
 |   } else { | 
 |     throw new Error('Invalid info arguments.'); | 
 |   } | 
 |  | 
 |   return request.toJSONProtocol(); | 
 | }; | 
 |  | 
 |  | 
 | DebugRequest.prototype.v8FlagsToJSONRequest_ = function(args) { | 
 |   var request; | 
 |   request = this.createRequest('v8flags'); | 
 |   request.arguments = {}; | 
 |   request.arguments.flags = args; | 
 |   return request.toJSONProtocol(); | 
 | }; | 
 |  | 
 |  | 
 | DebugRequest.prototype.gcToJSONRequest_ = function(args) { | 
 |   var request; | 
 |   if (!args) { | 
 |     args = 'all'; | 
 |   } | 
 |   var args = args.split(/\s+/g); | 
 |   var cmd = args[0]; | 
 |  | 
 |   switch(cmd) { | 
 |     case 'all': | 
 |     case 'quick': | 
 |     case 'full': | 
 |     case 'young': | 
 |     case 'old': | 
 |     case 'compact': | 
 |     case 'sweep': | 
 |     case 'scavenge': { | 
 |       if (cmd == 'young') { cmd = 'quick'; } | 
 |       else if (cmd == 'old') { cmd = 'full'; } | 
 |  | 
 |       request = this.createRequest('gc'); | 
 |       request.arguments = {}; | 
 |       request.arguments.type = cmd; | 
 |       break; | 
 |     } | 
 |       // Else fall thru to the default case below to report the error. | 
 |     default: | 
 |       throw new Error('Missing arguments after ' + cmd + '.'); | 
 |   } | 
 |   return request.toJSONProtocol(); | 
 | }; | 
 |  | 
 |  | 
 | // Args: [v[erbose]] [<N>] [i[ndex] <i>] [t[ype] <type>] [sp[ace] <space>] | 
 | DebugRequest.prototype.lolMakeListRequest = | 
 |     function(cmd, args, first_arg_index, is_repeating) { | 
 |  | 
 |   var request; | 
 |   var start_index = 0; | 
 |   var dump_limit = void 0; | 
 |   var type_filter = void 0; | 
 |   var space_filter = void 0; | 
 |   var prop_filter = void 0; | 
 |   var is_verbose = false; | 
 |   var i; | 
 |  | 
 |   for (i = first_arg_index; i < args.length; i++) { | 
 |     var arg = args[i]; | 
 |     // Check for [v[erbose]]: | 
 |     if (arg === 'verbose' || arg === 'v') { | 
 |       // Nothing to do.  This is already implied by args.length > 3. | 
 |       is_verbose = true; | 
 |  | 
 |     // Check for [<N>]: | 
 |     } else if (arg.match(/^[0-9]+$/)) { | 
 |       dump_limit = arg; | 
 |       is_verbose = true; | 
 |  | 
 |     // Check for i[ndex] <i>: | 
 |     } else if (arg === 'index' || arg === 'i') { | 
 |       i++; | 
 |       if (args.length < i) { | 
 |         throw new Error('Missing index after ' + arg + '.'); | 
 |       } | 
 |       start_index = parseInt(args[i]); | 
 |       // The user input start index starts at 1: | 
 |       if (start_index <= 0) { | 
 |         throw new Error('Invalid index ' + args[i] + '.'); | 
 |       } | 
 |       start_index -= 1; | 
 |       is_verbose = true; | 
 |  | 
 |     // Check for t[ype] <type>: | 
 |     } else if (arg === 'type' || arg === 't') { | 
 |       i++; | 
 |       if (args.length < i) { | 
 |         throw new Error('Missing type after ' + arg + '.'); | 
 |       } | 
 |       type_filter = args[i]; | 
 |  | 
 |     // Check for space <heap space name>: | 
 |     } else if (arg === 'space' || arg === 'sp') { | 
 |       i++; | 
 |       if (args.length < i) { | 
 |         throw new Error('Missing space name after ' + arg + '.'); | 
 |       } | 
 |       space_filter = args[i]; | 
 |  | 
 |     // Check for property <prop name>: | 
 |     } else if (arg === 'property' || arg === 'prop') { | 
 |       i++; | 
 |       if (args.length < i) { | 
 |         throw new Error('Missing property name after ' + arg + '.'); | 
 |       } | 
 |       prop_filter = args[i]; | 
 |  | 
 |     } else { | 
 |       throw new Error('Unknown args at ' + arg + '.'); | 
 |     } | 
 |   } | 
 |  | 
 |   // Build the verbose request: | 
 |   if (is_verbose) { | 
 |     request = this.createLOLRequest('lol-'+cmd, | 
 |                                     start_index, | 
 |                                     dump_limit, | 
 |                                     is_repeating); | 
 |     request.arguments.verbose = true; | 
 |   } else { | 
 |     request = this.createRequest('lol-'+cmd); | 
 |     request.arguments = {}; | 
 |   } | 
 |  | 
 |   request.arguments.filter = {}; | 
 |   if (type_filter) { | 
 |     request.arguments.filter.type = type_filter; | 
 |   } | 
 |   if (space_filter) { | 
 |     request.arguments.filter.space = space_filter; | 
 |   } | 
 |   if (prop_filter) { | 
 |     request.arguments.filter.prop = prop_filter; | 
 |   } | 
 |  | 
 |   return request; | 
 | }; | 
 |  | 
 |  | 
 | function extractObjId(args) { | 
 |   var id = args; | 
 |   id = id.match(/^@([0-9]+)$/); | 
 |   if (id) { | 
 |     id = id[1]; | 
 |   } else { | 
 |     throw new Error('Invalid obj id ' + args + '.'); | 
 |   } | 
 |   return parseInt(id); | 
 | } | 
 |  | 
 |  | 
 | DebugRequest.prototype.lolToJSONRequest_ = function(args, is_repeating) { | 
 |   var request; | 
 |   // Use default command if one is not specified: | 
 |   if (!args) { | 
 |     args = 'info'; | 
 |   } | 
 |  | 
 |   var orig_args = args; | 
 |   var first_arg_index; | 
 |  | 
 |   var arg, i; | 
 |   var args = args.split(/\s+/g); | 
 |   var cmd = args[0]; | 
 |   var id; | 
 |  | 
 |   // Command: <id> [v[erbose]] ... | 
 |   if (cmd.match(/^[0-9]+$/)) { | 
 |     // Convert to the padded list command: | 
 |     // Command: l[ist] <dummy> <id> [v[erbose]] ... | 
 |  | 
 |     // Insert the implicit 'list' in front and process as normal: | 
 |     cmd = 'list'; | 
 |     args.unshift(cmd); | 
 |   } | 
 |  | 
 |   switch(cmd) { | 
 |     // Command: c[apture] | 
 |     case 'capture': | 
 |     case 'c': | 
 |       request = this.createRequest('lol-capture'); | 
 |       break; | 
 |  | 
 |     // Command: clear|d[elete] <id>|all | 
 |     case 'clear': | 
 |     case 'delete': | 
 |     case 'del': { | 
 |       if (args.length < 2) { | 
 |         throw new Error('Missing argument after ' + cmd + '.'); | 
 |       } else if (args.length > 2) { | 
 |         throw new Error('Too many arguments after ' + cmd + '.'); | 
 |       } | 
 |       id = args[1]; | 
 |       if (id.match(/^[0-9]+$/)) { | 
 |         // Delete a specific lol record: | 
 |         request = this.createRequest('lol-delete'); | 
 |         request.arguments = {}; | 
 |         request.arguments.id = parseInt(id); | 
 |       } else if (id === 'all') { | 
 |         // Delete all: | 
 |         request = this.createRequest('lol-reset'); | 
 |       } else { | 
 |         throw new Error('Invalid argument after ' + cmd + '.'); | 
 |       } | 
 |       break; | 
 |     } | 
 |  | 
 |     // Command: diff <id1> <id2> [<dump options>] | 
 |     case 'diff': | 
 |       first_arg_index = 3; | 
 |  | 
 |     // Command: list <dummy> <id> [<dump options>] | 
 |     case 'list': | 
 |  | 
 |     // Command: ret[ainers] <obj id> [<dump options>] | 
 |     case 'retainers': | 
 |     case 'ret': | 
 |     case 'retaining-paths': | 
 |     case 'rp': { | 
 |       if (cmd === 'ret') cmd = 'retainers'; | 
 |       else if (cmd === 'rp') cmd = 'retaining-paths'; | 
 |  | 
 |       if (!first_arg_index) first_arg_index = 2; | 
 |  | 
 |       if (args.length < first_arg_index) { | 
 |         throw new Error('Too few arguments after ' + cmd + '.'); | 
 |       } | 
 |  | 
 |       var request_cmd = (cmd === 'list') ? 'diff':cmd; | 
 |       request = this.lolMakeListRequest(request_cmd, | 
 |                                         args, | 
 |                                         first_arg_index, | 
 |                                         is_repeating); | 
 |  | 
 |       if (cmd === 'diff') { | 
 |         request.arguments.id1 = parseInt(args[1]); | 
 |         request.arguments.id2 = parseInt(args[2]); | 
 |       } else if (cmd == 'list') { | 
 |         request.arguments.id1 = 0; | 
 |         request.arguments.id2 = parseInt(args[1]); | 
 |       } else { | 
 |         request.arguments.id = extractObjId(args[1]); | 
 |       } | 
 |       break; | 
 |     } | 
 |  | 
 |     // Command: getid | 
 |     case 'getid': { | 
 |       request = this.createRequest('lol-getid'); | 
 |       request.arguments = {}; | 
 |       request.arguments.address = args[1]; | 
 |       break; | 
 |     } | 
 |  | 
 |     // Command: inf[o] [<N>] | 
 |     case 'info': | 
 |     case 'inf': { | 
 |       if (args.length > 2) { | 
 |         throw new Error('Too many arguments after ' + cmd + '.'); | 
 |       } | 
 |       // Built the info request: | 
 |       request = this.createLOLRequest('lol-info', 0, args[1], is_repeating); | 
 |       break; | 
 |     } | 
 |  | 
 |     // Command: path <obj id 1> <obj id 2> | 
 |     case 'path': { | 
 |       request = this.createRequest('lol-path'); | 
 |       request.arguments = {}; | 
 |       if (args.length > 2) { | 
 |         request.arguments.id1 = extractObjId(args[1]); | 
 |         request.arguments.id2 = extractObjId(args[2]); | 
 |       } else { | 
 |         request.arguments.id1 = 0; | 
 |         request.arguments.id2 = extractObjId(args[1]); | 
 |       } | 
 |       break; | 
 |     } | 
 |  | 
 |     // Command: print | 
 |     case 'print': { | 
 |       request = this.createRequest('lol-print'); | 
 |       request.arguments = {}; | 
 |       request.arguments.id = extractObjId(args[1]); | 
 |       break; | 
 |     } | 
 |  | 
 |     // Command: reset | 
 |     case 'reset': { | 
 |       request = this.createRequest('lol-reset'); | 
 |       break; | 
 |     } | 
 |  | 
 |     default: | 
 |       throw new Error('Invalid arguments.'); | 
 |   } | 
 |   return request.toJSONProtocol(); | 
 | }; | 
 |  | 
 |  | 
 | // Create a JSON request for the threads command. | 
 | DebugRequest.prototype.threadsCommandToJSONRequest_ = function(args) { | 
 |   // Build a threads request from the text command. | 
 |   var request = this.createRequest('threads'); | 
 |   return request.toJSONProtocol(); | 
 | }; | 
 |  | 
 |  | 
 | // Handle the trace command. | 
 | DebugRequest.prototype.traceCommand_ = function(args) { | 
 |   // Process arguments. | 
 |   if (args && args.length > 0) { | 
 |     if (args == 'compile') { | 
 |       trace_compile = !trace_compile; | 
 |       print('Tracing of compiled scripts ' + (trace_compile ? 'on' : 'off')); | 
 |     } else if (args === 'debug json' || args === 'json' || args === 'packets') { | 
 |       trace_debug_json = !trace_debug_json; | 
 |       print('Tracing of debug json packets ' + | 
 |             (trace_debug_json ? 'on' : 'off')); | 
 |     } else { | 
 |       throw new Error('Invalid trace arguments.'); | 
 |     } | 
 |   } else { | 
 |     throw new Error('Invalid trace arguments.'); | 
 |   } | 
 | }; | 
 |  | 
 | // Handle the help command. | 
 | DebugRequest.prototype.helpCommand_ = function(args) { | 
 |   // Help os quite simple. | 
 |   if (args && args.length > 0) { | 
 |     print('warning: arguments to \'help\' are ignored'); | 
 |   } | 
 |  | 
 |   print('Note: <> denotes symbollic values to be replaced with real values.'); | 
 |   print('Note: [] denotes optional parts of commands, or optional options / arguments.'); | 
 |   print('      e.g. d[elete] - you get the same command if you type d or delete.'); | 
 |   print(''); | 
 |   print('[break] - break as soon as possible'); | 
 |   print('b[reak] location [condition]'); | 
 |   print('        - break on named function: location is a function name'); | 
 |   print('        - break on function: location is #<id>#'); | 
 |   print('        - break on script position: location is name:line[:column]'); | 
 |   print(''); | 
 |   print('clear <breakpoint #>       - deletes the specified user defined breakpoint'); | 
 |   print('d[elete]  <breakpoint #>   - deletes the specified user defined breakpoint'); | 
 |   print('dis[able] <breakpoint #>   - disables the specified user defined breakpoint'); | 
 |   print('dis[able] exc[eptions] [[all] | unc[aught]]'); | 
 |   print('                           - disables breaking on exceptions'); | 
 |   print('en[able]  <breakpoint #>   - enables the specified user defined breakpoint'); | 
 |   print('en[able]  exc[eptions] [[all] | unc[aught]]'); | 
 |   print('                           - enables breaking on exceptions'); | 
 |   print(''); | 
 |   print('b[ack]t[race] [n] | [-n] | [from to]'); | 
 |   print('                           - prints the stack back trace'); | 
 |   print('f[rame]                    - prints info about the current frame context'); | 
 |   print('f[rame] <frame #>          - set context to specified frame #'); | 
 |   print('scopes'); | 
 |   print('scope <scope #>'); | 
 |   print(''); | 
 |   print('up                         - set context to caller of current frame'); | 
 |   print('do[wn]                     - set context to callee of current frame'); | 
 |   print('inf[o] br[eak]             - prints info about breakpoints in use'); | 
 |   print('inf[o] ar[gs]              - prints info about arguments of the current function'); | 
 |   print('inf[o] lo[cals]            - prints info about locals in the current function'); | 
 |   print('inf[o] liveobjectlist|lol  - same as \'lol info\''); | 
 |   print(''); | 
 |   print('step [in | next | out| min [step count]]'); | 
 |   print('c[ontinue]                 - continue executing after a breakpoint'); | 
 |   print('s[tep]   [<N>]             - step into the next N callees (default N is 1)'); | 
 |   print('s[tep]i  [<N>]             - step into the next N callees (default N is 1)'); | 
 |   print('n[ext]   [<N>]             - step over the next N callees (default N is 1)'); | 
 |   print('fin[ish] [<N>]             - step out of N frames (default N is 1)'); | 
 |   print(''); | 
 |   print('p[rint] <expression>       - prints the result of the specified expression'); | 
 |   print('dir <expression>           - prints the object structure of the result'); | 
 |   print('set <var> = <expression>   - executes the specified statement'); | 
 |   print(''); | 
 |   print('l[ist]                     - list the source code around for the current pc'); | 
 |   print('l[ist] [- | <start>,<end>] - list the specified range of source code'); | 
 |   print('source [from line [num lines]]'); | 
 |   print('scr[ipts] [native|extensions|all]'); | 
 |   print('scr[ipts] [<filter text>]  - list scripts with the specified text in its description'); | 
 |   print(''); | 
 |   print('gc                         - runs the garbage collector'); | 
 |   print(''); | 
 |  | 
 |   if (lol_is_enabled) { | 
 |     print('liveobjectlist|lol <command> - live object list tracking.'); | 
 |     print('  where <command> can be:'); | 
 |     print('  c[apture]               - captures a LOL list.'); | 
 |     print('  clear|del[ete] <id>|all - clears LOL of id <id>.'); | 
 |     print('                            If \'all\' is unspecified instead, will clear all.'); | 
 |     print('  diff <id1> <id2> [<dump options>]'); | 
 |     print('                          - prints the diff between LOLs id1 and id2.'); | 
 |     print('                          - also see <dump options> below.'); | 
 |     print('  getid <address>         - gets the obj id for the specified address if available.'); | 
 |     print('                            The address must be in hex form prefixed with 0x.'); | 
 |     print('  inf[o] [<N>]            - lists summary info of all LOL lists.'); | 
 |     print('                            If N is specified, will print N items at a time.'); | 
 |     print('  [l[ist]] <id> [<dump options>]'); | 
 |     print('                          - prints the listing of objects in LOL id.'); | 
 |     print('                          - also see <dump options> below.'); | 
 |     print('  reset                   - clears all LOL lists.'); | 
 |     print('  ret[ainers] <id> [<dump options>]'); | 
 |     print('                          - prints the list of retainers of obj id.'); | 
 |     print('                          - also see <dump options> below.'); | 
 |     print('  path <id1> <id2>        - prints the retaining path from obj id1 to id2.'); | 
 |     print('                            If only one id is specified, will print the path from'); | 
 |     print('                            roots to the specified object if available.'); | 
 |     print('  print <id>              - prints the obj for the specified obj id if available.'); | 
 |     print(''); | 
 |     print('  <dump options> includes:'); | 
 |     print('     [v[erbose]]            - do verbose dump.'); | 
 |     print('     [<N>]                  - dump N items at a time.  Implies verbose dump.'); | 
 |     print('                             If unspecified, N will default to '+ | 
 |           kDefaultLolLinesToPrintAtATime+'.  Max N is '+ | 
 |           kMaxLolLinesToPrintAtATime+'.'); | 
 |     print('     [i[ndex] <i>]          - start dump from index i.  Implies verbose dump.'); | 
 |     print('     [t[ype] <type>]        - filter by type.'); | 
 |     print('     [sp[ace] <space name>] - filter by heap space where <space name> is one of'); | 
 |     print('                              { cell, code, lo, map, new, old-data, old-pointer }.'); | 
 |     print(''); | 
 |     print('     If the verbose option, or an option that implies a verbose dump'); | 
 |     print('     is specified, then a verbose dump will requested.  Else, a summary dump'); | 
 |     print('     will be requested.'); | 
 |     print(''); | 
 |   } | 
 |  | 
 |   print('trace compile'); | 
 |   // hidden command: trace debug json - toggles tracing of debug json packets | 
 |   print(''); | 
 |   print('disconnect|exit|quit       - disconnects and quits the debugger'); | 
 |   print('help                       - prints this help information'); | 
 | }; | 
 |  | 
 |  | 
 | function formatHandleReference_(value) { | 
 |   if (value.handle() >= 0) { | 
 |     return '#' + value.handle() + '#'; | 
 |   } else { | 
 |     return '#Transient#'; | 
 |   } | 
 | } | 
 |  | 
 |  | 
 | function formatObject_(value, include_properties) { | 
 |   var result = ''; | 
 |   result += formatHandleReference_(value); | 
 |   result += ', type: object'; | 
 |   result += ', constructor '; | 
 |   var ctor = value.constructorFunctionValue(); | 
 |   result += formatHandleReference_(ctor); | 
 |   result += ', __proto__ '; | 
 |   var proto = value.protoObjectValue(); | 
 |   result += formatHandleReference_(proto); | 
 |   result += ', '; | 
 |   result += value.propertyCount(); | 
 |   result +=  ' properties.'; | 
 |   if (include_properties) { | 
 |     result +=  '\n'; | 
 |     for (var i = 0; i < value.propertyCount(); i++) { | 
 |       result += '  '; | 
 |       result += value.propertyName(i); | 
 |       result += ': '; | 
 |       var property_value = value.propertyValue(i); | 
 |       if (property_value instanceof ProtocolReference) { | 
 |         result += '<no type>'; | 
 |       } else { | 
 |         if (property_value && property_value.type()) { | 
 |           result += property_value.type(); | 
 |         } else { | 
 |           result += '<no type>'; | 
 |         } | 
 |       } | 
 |       result += ' '; | 
 |       result += formatHandleReference_(property_value); | 
 |       result += '\n'; | 
 |     } | 
 |   } | 
 |   return result; | 
 | } | 
 |  | 
 |  | 
 | function formatScope_(scope) { | 
 |   var result = ''; | 
 |   var index = scope.index; | 
 |   result += '#' + (index <= 9 ? '0' : '') + index; | 
 |   result += ' '; | 
 |   switch (scope.type) { | 
 |     case Debug.ScopeType.Global: | 
 |       result += 'Global, '; | 
 |       result += '#' + scope.object.ref + '#'; | 
 |       break; | 
 |     case Debug.ScopeType.Local: | 
 |       result += 'Local'; | 
 |       break; | 
 |     case Debug.ScopeType.With: | 
 |       result += 'With, '; | 
 |       result += '#' + scope.object.ref + '#'; | 
 |       break; | 
 |     case Debug.ScopeType.Catch: | 
 |       result += 'Catch, '; | 
 |       result += '#' + scope.object.ref + '#'; | 
 |       break; | 
 |     case Debug.ScopeType.Closure: | 
 |       result += 'Closure'; | 
 |       break; | 
 |     default: | 
 |       result += 'UNKNOWN'; | 
 |   } | 
 |   return result; | 
 | } | 
 |  | 
 |  | 
 | function refObjectToString_(protocolPackage, handle) { | 
 |   var value = protocolPackage.lookup(handle); | 
 |   var result = ''; | 
 |   if (value.isString()) { | 
 |     result = '"' + value.value() + '"'; | 
 |   } else if (value.isPrimitive()) { | 
 |     result = value.valueString(); | 
 |   } else if (value.isObject()) { | 
 |     result += formatObject_(value, true); | 
 |   } | 
 |   return result; | 
 | } | 
 |  | 
 |  | 
 | function decodeLolCaptureResponse(body) { | 
 |   var result; | 
 |   result = 'Captured live object list '+ body.id + | 
 |            ': count '+ body.count + ' size ' + body.size; | 
 |   return result; | 
 | } | 
 |  | 
 |  | 
 | function decodeLolDeleteResponse(body) { | 
 |   var result; | 
 |   result = 'Deleted live object list '+ body.id; | 
 |   return result; | 
 | } | 
 |  | 
 |  | 
 | function digitsIn(value) { | 
 |   var digits = 0; | 
 |   if (value === 0) value = 1; | 
 |   while (value >= 1) { | 
 |     digits++; | 
 |     value /= 10; | 
 |   } | 
 |   return digits; | 
 | } | 
 |  | 
 |  | 
 | function padding(value, max_digits) { | 
 |   var padding_digits = max_digits - digitsIn(value); | 
 |   var padding = ''; | 
 |   while (padding_digits > 0) { | 
 |     padding += ' '; | 
 |     padding_digits--; | 
 |   } | 
 |   return padding; | 
 | } | 
 |  | 
 |  | 
 | function decodeLolInfoResponse(body) { | 
 |   var result; | 
 |   var lists = body.lists; | 
 |   var length = lists.length; | 
 |   var first_index = body.first_index + 1; | 
 |   var has_more = ((first_index + length) <= body.count); | 
 |   result = 'captured live object lists'; | 
 |   if (has_more || (first_index != 1)) { | 
 |     result += ' ['+ length +' of '+ body.count + | 
 |               ': starting from '+ first_index +']'; | 
 |   } | 
 |   result += ':\n'; | 
 |   var max_digits = digitsIn(body.count); | 
 |   var last_count = 0; | 
 |   var last_size = 0; | 
 |   for (var i = 0; i < length; i++) { | 
 |     var entry = lists[i]; | 
 |     var count = entry.count; | 
 |     var size = entry.size; | 
 |     var index = first_index + i; | 
 |     result += '  [' + padding(index, max_digits) + index + '] id '+ entry.id + | 
 |               ': count '+ count; | 
 |     if (last_count > 0) { | 
 |       result += '(+' + (count - last_count) + ')'; | 
 |     } | 
 |     result += ' size '+ size; | 
 |     if (last_size > 0) { | 
 |       result += '(+' + (size - last_size) + ')'; | 
 |     } | 
 |     result += '\n'; | 
 |     last_count = count; | 
 |     last_size = size; | 
 |   } | 
 |   result += '  total: '+length+' lists\n'; | 
 |   if (has_more) { | 
 |     result += '  -- press <enter> for more --\n'; | 
 |   } else { | 
 |     repeat_cmd_line = ''; | 
 |   } | 
 |   if (length === 0) result += '  none\n'; | 
 |  | 
 |   return result; | 
 | } | 
 |  | 
 |  | 
 | function decodeLolListResponse(body, title) { | 
 |  | 
 |   var result; | 
 |   var total_count = body.count; | 
 |   var total_size = body.size; | 
 |   var length; | 
 |   var max_digits; | 
 |   var i; | 
 |   var entry; | 
 |   var index; | 
 |  | 
 |   var max_count_digits = digitsIn(total_count); | 
 |   var max_size_digits; | 
 |  | 
 |   var summary = body.summary; | 
 |   if (summary) { | 
 |  | 
 |     var roots_count = 0; | 
 |     var found_root = body.found_root || 0; | 
 |     var found_weak_root = body.found_weak_root || 0; | 
 |  | 
 |     // Print the summary result: | 
 |     result = 'summary of objects:\n'; | 
 |     length = summary.length; | 
 |     if (found_root !== 0) { | 
 |       roots_count++; | 
 |     } | 
 |     if (found_weak_root !== 0) { | 
 |       roots_count++; | 
 |     } | 
 |     max_digits = digitsIn(length + roots_count); | 
 |     max_size_digits = digitsIn(total_size); | 
 |  | 
 |     index = 1; | 
 |     if (found_root !== 0) { | 
 |       result += '  [' + padding(index, max_digits) + index + '] ' + | 
 |                 ' count '+ 1 + padding(0, max_count_digits) + | 
 |                 '      '+ padding(0, max_size_digits+1) + | 
 |                 ' : <root>\n'; | 
 |       index++; | 
 |     } | 
 |     if (found_weak_root !== 0) { | 
 |       result += '  [' + padding(index, max_digits) + index + '] ' + | 
 |                 ' count '+ 1 + padding(0, max_count_digits) + | 
 |                 '      '+ padding(0, max_size_digits+1) + | 
 |                 ' : <weak root>\n'; | 
 |       index++; | 
 |     } | 
 |  | 
 |     for (i = 0; i < length; i++) { | 
 |       entry = summary[i]; | 
 |       var count = entry.count; | 
 |       var size = entry.size; | 
 |       result += '  [' + padding(index, max_digits) + index + '] ' + | 
 |                 ' count '+ count + padding(count, max_count_digits) + | 
 |                 ' size '+ size + padding(size, max_size_digits) + | 
 |                 ' : <' + entry.desc + '>\n'; | 
 |       index++; | 
 |     } | 
 |     result += '\n  total count: '+(total_count+roots_count)+'\n'; | 
 |     if (body.size) { | 
 |       result += '  total size:  '+body.size+'\n'; | 
 |     } | 
 |  | 
 |   } else { | 
 |     // Print the full dump result: | 
 |     var first_index = body.first_index + 1; | 
 |     var elements = body.elements; | 
 |     length = elements.length; | 
 |     var has_more = ((first_index + length) <= total_count); | 
 |     result = title; | 
 |     if (has_more || (first_index != 1)) { | 
 |       result += ' ['+ length +' of '+ total_count + | 
 |                 ': starting from '+ first_index +']'; | 
 |     } | 
 |     result += ':\n'; | 
 |     if (length === 0) result += '  none\n'; | 
 |     max_digits = digitsIn(length); | 
 |  | 
 |     var max_id = 0; | 
 |     var max_size = 0; | 
 |     for (i = 0; i < length; i++) { | 
 |       entry = elements[i]; | 
 |       if (entry.id > max_id) max_id = entry.id; | 
 |       if (entry.size > max_size) max_size = entry.size; | 
 |     } | 
 |     var max_id_digits = digitsIn(max_id); | 
 |     max_size_digits = digitsIn(max_size); | 
 |  | 
 |     for (i = 0; i < length; i++) { | 
 |       entry = elements[i]; | 
 |       index = first_index + i; | 
 |       result += '  ['+ padding(index, max_digits) + index +']'; | 
 |       if (entry.id !== 0) { | 
 |         result += ' @' + entry.id + padding(entry.id, max_id_digits) + | 
 |                   ': size ' + entry.size + ', ' + | 
 |                   padding(entry.size, max_size_digits) +  entry.desc + '\n'; | 
 |       } else { | 
 |         // Must be a root or weak root: | 
 |         result += ' ' + entry.desc + '\n'; | 
 |       } | 
 |     } | 
 |     if (has_more) { | 
 |       result += '  -- press <enter> for more --\n'; | 
 |     } else { | 
 |       repeat_cmd_line = ''; | 
 |     } | 
 |     if (length === 0) result += '  none\n'; | 
 |   } | 
 |  | 
 |   return result; | 
 | } | 
 |  | 
 |  | 
 | function decodeLolDiffResponse(body) { | 
 |   var title = 'objects'; | 
 |   return decodeLolListResponse(body, title); | 
 | } | 
 |  | 
 |  | 
 | function decodeLolRetainersResponse(body) { | 
 |   var title = 'retainers for @' + body.id; | 
 |   return decodeLolListResponse(body, title); | 
 | } | 
 |  | 
 |  | 
 | function decodeLolPathResponse(body) { | 
 |   return body.path; | 
 | } | 
 |  | 
 |  | 
 | function decodeLolResetResponse(body) { | 
 |   return 'Reset all live object lists.'; | 
 | } | 
 |  | 
 |  | 
 | function decodeLolGetIdResponse(body) { | 
 |   if (body.id == 0) { | 
 |     return 'Address is invalid, or object has been moved or collected'; | 
 |   } | 
 |   return 'obj id is @' + body.id; | 
 | } | 
 |  | 
 |  | 
 | function decodeLolPrintResponse(body) { | 
 |   return body.dump; | 
 | } | 
 |  | 
 |  | 
 | // Rounds number 'num' to 'length' decimal places. | 
 | function roundNumber(num, length) { | 
 |   var factor = Math.pow(10, length); | 
 |   return Math.round(num * factor) / factor; | 
 | } | 
 |  | 
 |  | 
 | // Convert a JSON response to text for display in a text based debugger. | 
 | function DebugResponseDetails(response) { | 
 |   var details = { text: '', running: false }; | 
 |  | 
 |   try { | 
 |     if (!response.success()) { | 
 |       details.text = response.message(); | 
 |       return details; | 
 |     } | 
 |  | 
 |     // Get the running state. | 
 |     details.running = response.running(); | 
 |  | 
 |     var body = response.body(); | 
 |     var result = ''; | 
 |     switch (response.command()) { | 
 |       case 'suspend': | 
 |         details.text = 'stopped'; | 
 |         break; | 
 |  | 
 |       case 'setbreakpoint': | 
 |         result = 'set breakpoint #'; | 
 |         result += body.breakpoint; | 
 |         details.text = result; | 
 |         break; | 
 |  | 
 |       case 'clearbreakpoint': | 
 |         result = 'cleared breakpoint #'; | 
 |         result += body.breakpoint; | 
 |         details.text = result; | 
 |         break; | 
 |  | 
 |       case 'changebreakpoint': | 
 |         result = 'successfully changed breakpoint'; | 
 |         details.text = result; | 
 |         break; | 
 |  | 
 |       case 'listbreakpoints': | 
 |         result = 'breakpoints: (' + body.breakpoints.length + ')'; | 
 |         for (var i = 0; i < body.breakpoints.length; i++) { | 
 |           var breakpoint = body.breakpoints[i]; | 
 |           result += '\n id=' + breakpoint.number; | 
 |           result += ' type=' + breakpoint.type; | 
 |           if (breakpoint.script_id) { | 
 |               result += ' script_id=' + breakpoint.script_id; | 
 |           } | 
 |           if (breakpoint.script_name) { | 
 |               result += ' script_name=' + breakpoint.script_name; | 
 |           } | 
 |           if (breakpoint.script_regexp) { | 
 |               result += ' script_regexp=' + breakpoint.script_regexp; | 
 |           } | 
 |           result += ' line=' + (breakpoint.line + 1); | 
 |           if (breakpoint.column != null) { | 
 |             result += ' column=' + (breakpoint.column + 1); | 
 |           } | 
 |           if (breakpoint.groupId) { | 
 |             result += ' groupId=' + breakpoint.groupId; | 
 |           } | 
 |           if (breakpoint.ignoreCount) { | 
 |               result += ' ignoreCount=' + breakpoint.ignoreCount; | 
 |           } | 
 |           if (breakpoint.active === false) { | 
 |             result += ' inactive'; | 
 |           } | 
 |           if (breakpoint.condition) { | 
 |             result += ' condition=' + breakpoint.condition; | 
 |           } | 
 |           result += ' hit_count=' + breakpoint.hit_count; | 
 |         } | 
 |         if (body.breakpoints.length === 0) { | 
 |           result = "No user defined breakpoints\n"; | 
 |         } else { | 
 |           result += '\n'; | 
 |         } | 
 |         if (body.breakOnExceptions) { | 
 |           result += '* breaking on ALL exceptions is enabled\n'; | 
 |         } else if (body.breakOnUncaughtExceptions) { | 
 |           result += '* breaking on UNCAUGHT exceptions is enabled\n'; | 
 |         } else { | 
 |           result += '* all exception breakpoints are disabled\n'; | 
 |         } | 
 |         details.text = result; | 
 |         break; | 
 |  | 
 |       case 'setexceptionbreak': | 
 |         result = 'Break on ' + body.type + ' exceptions: '; | 
 |         result += body.enabled ? 'enabled' : 'disabled'; | 
 |         details.text = result; | 
 |         break; | 
 |  | 
 |       case 'backtrace': | 
 |         if (body.totalFrames == 0) { | 
 |           result = '(empty stack)'; | 
 |         } else { | 
 |           var result = 'Frames #' + body.fromFrame + ' to #' + | 
 |               (body.toFrame - 1) + ' of ' + body.totalFrames + '\n'; | 
 |           for (i = 0; i < body.frames.length; i++) { | 
 |             if (i != 0) result += '\n'; | 
 |             result += body.frames[i].text; | 
 |           } | 
 |         } | 
 |         details.text = result; | 
 |         break; | 
 |  | 
 |       case 'frame': | 
 |         if (last_cmd === 'info locals') { | 
 |           var locals = body.locals; | 
 |           if (locals.length === 0) { | 
 |             result = 'No locals'; | 
 |           } else { | 
 |             for (var i = 0; i < locals.length; i++) { | 
 |               var local = locals[i]; | 
 |               result += local.name + ' = '; | 
 |               result += refObjectToString_(response, local.value.ref); | 
 |               result += '\n'; | 
 |             } | 
 |           } | 
 |         } else if (last_cmd === 'info args') { | 
 |           var args = body.arguments; | 
 |           if (args.length === 0) { | 
 |             result = 'No arguments'; | 
 |           } else { | 
 |             for (var i = 0; i < args.length; i++) { | 
 |               var arg = args[i]; | 
 |               result += arg.name + ' = '; | 
 |               result += refObjectToString_(response, arg.value.ref); | 
 |               result += '\n'; | 
 |             } | 
 |           } | 
 |         } else { | 
 |           result = SourceUnderline(body.sourceLineText, | 
 |                                    body.column); | 
 |           Debug.State.currentSourceLine = body.line; | 
 |           Debug.State.currentFrame = body.index; | 
 |           Debug.State.displaySourceStartLine = -1; | 
 |           Debug.State.displaySourceEndLine = -1; | 
 |         } | 
 |         details.text = result; | 
 |         break; | 
 |  | 
 |       case 'scopes': | 
 |         if (body.totalScopes == 0) { | 
 |           result = '(no scopes)'; | 
 |         } else { | 
 |           result = 'Scopes #' + body.fromScope + ' to #' + | 
 |                    (body.toScope - 1) + ' of ' + body.totalScopes + '\n'; | 
 |           for (i = 0; i < body.scopes.length; i++) { | 
 |             if (i != 0) { | 
 |               result += '\n'; | 
 |             } | 
 |             result += formatScope_(body.scopes[i]); | 
 |           } | 
 |         } | 
 |         details.text = result; | 
 |         break; | 
 |  | 
 |       case 'scope': | 
 |         result += formatScope_(body); | 
 |         result += '\n'; | 
 |         var scope_object_value = response.lookup(body.object.ref); | 
 |         result += formatObject_(scope_object_value, true); | 
 |         details.text = result; | 
 |         break; | 
 |  | 
 |       case 'evaluate': | 
 |       case 'lookup': | 
 |       case 'getobj': | 
 |         if (last_cmd == 'p' || last_cmd == 'print') { | 
 |           result = body.text; | 
 |         } else { | 
 |           var value; | 
 |           if (lookup_handle) { | 
 |             value = response.bodyValue(lookup_handle); | 
 |           } else { | 
 |             value = response.bodyValue(); | 
 |           } | 
 |           if (value.isObject()) { | 
 |             result += formatObject_(value, true); | 
 |           } else { | 
 |             result += 'type: '; | 
 |             result += value.type(); | 
 |             if (!value.isUndefined() && !value.isNull()) { | 
 |               result += ', '; | 
 |               if (value.isString()) { | 
 |                 result += '"'; | 
 |               } | 
 |               result += value.value(); | 
 |               if (value.isString()) { | 
 |                 result += '"'; | 
 |               } | 
 |             } | 
 |             result += '\n'; | 
 |           } | 
 |         } | 
 |         details.text = result; | 
 |         break; | 
 |  | 
 |       case 'references': | 
 |         var count = body.length; | 
 |         result += 'found ' + count + ' objects'; | 
 |         result += '\n'; | 
 |         for (var i = 0; i < count; i++) { | 
 |           var value = response.bodyValue(i); | 
 |           result += formatObject_(value, false); | 
 |           result += '\n'; | 
 |         } | 
 |         details.text = result; | 
 |         break; | 
 |  | 
 |       case 'source': | 
 |         // Get the source from the response. | 
 |         var source = body.source; | 
 |         var from_line = body.fromLine + 1; | 
 |         var lines = source.split('\n'); | 
 |         var maxdigits = 1 + Math.floor(log10(from_line + lines.length)); | 
 |         if (maxdigits < 3) { | 
 |           maxdigits = 3; | 
 |         } | 
 |         var result = ''; | 
 |         for (var num = 0; num < lines.length; num++) { | 
 |           // Check if there's an extra newline at the end. | 
 |           if (num == (lines.length - 1) && lines[num].length == 0) { | 
 |             break; | 
 |           } | 
 |  | 
 |           var current_line = from_line + num; | 
 |           var spacer = maxdigits - (1 + Math.floor(log10(current_line))); | 
 |           if (current_line == Debug.State.currentSourceLine + 1) { | 
 |             for (var i = 0; i < maxdigits; i++) { | 
 |               result += '>'; | 
 |             } | 
 |             result += '  '; | 
 |           } else { | 
 |             for (var i = 0; i < spacer; i++) { | 
 |               result += ' '; | 
 |             } | 
 |             result += current_line + ': '; | 
 |           } | 
 |           result += lines[num]; | 
 |           result += '\n'; | 
 |         } | 
 |         details.text = result; | 
 |         break; | 
 |  | 
 |       case 'scripts': | 
 |         var result = ''; | 
 |         for (i = 0; i < body.length; i++) { | 
 |           if (i != 0) result += '\n'; | 
 |           if (body[i].id) { | 
 |             result += body[i].id; | 
 |           } else { | 
 |             result += '[no id]'; | 
 |           } | 
 |           result += ', '; | 
 |           if (body[i].name) { | 
 |             result += body[i].name; | 
 |           } else { | 
 |             if (body[i].compilationType == Debug.ScriptCompilationType.Eval | 
 |                 && body[i].evalFromScript | 
 |                 ) { | 
 |               result += 'eval from '; | 
 |               var script_value = response.lookup(body[i].evalFromScript.ref); | 
 |               result += ' ' + script_value.field('name'); | 
 |               result += ':' + (body[i].evalFromLocation.line + 1); | 
 |               result += ':' + body[i].evalFromLocation.column; | 
 |             } else if (body[i].compilationType == | 
 |                        Debug.ScriptCompilationType.JSON) { | 
 |               result += 'JSON '; | 
 |             } else {  // body[i].compilation == Debug.ScriptCompilationType.Host | 
 |               result += '[unnamed] '; | 
 |             } | 
 |           } | 
 |           result += ' (lines: '; | 
 |           result += body[i].lineCount; | 
 |           result += ', length: '; | 
 |           result += body[i].sourceLength; | 
 |           if (body[i].type == Debug.ScriptType.Native) { | 
 |             result += ', native'; | 
 |           } else if (body[i].type == Debug.ScriptType.Extension) { | 
 |             result += ', extension'; | 
 |           } | 
 |           result += '), ['; | 
 |           var sourceStart = body[i].sourceStart; | 
 |           if (sourceStart.length > 40) { | 
 |             sourceStart = sourceStart.substring(0, 37) + '...'; | 
 |           } | 
 |           result += sourceStart; | 
 |           result += ']'; | 
 |         } | 
 |         if (body.length == 0) { | 
 |           result = "no matching scripts found"; | 
 |         } | 
 |         details.text = result; | 
 |         break; | 
 |  | 
 |       case 'threads': | 
 |         var result = 'Active V8 threads: ' + body.totalThreads + '\n'; | 
 |         body.threads.sort(function(a, b) { return a.id - b.id; }); | 
 |         for (i = 0; i < body.threads.length; i++) { | 
 |           result += body.threads[i].current ? '*' : ' '; | 
 |           result += ' '; | 
 |           result += body.threads[i].id; | 
 |           result += '\n'; | 
 |         } | 
 |         details.text = result; | 
 |         break; | 
 |  | 
 |       case 'continue': | 
 |         details.text = "(running)"; | 
 |         break; | 
 |  | 
 |       case 'v8flags': | 
 |         details.text = "flags set"; | 
 |         break; | 
 |  | 
 |       case 'gc': | 
 |         details.text = "GC " + body.before + " => " + body.after; | 
 |         if (body.after > (1024*1024)) { | 
 |           details.text += | 
 |               " (" + roundNumber(body.before/(1024*1024), 1) + "M => " + | 
 |                      roundNumber(body.after/(1024*1024), 1) + "M)"; | 
 |         } else if (body.after > 1024) { | 
 |           details.text += | 
 |               " (" + roundNumber(body.before/1024, 1) + "K => " + | 
 |                      roundNumber(body.after/1024, 1) + "K)"; | 
 |         } | 
 |         break; | 
 |  | 
 |       case 'lol-capture': | 
 |         details.text = decodeLolCaptureResponse(body); | 
 |         break; | 
 |       case 'lol-delete': | 
 |         details.text = decodeLolDeleteResponse(body); | 
 |         break; | 
 |       case 'lol-diff': | 
 |         details.text = decodeLolDiffResponse(body); | 
 |         break; | 
 |       case 'lol-getid': | 
 |         details.text = decodeLolGetIdResponse(body); | 
 |         break; | 
 |       case 'lol-info': | 
 |         details.text = decodeLolInfoResponse(body); | 
 |         break; | 
 |       case 'lol-print': | 
 |         details.text = decodeLolPrintResponse(body); | 
 |         break; | 
 |       case 'lol-reset': | 
 |         details.text = decodeLolResetResponse(body); | 
 |         break; | 
 |       case 'lol-retainers': | 
 |         details.text = decodeLolRetainersResponse(body); | 
 |         break; | 
 |       case 'lol-path': | 
 |         details.text = decodeLolPathResponse(body); | 
 |         break; | 
 |  | 
 |       default: | 
 |         details.text = | 
 |             'Response for unknown command \'' + response.command() + '\'' + | 
 |             ' (' + response.raw_json() + ')'; | 
 |     } | 
 |   } catch (e) { | 
 |     details.text = 'Error: "' + e + '" formatting response'; | 
 |   } | 
 |  | 
 |   return details; | 
 | } | 
 |  | 
 |  | 
 | /** | 
 |  * Protocol packages send from the debugger. | 
 |  * @param {string} json - raw protocol packet as JSON string. | 
 |  * @constructor | 
 |  */ | 
 | function ProtocolPackage(json) { | 
 |   this.raw_json_ = json; | 
 |   this.packet_ = JSON.parse(json); | 
 |   this.refs_ = []; | 
 |   if (this.packet_.refs) { | 
 |     for (var i = 0; i < this.packet_.refs.length; i++) { | 
 |       this.refs_[this.packet_.refs[i].handle] = this.packet_.refs[i]; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 |  | 
 | /** | 
 |  * Get the packet type. | 
 |  * @return {String} the packet type | 
 |  */ | 
 | ProtocolPackage.prototype.type = function() { | 
 |   return this.packet_.type; | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Get the packet event. | 
 |  * @return {Object} the packet event | 
 |  */ | 
 | ProtocolPackage.prototype.event = function() { | 
 |   return this.packet_.event; | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Get the packet request sequence. | 
 |  * @return {number} the packet request sequence | 
 |  */ | 
 | ProtocolPackage.prototype.requestSeq = function() { | 
 |   return this.packet_.request_seq; | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Get the packet request sequence. | 
 |  * @return {number} the packet request sequence | 
 |  */ | 
 | ProtocolPackage.prototype.running = function() { | 
 |   return this.packet_.running ? true : false; | 
 | }; | 
 |  | 
 |  | 
 | ProtocolPackage.prototype.success = function() { | 
 |   return this.packet_.success ? true : false; | 
 | }; | 
 |  | 
 |  | 
 | ProtocolPackage.prototype.message = function() { | 
 |   return this.packet_.message; | 
 | }; | 
 |  | 
 |  | 
 | ProtocolPackage.prototype.command = function() { | 
 |   return this.packet_.command; | 
 | }; | 
 |  | 
 |  | 
 | ProtocolPackage.prototype.body = function() { | 
 |   return this.packet_.body; | 
 | }; | 
 |  | 
 |  | 
 | ProtocolPackage.prototype.bodyValue = function(index) { | 
 |   if (index != null) { | 
 |     return new ProtocolValue(this.packet_.body[index], this); | 
 |   } else { | 
 |     return new ProtocolValue(this.packet_.body, this); | 
 |   } | 
 | }; | 
 |  | 
 |  | 
 | ProtocolPackage.prototype.body = function() { | 
 |   return this.packet_.body; | 
 | }; | 
 |  | 
 |  | 
 | ProtocolPackage.prototype.lookup = function(handle) { | 
 |   var value = this.refs_[handle]; | 
 |   if (value) { | 
 |     return new ProtocolValue(value, this); | 
 |   } else { | 
 |     return new ProtocolReference(handle); | 
 |   } | 
 | }; | 
 |  | 
 |  | 
 | ProtocolPackage.prototype.raw_json = function() { | 
 |   return this.raw_json_; | 
 | }; | 
 |  | 
 |  | 
 | function ProtocolValue(value, packet) { | 
 |   this.value_ = value; | 
 |   this.packet_ = packet; | 
 | } | 
 |  | 
 |  | 
 | /** | 
 |  * Get the value type. | 
 |  * @return {String} the value type | 
 |  */ | 
 | ProtocolValue.prototype.type = function() { | 
 |   return this.value_.type; | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Get a metadata field from a protocol value. | 
 |  * @return {Object} the metadata field value | 
 |  */ | 
 | ProtocolValue.prototype.field = function(name) { | 
 |   return this.value_[name]; | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Check is the value is a primitive value. | 
 |  * @return {boolean} true if the value is primitive | 
 |  */ | 
 | ProtocolValue.prototype.isPrimitive = function() { | 
 |   return this.isUndefined() || this.isNull() || this.isBoolean() || | 
 |          this.isNumber() || this.isString(); | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Get the object handle. | 
 |  * @return {number} the value handle | 
 |  */ | 
 | ProtocolValue.prototype.handle = function() { | 
 |   return this.value_.handle; | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Check is the value is undefined. | 
 |  * @return {boolean} true if the value is undefined | 
 |  */ | 
 | ProtocolValue.prototype.isUndefined = function() { | 
 |   return this.value_.type == 'undefined'; | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Check is the value is null. | 
 |  * @return {boolean} true if the value is null | 
 |  */ | 
 | ProtocolValue.prototype.isNull = function() { | 
 |   return this.value_.type == 'null'; | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Check is the value is a boolean. | 
 |  * @return {boolean} true if the value is a boolean | 
 |  */ | 
 | ProtocolValue.prototype.isBoolean = function() { | 
 |   return this.value_.type == 'boolean'; | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Check is the value is a number. | 
 |  * @return {boolean} true if the value is a number | 
 |  */ | 
 | ProtocolValue.prototype.isNumber = function() { | 
 |   return this.value_.type == 'number'; | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Check is the value is a string. | 
 |  * @return {boolean} true if the value is a string | 
 |  */ | 
 | ProtocolValue.prototype.isString = function() { | 
 |   return this.value_.type == 'string'; | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Check is the value is an object. | 
 |  * @return {boolean} true if the value is an object | 
 |  */ | 
 | ProtocolValue.prototype.isObject = function() { | 
 |   return this.value_.type == 'object' || this.value_.type == 'function' || | 
 |          this.value_.type == 'error' || this.value_.type == 'regexp'; | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Get the constructor function | 
 |  * @return {ProtocolValue} constructor function | 
 |  */ | 
 | ProtocolValue.prototype.constructorFunctionValue = function() { | 
 |   var ctor = this.value_.constructorFunction; | 
 |   return this.packet_.lookup(ctor.ref); | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Get the __proto__ value | 
 |  * @return {ProtocolValue} __proto__ value | 
 |  */ | 
 | ProtocolValue.prototype.protoObjectValue = function() { | 
 |   var proto = this.value_.protoObject; | 
 |   return this.packet_.lookup(proto.ref); | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Get the number og properties. | 
 |  * @return {number} the number of properties | 
 |  */ | 
 | ProtocolValue.prototype.propertyCount = function() { | 
 |   return this.value_.properties ? this.value_.properties.length : 0; | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Get the specified property name. | 
 |  * @return {string} property name | 
 |  */ | 
 | ProtocolValue.prototype.propertyName = function(index) { | 
 |   var property = this.value_.properties[index]; | 
 |   return property.name; | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Return index for the property name. | 
 |  * @param name The property name to look for | 
 |  * @return {number} index for the property name | 
 |  */ | 
 | ProtocolValue.prototype.propertyIndex = function(name) { | 
 |   for (var i = 0; i < this.propertyCount(); i++) { | 
 |     if (this.value_.properties[i].name == name) { | 
 |       return i; | 
 |     } | 
 |   } | 
 |   return null; | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Get the specified property value. | 
 |  * @return {ProtocolValue} property value | 
 |  */ | 
 | ProtocolValue.prototype.propertyValue = function(index) { | 
 |   var property = this.value_.properties[index]; | 
 |   return this.packet_.lookup(property.ref); | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Check is the value is a string. | 
 |  * @return {boolean} true if the value is a string | 
 |  */ | 
 | ProtocolValue.prototype.value = function() { | 
 |   return this.value_.value; | 
 | }; | 
 |  | 
 |  | 
 | ProtocolValue.prototype.valueString = function() { | 
 |   return this.value_.text; | 
 | }; | 
 |  | 
 |  | 
 | function ProtocolReference(handle) { | 
 |   this.handle_ = handle; | 
 | } | 
 |  | 
 |  | 
 | ProtocolReference.prototype.handle = function() { | 
 |   return this.handle_; | 
 | }; | 
 |  | 
 |  | 
 | function MakeJSONPair_(name, value) { | 
 |   return '"' + name + '":' + value; | 
 | } | 
 |  | 
 |  | 
 | function ArrayToJSONObject_(content) { | 
 |   return '{' + content.join(',') + '}'; | 
 | } | 
 |  | 
 |  | 
 | function ArrayToJSONArray_(content) { | 
 |   return '[' + content.join(',') + ']'; | 
 | } | 
 |  | 
 |  | 
 | function BooleanToJSON_(value) { | 
 |   return String(value); | 
 | } | 
 |  | 
 |  | 
 | function NumberToJSON_(value) { | 
 |   return String(value); | 
 | } | 
 |  | 
 |  | 
 | // Mapping of some control characters to avoid the \uXXXX syntax for most | 
 | // commonly used control cahracters. | 
 | var ctrlCharMap_ = { | 
 |   '\b': '\\b', | 
 |   '\t': '\\t', | 
 |   '\n': '\\n', | 
 |   '\f': '\\f', | 
 |   '\r': '\\r', | 
 |   '"' : '\\"', | 
 |   '\\': '\\\\' | 
 | }; | 
 |  | 
 |  | 
 | // Regular expression testing for ", \ and control characters (0x00 - 0x1F). | 
 | var ctrlCharTest_ = new RegExp('["\\\\\x00-\x1F]'); | 
 |  | 
 |  | 
 | // Regular expression matching ", \ and control characters (0x00 - 0x1F) | 
 | // globally. | 
 | var ctrlCharMatch_ = new RegExp('["\\\\\x00-\x1F]', 'g'); | 
 |  | 
 |  | 
 | /** | 
 |  * Convert a String to its JSON representation (see http://www.json.org/). To | 
 |  * avoid depending on the String object this method calls the functions in | 
 |  * string.js directly and not through the value. | 
 |  * @param {String} value The String value to format as JSON | 
 |  * @return {string} JSON formatted String value | 
 |  */ | 
 | function StringToJSON_(value) { | 
 |   // Check for" , \ and control characters (0x00 - 0x1F). No need to call | 
 |   // RegExpTest as ctrlchar is constructed using RegExp. | 
 |   if (ctrlCharTest_.test(value)) { | 
 |     // Replace ", \ and control characters (0x00 - 0x1F). | 
 |     return '"' + | 
 |       value.replace(ctrlCharMatch_, function (char) { | 
 |         // Use charmap if possible. | 
 |         var mapped = ctrlCharMap_[char]; | 
 |         if (mapped) return mapped; | 
 |         mapped = char.charCodeAt(); | 
 |         // Convert control character to unicode escape sequence. | 
 |         return '\\u00' + | 
 |           '0' + // TODO %NumberToRadixString(Math.floor(mapped / 16), 16) + | 
 |           '0'; // TODO %NumberToRadixString(mapped % 16, 16) | 
 |       }) | 
 |     + '"'; | 
 |   } | 
 |  | 
 |   // Simple string with no special characters. | 
 |   return '"' + value + '"'; | 
 | } | 
 |  | 
 |  | 
 | /** | 
 |  * Convert a Date to ISO 8601 format. To avoid depending on the Date object | 
 |  * this method calls the functions in date.js directly and not through the | 
 |  * value. | 
 |  * @param {Date} value The Date value to format as JSON | 
 |  * @return {string} JSON formatted Date value | 
 |  */ | 
 | function DateToISO8601_(value) { | 
 |   var f = function(n) { | 
 |     return n < 10 ? '0' + n : n; | 
 |   }; | 
 |   var g = function(n) { | 
 |     return n < 10 ? '00' + n : n < 100 ? '0' + n : n; | 
 |   }; | 
 |   return builtins.GetUTCFullYearFrom(value)         + '-' + | 
 |           f(builtins.GetUTCMonthFrom(value) + 1)    + '-' + | 
 |           f(builtins.GetUTCDateFrom(value))         + 'T' + | 
 |           f(builtins.GetUTCHoursFrom(value))        + ':' + | 
 |           f(builtins.GetUTCMinutesFrom(value))      + ':' + | 
 |           f(builtins.GetUTCSecondsFrom(value))      + '.' + | 
 |           g(builtins.GetUTCMillisecondsFrom(value)) + 'Z'; | 
 | } | 
 |  | 
 |  | 
 | /** | 
 |  * Convert a Date to ISO 8601 format. To avoid depending on the Date object | 
 |  * this method calls the functions in date.js directly and not through the | 
 |  * value. | 
 |  * @param {Date} value The Date value to format as JSON | 
 |  * @return {string} JSON formatted Date value | 
 |  */ | 
 | function DateToJSON_(value) { | 
 |   return '"' + DateToISO8601_(value) + '"'; | 
 | } | 
 |  | 
 |  | 
 | /** | 
 |  * Convert an Object to its JSON representation (see http://www.json.org/). | 
 |  * This implementation simply runs through all string property names and adds | 
 |  * each property to the JSON representation for some predefined types. For type | 
 |  * "object" the function calls itself recursively unless the object has the | 
 |  * function property "toJSONProtocol" in which case that is used. This is not | 
 |  * a general implementation but sufficient for the debugger. Note that circular | 
 |  * structures will cause infinite recursion. | 
 |  * @param {Object} object The object to format as JSON | 
 |  * @return {string} JSON formatted object value | 
 |  */ | 
 | function SimpleObjectToJSON_(object) { | 
 |   var content = []; | 
 |   for (var key in object) { | 
 |     // Only consider string keys. | 
 |     if (typeof key == 'string') { | 
 |       var property_value = object[key]; | 
 |  | 
 |       // Format the value based on its type. | 
 |       var property_value_json; | 
 |       switch (typeof property_value) { | 
 |         case 'object': | 
 |           if (property_value === null) { | 
 |             property_value_json = 'null'; | 
 |           } else if (typeof property_value.toJSONProtocol == 'function') { | 
 |             property_value_json = property_value.toJSONProtocol(true); | 
 |           } else if (property_value.constructor.name == 'Array'){ | 
 |             property_value_json = SimpleArrayToJSON_(property_value); | 
 |           } else { | 
 |             property_value_json = SimpleObjectToJSON_(property_value); | 
 |           } | 
 |           break; | 
 |  | 
 |         case 'boolean': | 
 |           property_value_json = BooleanToJSON_(property_value); | 
 |           break; | 
 |  | 
 |         case 'number': | 
 |           property_value_json = NumberToJSON_(property_value); | 
 |           break; | 
 |  | 
 |         case 'string': | 
 |           property_value_json = StringToJSON_(property_value); | 
 |           break; | 
 |  | 
 |         default: | 
 |           property_value_json = null; | 
 |       } | 
 |  | 
 |       // Add the property if relevant. | 
 |       if (property_value_json) { | 
 |         content.push(StringToJSON_(key) + ':' + property_value_json); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   // Make JSON object representation. | 
 |   return '{' + content.join(',') + '}'; | 
 | } | 
 |  | 
 |  | 
 | /** | 
 |  * Convert an array to its JSON representation. This is a VERY simple | 
 |  * implementation just to support what is needed for the debugger. | 
 |  * @param {Array} arrya The array to format as JSON | 
 |  * @return {string} JSON formatted array value | 
 |  */ | 
 | function SimpleArrayToJSON_(array) { | 
 |   // Make JSON array representation. | 
 |   var json = '['; | 
 |   for (var i = 0; i < array.length; i++) { | 
 |     if (i != 0) { | 
 |       json += ','; | 
 |     } | 
 |     var elem = array[i]; | 
 |     if (elem.toJSONProtocol) { | 
 |       json += elem.toJSONProtocol(true); | 
 |     } else if (typeof(elem) === 'object')  { | 
 |       json += SimpleObjectToJSON_(elem); | 
 |     } else if (typeof(elem) === 'boolean')  { | 
 |       json += BooleanToJSON_(elem); | 
 |     } else if (typeof(elem) === 'number')  { | 
 |       json += NumberToJSON_(elem); | 
 |     } else if (typeof(elem) === 'string')  { | 
 |       json += StringToJSON_(elem); | 
 |     } else { | 
 |       json += elem; | 
 |     } | 
 |   } | 
 |   json += ']'; | 
 |   return json; | 
 | } |