text: (function() {
      /*
   * Copyright (C) 2012 Google Inc. 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.
   */
  
  function defineCommonExtensionSymbols(apiPrivate)
  {
      if (!apiPrivate.audits)
          apiPrivate.audits = {};
      apiPrivate.audits.Severity = {
          Info: "info",
          Warning: "warning",
          Severe: "severe"
      };
  
      if (!apiPrivate.console)
          apiPrivate.console = {};
      apiPrivate.console.Severity = {
          Debug: "debug",
          Log: "log",
          Warning: "warning",
          Error: "error"
      };
  
      if (!apiPrivate.panels)
          apiPrivate.panels = {};
      apiPrivate.panels.SearchAction = {
          CancelSearch: "cancelSearch",
          PerformSearch: "performSearch",
          NextSearchResult: "nextSearchResult",
          PreviousSearchResult: "previousSearchResult"
      };
  
      apiPrivate.Events = {
          AuditStarted: "audit-started-",
          ButtonClicked: "button-clicked-",
          ConsoleMessageAdded: "console-message-added",
          PanelObjectSelected: "panel-objectSelected-",
          NetworkRequestFinished: "network-request-finished",
          OpenResource: "open-resource",
          PanelSearch: "panel-search-",
          ResourceAdded: "resource-added",
          ResourceContentCommitted: "resource-content-committed",
          TimelineEventRecorded: "timeline-event-recorded",
          ViewShown: "view-shown-",
          ViewHidden: "view-hidden-"
      };
  
      apiPrivate.Commands = {
          AddAuditCategory: "addAuditCategory",
          AddAuditResult: "addAuditResult",
          AddConsoleMessage: "addConsoleMessage",
          AddRequestHeaders: "addRequestHeaders",
          ApplyStyleSheet: "applyStyleSheet",
          CreatePanel: "createPanel",
          CreateSidebarPane: "createSidebarPane",
          CreateStatusBarButton: "createStatusBarButton",
          EvaluateOnInspectedPage: "evaluateOnInspectedPage",
          ForwardKeyboardEvent: "_forwardKeyboardEvent",
          GetConsoleMessages: "getConsoleMessages",
          GetHAR: "getHAR",
          GetPageResources: "getPageResources",
          GetRequestContent: "getRequestContent",
          GetResourceContent: "getResourceContent",
          InspectedURLChanged: "inspectedURLChanged",
          OpenResource: "openResource",
          Reload: "Reload",
          Subscribe: "subscribe",
          SetOpenResourceHandler: "setOpenResourceHandler",
          SetResourceContent: "setResourceContent",
          SetSidebarContent: "setSidebarContent",
          SetSidebarHeight: "setSidebarHeight",
          SetSidebarPage: "setSidebarPage",
          ShowPanel: "showPanel",
          StopAuditCategoryRun: "stopAuditCategoryRun",
          Unsubscribe: "unsubscribe",
          UpdateAuditProgress: "updateAuditProgress",
          UpdateButton: "updateButton"
      };
  }
  
  function injectedExtensionAPI(injectedScriptId)
  {
  
  var apiPrivate = {};
  
  defineCommonExtensionSymbols(apiPrivate);
  
  var commands = apiPrivate.Commands;
  var events = apiPrivate.Events;
  var userAction = false;
  
  // Here and below, all constructors are private to API implementation.
  // For a public type Foo, if internal fields are present, these are on
  // a private FooImpl type, an instance of FooImpl is used in a closure
  // by Foo consutrctor to re-bind publicly exported members to an instance
  // of Foo.
  
  /**
   * @constructor
   */
  function EventSinkImpl(type, customDispatch)
  {
      this._type = type;
      this._listeners = [];
      this._customDispatch = customDispatch;
  }
  
  EventSinkImpl.prototype = {
      addListener: function(callback)
      {
          if (typeof callback !== "function")
              throw "addListener: callback is not a function";
          if (this._listeners.length === 0)
              extensionServer.sendRequest({ command: commands.Subscribe, type: this._type });
          this._listeners.push(callback);
          extensionServer.registerHandler("notify-" + this._type, this._dispatch.bind(this));
      },
  
      removeListener: function(callback)
      {
          var listeners = this._listeners;
  
          for (var i = 0; i < listeners.length; ++i) {
              if (listeners[i] === callback) {
                  listeners.splice(i, 1);
                  break;
              }
          }
          if (this._listeners.length === 0)
              extensionServer.sendRequest({ command: commands.Unsubscribe, type: this._type });
      },
  
      /**
       * @param {...} vararg
       */
      _fire: function(vararg)
      {
          var listeners = this._listeners.slice();
          for (var i = 0; i < listeners.length; ++i)
              listeners[i].apply(null, arguments);
      },
  
      _dispatch: function(request)
      {
           if (this._customDispatch)
               this._customDispatch.call(this, request);
           else
               this._fire.apply(this, request.arguments);
      }
  }
  
  /**
   * @constructor
   */
  function InspectorExtensionAPI()
  {
      this.audits = new Audits();
      this.inspectedWindow = new InspectedWindow();
      this.panels = new Panels();
      this.network = new Network();
      defineDeprecatedProperty(this, "webInspector", "resources", "network");
      this.timeline = new Timeline();
      this.console = new ConsoleAPI();
  }
  
  /**
   * @constructor
   */
  function ConsoleAPI()
  {
      this.onMessageAdded = new EventSink(events.ConsoleMessageAdded);
  }
  
  ConsoleAPI.prototype = {
      getMessages: function(callback)
      {
          extensionServer.sendRequest({ command: commands.GetConsoleMessages }, callback);
      },
  
      addMessage: function(severity, text, url, line)
      {
          extensionServer.sendRequest({ command: commands.AddConsoleMessage, severity: severity, text: text, url: url, line: line });
      },
  
      get Severity()
      {
          return apiPrivate.console.Severity;
      }
  }
  
  /**
   * @constructor
   */
  function Network()
  {
      /**
       * @this {EventSinkImpl}
       */
      function dispatchRequestEvent(message)
      {
          var request = message.arguments[1];
          request.__proto__ = new Request(message.arguments[0]);
          this._fire(request);
      }
      this.onRequestFinished = new EventSink(events.NetworkRequestFinished, dispatchRequestEvent);
      defineDeprecatedProperty(this, "network", "onFinished", "onRequestFinished");
      this.onNavigated = new EventSink(events.InspectedURLChanged);
  }
  
  Network.prototype = {
      getHAR: function(callback)
      {
          function callbackWrapper(result)
          {
              var entries = (result && result.entries) || [];
              for (var i = 0; i < entries.length; ++i) {
                  entries[i].__proto__ = new Request(entries[i]._requestId);
                  delete entries[i]._requestId;
              }
              callback(result);
          }
          return extensionServer.sendRequest({ command: commands.GetHAR }, callback && callbackWrapper);
      },
  
      addRequestHeaders: function(headers)
      {
          return extensionServer.sendRequest({ command: commands.AddRequestHeaders, headers: headers, extensionId: window.location.hostname });
      }
  }
  
  /**
   * @constructor
   */
  function RequestImpl(id)
  {
      this._id = id;
  }
  
  RequestImpl.prototype = {
      getContent: function(callback)
      {
          function callbackWrapper(response)
          {
              callback(response.content, response.encoding);
          }
          extensionServer.sendRequest({ command: commands.GetRequestContent, id: this._id }, callback && callbackWrapper);
      }
  }
  
  /**
   * @constructor
   */
  function Panels()
  {
      var panels = {
          elements: new ElementsPanel(),
          sources: new SourcesPanel(),
      };
  
      function panelGetter(name)
      {
          return panels[name];
      }
      for (var panel in panels)
          this.__defineGetter__(panel, panelGetter.bind(null, panel));
      this.applyStyleSheet = function(styleSheet) { extensionServer.sendRequest({ command: commands.ApplyStyleSheet, styleSheet: styleSheet }); };
  }
  
  Panels.prototype = {
      create: function(title, icon, page, callback)
      {
          var id = "extension-panel-" + extensionServer.nextObjectId();
          var request = {
              command: commands.CreatePanel,
              id: id,
              title: title,
              icon: icon,
              page: page
          };
          extensionServer.sendRequest(request, callback && callback.bind(this, new ExtensionPanel(id)));
      },
  
      setOpenResourceHandler: function(callback)
      {
          var hadHandler = extensionServer.hasHandler(events.OpenResource);
  
          function callbackWrapper(message)
          {
              // Allow the panel to show itself when handling the event.
              userAction = true;
              try {
                  callback.call(null, new Resource(message.resource), message.lineNumber);
              } finally {
                  userAction = false;
              }
          }
  
          if (!callback)
              extensionServer.unregisterHandler(events.OpenResource);
          else
              extensionServer.registerHandler(events.OpenResource, callbackWrapper);
  
          // Only send command if we either removed an existing handler or added handler and had none before.
          if (hadHandler === !callback)
              extensionServer.sendRequest({ command: commands.SetOpenResourceHandler, "handlerPresent": !!callback });
      },
  
      openResource: function(url, lineNumber, callback)
      {
          extensionServer.sendRequest({ command: commands.OpenResource, "url": url, "lineNumber": lineNumber }, callback);
      },
  
      get SearchAction()
      {
          return apiPrivate.panels.SearchAction;
      }
  }
  
  /**
   * @constructor
   */
  function ExtensionViewImpl(id)
  {
      this._id = id;
  
      /**
       * @this {EventSinkImpl}
       */
      function dispatchShowEvent(message)
      {
          var frameIndex = message.arguments[0];
          if (typeof frameIndex === "number")
              this._fire(window.parent.frames[frameIndex]);
          else
              this._fire();
      }
      this.onShown = new EventSink(events.ViewShown + id, dispatchShowEvent);
      this.onHidden = new EventSink(events.ViewHidden + id);
  }
  
  /**
   * @constructor
   */
  function PanelWithSidebarImpl(hostPanelName)
  {
      this._hostPanelName = hostPanelName;
      this.onSelectionChanged = new EventSink(events.PanelObjectSelected + hostPanelName);
  }
  
  PanelWithSidebarImpl.prototype = {
      createSidebarPane: function(title, callback)
      {
          var id = "extension-sidebar-" + extensionServer.nextObjectId();
          var request = {
              command: commands.CreateSidebarPane,
              panel: this._hostPanelName,
              id: id,
              title: title
          };
          function callbackWrapper()
          {
              callback(new ExtensionSidebarPane(id));
          }
          extensionServer.sendRequest(request, callback && callbackWrapper);
      },
  
      __proto__: ExtensionViewImpl.prototype
  }
  
  /**
   * @constructor
   * @extends {PanelWithSidebar}
   */
  function ElementsPanel()
  {
      PanelWithSidebar.call(this, "elements");
  }
  
  /**
   * @constructor
   * @extends {PanelWithSidebar}
   */
  function SourcesPanel()
  {
      PanelWithSidebar.call(this, "sources");
  }
  
  /**
   * @constructor
   * @extends {ExtensionViewImpl}
   */
  function ExtensionPanelImpl(id)
  {
      ExtensionViewImpl.call(this, id);
      this.onSearch = new EventSink(events.PanelSearch + id);
  }
  
  ExtensionPanelImpl.prototype = {
      createStatusBarButton: function(iconPath, tooltipText, disabled)
      {
          var id = "button-" + extensionServer.nextObjectId();
          var request = {
              command: commands.CreateStatusBarButton,
              panel: this._id,
              id: id,
              icon: iconPath,
              tooltip: tooltipText,
              disabled: !!disabled
          };
          extensionServer.sendRequest(request);
          return new Button(id);
      },
  
      show: function()
      {
          if (!userAction)
              return;
  
          var request = {
              command: commands.ShowPanel,
              id: this._id
          };
          extensionServer.sendRequest(request);
      },
  
      __proto__: ExtensionViewImpl.prototype
  }
  
  /**
   * @constructor
   * @extends {ExtensionViewImpl}
   */
  function ExtensionSidebarPaneImpl(id)
  {
      ExtensionViewImpl.call(this, id);
  }
  
  ExtensionSidebarPaneImpl.prototype = {
      setHeight: function(height)
      {
          extensionServer.sendRequest({ command: commands.SetSidebarHeight, id: this._id, height: height });
      },
  
      setExpression: function(expression, rootTitle, evaluateOptions)
      {
          var request = {
              command: commands.SetSidebarContent,
              id: this._id,
              expression: expression,
              rootTitle: rootTitle,
              evaluateOnPage: true,
          };
          if (typeof evaluateOptions === "object")
              request.evaluateOptions = evaluateOptions;
          extensionServer.sendRequest(request, extractCallbackArgument(arguments));
      },
  
      setObject: function(jsonObject, rootTitle, callback)
      {
          extensionServer.sendRequest({ command: commands.SetSidebarContent, id: this._id, expression: jsonObject, rootTitle: rootTitle }, callback);
      },
  
      setPage: function(page)
      {
          extensionServer.sendRequest({ command: commands.SetSidebarPage, id: this._id, page: page });
      }
  }
  
  /**
   * @constructor
   */
  function ButtonImpl(id)
  {
      this._id = id;
      this.onClicked = new EventSink(events.ButtonClicked + id);
  }
  
  ButtonImpl.prototype = {
      update: function(iconPath, tooltipText, disabled)
      {
          var request = {
              command: commands.UpdateButton,
              id: this._id,
              icon: iconPath,
              tooltip: tooltipText,
              disabled: !!disabled
          };
          extensionServer.sendRequest(request);
      }
  };
  
  /**
   * @constructor
   */
  function Audits()
  {
  }
  
  Audits.prototype = {
      addCategory: function(displayName, resultCount)
      {
          var id = "extension-audit-category-" + extensionServer.nextObjectId();
          if (typeof resultCount !== "undefined")
              console.warn("Passing resultCount to audits.addCategory() is deprecated. Use AuditResult.updateProgress() instead.");
          extensionServer.sendRequest({ command: commands.AddAuditCategory, id: id, displayName: displayName, resultCount: resultCount });
          return new AuditCategory(id);
      }
  }
  
  /**
   * @constructor
   */
  function AuditCategoryImpl(id)
  {
      /**
       * @this {EventSinkImpl}
       */
      function dispatchAuditEvent(request)
      {
          var auditResult = new AuditResult(request.arguments[0]);
          try {
              this._fire(auditResult);
          } catch (e) {
              console.error("Uncaught exception in extension audit event handler: " + e);
              auditResult.done();
          }
      }
      this._id = id;
      this.onAuditStarted = new EventSink(events.AuditStarted + id, dispatchAuditEvent);
  }
  
  /**
   * @constructor
   */
  function AuditResultImpl(id)
  {
      this._id = id;
  
      this.createURL = this._nodeFactory.bind(null, "url");
      this.createSnippet = this._nodeFactory.bind(null, "snippet");
      this.createText = this._nodeFactory.bind(null, "text");
      this.createObject = this._nodeFactory.bind(null, "object");
      this.createNode = this._nodeFactory.bind(null, "node");
  }
  
  AuditResultImpl.prototype = {
      addResult: function(displayName, description, severity, details)
      {
          // shorthand for specifying details directly in addResult().
          if (details && !(details instanceof AuditResultNode))
              details = new AuditResultNode(details instanceof Array ? details : [details]);
  
          var request = {
              command: commands.AddAuditResult,
              resultId: this._id,
              displayName: displayName,
              description: description,
              severity: severity,
              details: details
          };
          extensionServer.sendRequest(request);
      },
  
      createResult: function()
      {
          return new AuditResultNode(Array.prototype.slice.call(arguments));
      },
  
      updateProgress: function(worked, totalWork)
      {
          extensionServer.sendRequest({ command: commands.UpdateAuditProgress, resultId: this._id, progress: worked / totalWork });
      },
  
      done: function()
      {
          extensionServer.sendRequest({ command: commands.StopAuditCategoryRun, resultId: this._id });
      },
  
      get Severity()
      {
          return apiPrivate.audits.Severity;
      },
  
      createResourceLink: function(url, lineNumber)
      {
          return {
              type: "resourceLink",
              arguments: [url, lineNumber && lineNumber - 1]
          };
      },
  
      _nodeFactory: function(type)
      {
          return {
              type: type,
              arguments: Array.prototype.slice.call(arguments, 1)
          };
      }
  }
  
  /**
   * @constructor
   */
  function AuditResultNode(contents)
  {
      this.contents = contents;
      this.children = [];
      this.expanded = false;
  }
  
  AuditResultNode.prototype = {
      addChild: function()
      {
          var node = new AuditResultNode(Array.prototype.slice.call(arguments));
          this.children.push(node);
          return node;
      }
  };
  
  /**
   * @constructor
   */
  function InspectedWindow()
  {
      /**
       * @this {EventSinkImpl}
       */
      function dispatchResourceEvent(message)
      {
          this._fire(new Resource(message.arguments[0]));
      }
  
      /**
       * @this {EventSinkImpl}
       */
      function dispatchResourceContentEvent(message)
      {
          this._fire(new Resource(message.arguments[0]), message.arguments[1]);
      }
  
      this.onResourceAdded = new EventSink(events.ResourceAdded, dispatchResourceEvent);
      this.onResourceContentCommitted = new EventSink(events.ResourceContentCommitted, dispatchResourceContentEvent);
  }
  
  InspectedWindow.prototype = {
      reload: function(optionsOrUserAgent)
      {
          var options = null;
          if (typeof optionsOrUserAgent === "object")
              options = optionsOrUserAgent;
          else if (typeof optionsOrUserAgent === "string") {
              options = { userAgent: optionsOrUserAgent };
              console.warn("Passing userAgent as string parameter to inspectedWindow.reload() is deprecated. " +
                           "Use inspectedWindow.reload({ userAgent: value}) instead.");
          }
          return extensionServer.sendRequest({ command: commands.Reload, options: options });
      },
  
      eval: function(expression, evaluateOptions)
      {
          var callback = extractCallbackArgument(arguments);
          function callbackWrapper(result)
          {
              if (result.isError || result.isException)
                  callback(undefined, result);
              else
                  callback(result.value);
          }
          var request = {
              command: commands.EvaluateOnInspectedPage,
              expression: expression
          };
          if (typeof evaluateOptions === "object")
              request.evaluateOptions = evaluateOptions;
          return extensionServer.sendRequest(request, callback && callbackWrapper);
      },
  
      getResources: function(callback)
      {
          function wrapResource(resourceData)
          {
              return new Resource(resourceData);
          }
          function callbackWrapper(resources)
          {
              callback(resources.map(wrapResource));
          }
          return extensionServer.sendRequest({ command: commands.GetPageResources }, callback && callbackWrapper);
      }
  }
  
  /**
   * @constructor
   */
  function ResourceImpl(resourceData)
  {
      this._url = resourceData.url
      this._type = resourceData.type;
  }
  
  ResourceImpl.prototype = {
      get url()
      {
          return this._url;
      },
  
      get type()
      {
          return this._type;
      },
  
      getContent: function(callback)
      {
          function callbackWrapper(response)
          {
              callback(response.content, response.encoding);
          }
  
          return extensionServer.sendRequest({ command: commands.GetResourceContent, url: this._url }, callback && callbackWrapper);
      },
  
      setContent: function(content, commit, callback)
      {
          return extensionServer.sendRequest({ command: commands.SetResourceContent, url: this._url, content: content, commit: commit }, callback);
      }
  }
  
  /**
   * @constructor
   */
  function TimelineImpl()
  {
      this.onEventRecorded = new EventSink(events.TimelineEventRecorded);
  }
  
  function forwardKeyboardEvent(event)
  {
      const Esc = "U+001B";
      // We only care about global hotkeys, not about random text
      if (!event.ctrlKey && !event.altKey && !event.metaKey && !/^F\d+$/.test(event.keyIdentifier) && event.keyIdentifier !== Esc)
          return;
      var request = {
          command: commands.ForwardKeyboardEvent,
          eventType: event.type,
          ctrlKey: event.ctrlKey,
          altKey: event.altKey,
          metaKey: event.metaKey,
          keyIdentifier: event.keyIdentifier,
          location: event.location
      };
      extensionServer.sendRequest(request);
  }
  
  document.addEventListener("keydown", forwardKeyboardEvent, false);
  document.addEventListener("keypress", forwardKeyboardEvent, false);
  
  /**
   * @constructor
   */
  function ExtensionServerClient()
  {
      this._callbacks = {};
      this._handlers = {};
      this._lastRequestId = 0;
      this._lastObjectId = 0;
  
      this.registerHandler("callback", this._onCallback.bind(this));
  
      var channel = new MessageChannel();
      this._port = channel.port1;
      this._port.addEventListener("message", this._onMessage.bind(this), false);
      this._port.start();
  
      window.parent.postMessage("registerExtension", [ channel.port2 ], "*");
  }
  
  ExtensionServerClient.prototype = {
      /**
       * @param {function()=} callback
       */
      sendRequest: function(message, callback)
      {
          if (typeof callback === "function")
              message.requestId = this._registerCallback(callback);
          return this._port.postMessage(message);
      },
  
      hasHandler: function(command)
      {
          return !!this._handlers[command];
      },
  
      registerHandler: function(command, handler)
      {
          this._handlers[command] = handler;
      },
  
      unregisterHandler: function(command)
      {
          delete this._handlers[command];
      },
  
      nextObjectId: function()
      {
          return injectedScriptId + "_" + ++this._lastObjectId;
      },
  
      _registerCallback: function(callback)
      {
          var id = ++this._lastRequestId;
          this._callbacks[id] = callback;
          return id;
      },
  
      _onCallback: function(request)
      {
          if (request.requestId in this._callbacks) {
              var callback = this._callbacks[request.requestId];
              delete this._callbacks[request.requestId];
              callback(request.result);
          }
      },
  
      _onMessage: function(event)
      {
          var request = event.data;
          var handler = this._handlers[request.command];
          if (handler)
              handler.call(this, request);
      }
  }
  
  function populateInterfaceClass(interface, implementation)
  {
      for (var member in implementation) {
          if (member.charAt(0) === "_")
              continue;
          var descriptor = null;
          // Traverse prototype chain until we find the owner.
          for (var owner = implementation; owner && !descriptor; owner = owner.__proto__)
              descriptor = Object.getOwnPropertyDescriptor(owner, member);
          if (!descriptor)
              continue;
          if (typeof descriptor.value === "function")
              interface[member] = descriptor.value.bind(implementation);
          else if (typeof descriptor.get === "function")
              interface.__defineGetter__(member, descriptor.get.bind(implementation));
          else
              Object.defineProperty(interface, member, descriptor);
      }
  }
  
  function declareInterfaceClass(implConstructor)
  {
      return function()
      {
          var impl = { __proto__: implConstructor.prototype };
          implConstructor.apply(impl, arguments);
          populateInterfaceClass(this, impl);
      }
  }
  
  function defineDeprecatedProperty(object, className, oldName, newName)
  {
      var warningGiven = false;
      function getter()
      {
          if (!warningGiven) {
              console.warn(className + "." + oldName + " is deprecated. Use " + className + "." + newName + " instead");
              warningGiven = true;
          }
          return object[newName];
      }
      object.__defineGetter__(oldName, getter);
  }
  
  function extractCallbackArgument(args)
  {
      var lastArgument = args[args.length - 1];
      return typeof lastArgument === "function" ? lastArgument : undefined;
  }
  
  var AuditCategory = declareInterfaceClass(AuditCategoryImpl);
  var AuditResult = declareInterfaceClass(AuditResultImpl);
  var Button = declareInterfaceClass(ButtonImpl);
  var EventSink = declareInterfaceClass(EventSinkImpl);
  var ExtensionPanel = declareInterfaceClass(ExtensionPanelImpl);
  var ExtensionSidebarPane = declareInterfaceClass(ExtensionSidebarPaneImpl);
  var PanelWithSidebar = declareInterfaceClass(PanelWithSidebarImpl);
  var Request = declareInterfaceClass(RequestImpl);
  var Resource = declareInterfaceClass(ResourceImpl);
  var Timeline = declareInterfaceClass(TimelineImpl);
  
  // extensionServer is a closure variable defined by the glue below -- make sure we fail if it's not there.
  if (!extensionServer)
      extensionServer = new ExtensionServerClient();
  
  return new InspectorExtensionAPI();
  }
  
  /**
   * @param {!ExtensionDescriptor} extensionInfo
   * @return {string}
   */
  function buildExtensionAPIInjectedScript(extensionInfo)
  {
      return "(function(injectedScriptId){ " +
          "var extensionServer;" +
          defineCommonExtensionSymbols.toString() + ";" +
          injectedExtensionAPI.toString() + ";" +
          buildPlatformExtensionAPI(extensionInfo) + ";" +
          "platformExtensionAPI(injectedExtensionAPI(injectedScriptId));" +
          "return {};" +
          "})";
  }
  /*
   * Copyright (C) 2011 Google Inc. 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.
   */
  
  function platformExtensionAPI(coreAPI)
  {
      function getTabId()
      {
          return tabId;
      }
      chrome = window.chrome || {};
      // Override chrome.devtools as a workaround for a error-throwing getter being exposed
      // in extension pages loaded into a non-extension process (only happens for remote client
      // extensions)
      var devtools_descriptor = Object.getOwnPropertyDescriptor(chrome, "devtools");
      if (!devtools_descriptor || devtools_descriptor.get)
          Object.defineProperty(chrome, "devtools", { value: {}, enumerable: true });
      // Only expose tabId on chrome.devtools.inspectedWindow, not webInspector.inspectedWindow.
      chrome.devtools.inspectedWindow = {};
      chrome.devtools.inspectedWindow.__defineGetter__("tabId", getTabId);
      chrome.devtools.inspectedWindow.__proto__ = coreAPI.inspectedWindow;
      chrome.devtools.network = coreAPI.network;
      chrome.devtools.panels = coreAPI.panels;
  
      // default to expose experimental APIs for now.
      if (extensionInfo.exposeExperimentalAPIs !== false) {
          chrome.experimental = chrome.experimental || {};
          chrome.experimental.devtools = chrome.experimental.devtools || {};
  
          var properties = Object.getOwnPropertyNames(coreAPI);
          for (var i = 0; i < properties.length; ++i) {
              var descriptor = Object.getOwnPropertyDescriptor(coreAPI, properties[i]);
              Object.defineProperty(chrome.experimental.devtools, properties[i], descriptor);
          }
          chrome.experimental.devtools.inspectedWindow = chrome.devtools.inspectedWindow;
      }
      if (extensionInfo.exposeWebInspectorNamespace)
          window.webInspector = coreAPI;
  }
  
          var tabId;
          var extensionInfo = {};
          var extensionServer;
          platformExtensionAPI(injectedExtensionAPI("remote-" + window.parent.frames.length));
      })();