text: // node-inspector version of on webkit-inspector/InspectorPageAgent.cpp
  var fs = require('fs'),
    path = require('path'),
    inherits = require('util').inherits,
    extend = require('util')._extend,
    EventEmitter = require('events').EventEmitter,
    async = require('async'),
    convert = require('./convert.js'),
    ScriptFileStorage = require('./ScriptFileStorage.js').ScriptFileStorage;
  
  
  /**
   * @param {{preload}} config
   * @param {DebuggerClient} debuggerClient
   * @param {ScriptManager} scriptManager
   * @constructor
   */
  function PageAgent(config, session) {
    this._session = session;
    this._debuggerClient = session.debuggerClient;
    this._scriptManager = session.scriptManager;
    this._scriptStorage = new ScriptFileStorage(config, session);
  }
  
  inherits(PageAgent, EventEmitter);
  
  extend(PageAgent.prototype, {
    enable: function(params, done) {
      done();
    },
  
    canEmulate: function(params, done) {
      done(null, { result: false });
    },
  
    canScreencast: function(params, done) {
      done(null, { result: false });
    },
  
    setTouchEmulationEnabled: function(params, done) {
      done();
    },
  
    getResourceTree: function(params, done) {
      var cb = function() {
        done.apply(null, arguments);
        this._session.emit('resource-tree-resolved');
      }.bind(this);
  
      if (this._debuggerClient.isConnected) {
        this._doGetResourceTree(params, cb);
      } else {
        this._debuggerClient.once(
          'connect',
          this._doGetResourceTree.bind(this, params, cb)
        );
      }
    },
  
    _doGetResourceTree: function(params, done) {
      var describeProgram = '[process.cwd(), ' +
        'process.mainModule ? process.mainModule.filename : process.argv[1]]';
  
      async.waterfall(
        [
          this._debuggerClient.evaluateGlobal
            .bind(this._debuggerClient, describeProgram),
          function(evaluateResult, cb) {
            cb(null, evaluateResult[0], evaluateResult[1]);
          },
          this._resolveMainAppScript.bind(this),
          this._getResourceTreeForAppScript.bind(this)
        ],
        done
      );
    },
  
    _resolveMainAppScript: function(startDirectory, mainAppScript, done) {
      this._scriptManager.mainAppScript = mainAppScript;
      if (mainAppScript == null) {
        // mainScriptFile is null when running in the REPL mode
        return done(null, startDirectory, mainAppScript);
      }
  
      fs.stat(mainAppScript, function(err, stat) {
        if (err && !/\.js$/.test(mainAppScript)) {
          mainAppScript += '.js';
        }
  
        if (process.platform !== 'win32') {
          this._scriptManager.realMainAppScript = mainAppScript;
          return done(null, startDirectory, mainAppScript);
        }
  
        var dirname = path.dirname(mainAppScript);
        var basename = path.basename(mainAppScript);
  
        fs.readdir(dirname, function(err, files) {
          var realBaseName = files.filter(function(filename) {
            return filename.toLowerCase() == basename.toLowerCase();
          })[0];
  
          mainAppScript = path.join(dirname, realBaseName);
          this._scriptManager.realMainAppScript = mainAppScript;
  
          return done(null, startDirectory, mainAppScript);
        }.bind(this));
      }.bind(this));
    },
  
    _getResourceTreeForAppScript: function(startDirectory, mainAppScript, done) {
      async.waterfall(
        [
          this._scriptStorage.findAllApplicationScripts
            .bind(this._scriptStorage, startDirectory, mainAppScript),
          this._createResourceTreeResponse.bind(this, mainAppScript)
        ],
        done
      );
    },
  
    _createResourceTreeResponse: function(mainAppScript, scriptFiles, done) {
      var resources = scriptFiles.map(function(filePath) {
        return {
          url: convert.v8NameToInspectorUrl(filePath),
          type: 'Script',
          mimeType: 'text/javascript'
        };
      });
  
      done(null, {
        frameTree: {
          frame: {
            id: 'nodeinspector-toplevel-frame',
            url: convert.v8NameToInspectorUrl(mainAppScript),
  
            // Front-end keeps a history of local modifications based
            // on loaderId. Ideally we should return such id that it remains
            // same as long as the the debugger process has the same content
            // of scripts and that changes when a new content is loaded.
            //
            // To keep things easy, we are returning an unique value for now.
            // This means that every reload of node-inspector page discards
            // the history of live-edit changes.
            //
            // Perhaps we can use PID as loaderId instead?
            loaderId: createUniqueLoaderId(),
            _isNodeInspectorScript: true
          },
          resources: resources
        }
      });
    },
  
    getResourceContent: function(params, done) {
      var scriptName = convert.inspectorUrlToV8Name(params.url,
        this._scriptManager.normalizeName.bind(this._scriptManager));
  
      if (scriptName === '') {
        // When running REPL, main application file is null
        // and node inspector returns an empty string to the front-end.
        // However, front-end still asks for resource content.
        // Let's return a descriptive comment then.
        var content = '// There is no main module loaded in node.\n' +
          '// This is expected when you are debugging node\'s interactive REPL console.';
  
        return process.nextTick(
          this._convertScriptSourceToGetResourceResponse.bind(this, content, done));
      }
  
      async.waterfall(
        [
          this._scriptStorage.load.bind(this._scriptStorage, scriptName),
          this._convertScriptSourceToGetResourceResponse.bind(this)
        ],
        done
      );
    },
  
    _convertScriptSourceToGetResourceResponse: function(source, done) {
      return done(null, {
        content: source
      });
    },
  
    reload: function(params, done) {
      // This is called when user press Cmd+R (F5?), do we want to perform an action on this?
      done();
    }
  });
  
  exports.PageAgent = PageAgent;
  
  function createUniqueLoaderId() {
    var randomPart = String(Math.random()).slice(2);
    return Date.now() + '-' + randomPart;
  }
  