<commit_before>'use strict';

var Promise = require("bluebird");
var EventEmitter = require("events").EventEmitter;
var Utils = require("cyclon.p2p-common");

function RTC(signallingService, channelFactory) {

    Utils.checkArguments(arguments, 2);

    this._signallingService = signallingService;
    this._channelFactory = channelFactory;
    this._channelListeners = {};
    this._connected = false;
}

RTC.prototype = Object.create(EventEmitter.prototype);

RTC.prototype.connect = function (metadataProviders, rooms) {
    var self = this;
    if(!this._connected) {
        this._signallingService.connect(metadataProviders, rooms);
        this._signallingService.on("offer", function (message) {
            self.handleOffer(message);
        });
        this.connected = true;
    }
};

RTC.prototype.createNewPointer = function (metaData) {
    return this._signallingService.createNewPointer(metaData);
};

RTC.prototype.getLocalId = function () {
    return this._signallingService.getLocalId();
};

RTC.prototype.onChannel = function (type, callback) {
    this._channelListeners[type] = callback;
};

RTC.prototype.openChannel = function (type, remotePointer) {
    var channel = this._channelFactory.createChannel(remotePointer);

    return channel.createOffer(type)
        .then(channel.sendOffer)
        .then(channel.startListeningForRemoteIceCandidates)
        .then(channel.waitForAnswer)
        .then(channel.handleAnswer)
        .then(channel.startSendingIceCandidates)
        .then(channel.waitForChannelToOpen)
        .then(channel.stopSendingIceCandidates)
        .catch(function (error) {
            // If an error occurs here, cleanup our attempted channel
            // establishment resources before continuing
            channel.close();
            throw error;
        });
};

RTC.prototype.handleOffer = function (offerMessage) {
    var self = this;
    var channelType = offerMessage.channelType;
    var listener = this._channelListeners[channelType];
    var remotePointer = offerMessage.sourcePointer;
    var correlationId = offerMessage.correlationId;

    self.emit("offerReceived", channelType, offerMessage.sourcePointer);

    if (listener) {
        var channel = this._channelFactory.createChannel(remotePointer, correlationId);

        channel.createAnswer(offerMessage.sessionDescription)
            .then(channel.startListeningForRemoteIceCandidates)
            .then(channel.sendAnswer)
            .then(channel.startSendingIceCandidates)
            .then(channel.waitForChannelEstablishment)
            .then(channel.waitForChannelToOpen)
            .then(channel.stopSendingIceCandidates)
            .then(listener)
            .catch(Promise.TimeoutError, function () {
                self.emit("incomingTimeout", channelType, offerMessage.sourcePointer);
            })
            .catch(function (e) {
                self.emit("incomingError", channelType, offerMessage.sourcePointer, e);
            })
            .finally(channel.close);
    }
    else {
        console.warn("No listener for channel type " + channelType + ", ignoring offer!");
    }
};

module.exports = RTC;
<commit_msg>Only automatically close connection if an error occurs<commit_after>'use strict';

var Promise = require("bluebird");
var EventEmitter = require("events").EventEmitter;
var Utils = require("cyclon.p2p-common");

function RTC(signallingService, channelFactory) {

    Utils.checkArguments(arguments, 2);

    this._signallingService = signallingService;
    this._channelFactory = channelFactory;
    this._channelListeners = {};
    this._connected = false;
}

RTC.prototype = Object.create(EventEmitter.prototype);

RTC.prototype.connect = function (metadataProviders, rooms) {
    var self = this;
    if (!this._connected) {
        this._signallingService.connect(metadataProviders, rooms);
        this._signallingService.on("offer", function (message) {
            self.handleOffer(message);
        });
        this.connected = true;
    }
};

RTC.prototype.createNewPointer = function (metaData) {
    return this._signallingService.createNewPointer(metaData);
};

RTC.prototype.getLocalId = function () {
    return this._signallingService.getLocalId();
};

RTC.prototype.onChannel = function (type, callback) {
    this._channelListeners[type] = callback;
};

RTC.prototype.openChannel = function (type, remotePointer) {
    var channel = this._channelFactory.createChannel(remotePointer);

    return channel.createOffer(type)
        .then(channel.sendOffer)
        .then(channel.startListeningForRemoteIceCandidates)
        .then(channel.waitForAnswer)
        .then(channel.handleAnswer)
        .then(channel.startSendingIceCandidates)
        .then(channel.waitForChannelToOpen)
        .then(channel.stopSendingIceCandidates)
        .catch(function (error) {
            // If an error occurs here, cleanup our attempted channel
            // establishment resources before continuing
            channel.close();
            throw error;
        });
};

RTC.prototype.handleOffer = function (offerMessage) {
    var self = this;
    var channelType = offerMessage.channelType;
    var listener = this._channelListeners[channelType];
    var remotePointer = offerMessage.sourcePointer;
    var correlationId = offerMessage.correlationId;

    self.emit("offerReceived", channelType, offerMessage.sourcePointer);

    if (listener) {
        var channel = this._channelFactory.createChannel(remotePointer, correlationId);

        channel.createAnswer(offerMessage.sessionDescription)
            .then(channel.startListeningForRemoteIceCandidates)
            .then(channel.sendAnswer)
            .then(channel.startSendingIceCandidates)
            .then(channel.waitForChannelEstablishment)
            .then(channel.waitForChannelToOpen)
            .then(channel.stopSendingIceCandidates)
            .then(listener)
            .catch(Promise.TimeoutError, function () {
                self.emit("incomingTimeout", channelType, offerMessage.sourcePointer);
                channel.close();
            })
            .catch(function (e) {
                self.emit("incomingError", channelType, offerMessage.sourcePointer, e);
                channel.close();
            });
    }
    else {
        console.warn("No listener for channel type " + channelType + ", ignoring offer!");
    }
};

module.exports = RTC;
<|endoftext|>


<commit_before>(function(express, jc, path, http, https, fs){
  'use strict';

  var Run = function(argv, app){
    var configPath = (typeof argv[1] === 'undefined' ?
                      'iora.json' :
                      (path.extname(argv[1]) !== '') ?
                       argv[1] :
                       argv[1] + '.json'
                     );

    var config = jc.read(path.resolve(configPath));

    if (typeof config.http !== 'undefined' && !config.http.disabled) {
      http.Server(app).listen(
        config.http.port || 80,
        config.host || config.http.host || '0.0.0.0',
        function(){ console.log("test") }
      );
    }

    if (typeof config.https !== 'undefined' && !config.https.disabled) {
      var fetchedData = {};
      for (var key in config.https.options) {
        if (typeof config.https.options[key] === 'string') {
          fs.readFile(config.https.options[key], function(err, data){
            if (!err) {
              fetchedData[key] = data;
            } else {
              fetchedData[key] = config.https.options[key];
            }
          });
        }
      }
      https.Server(fetchedData, app).listen(
        config.https.port || 80,
        config.host || config.https.host || '0.0.0.0'
      );
    }
  };

  module.exports = exports = Run;
})(require('express'),
   require('json-config-reader'),
   require('path'),
   require('http'),
   require('https'),
   require('fs'));
<commit_msg>Minor changes<commit_after>(function(express, jc, path, http, https, fs){
  'use strict';

  var Run = function(argv, app){
    var configPath = (typeof argv[1] === 'undefined' ?
                      'iora.json' :
                      (path.extname(argv[1]) !== '') ?
                       argv[1] :
                       argv[1] + '.json'
                     );

    var config = jc.read(path.resolve(configPath));

    if (typeof config.http !== 'undefined' && !config.http.disabled) {
      http.Server(app).listen(
        config.http.port || 80,
        config.host || config.http.host || '0.0.0.0',
        function(){ console.log('test'); }
      );
    }

    if (typeof config.https !== 'undefined' && !config.https.disabled) {
      var fetchedData = {};
      for (var key in config.https.options) {
        if (typeof config.https.options[key] === 'string') {
          fs.readFile(config.https.options[key], function(err, data){
            if (!err) {
              fetchedData[key] = data;
            } else {
              fetchedData[key] = config.https.options[key];
            }
          });
        }
      }
      https.Server(fetchedData, app).listen(
        config.https.port || 80,
        config.host || config.https.host || '0.0.0.0'
      );
    }
  };

  module.exports = exports = Run;
})(require('express'),
   require('json-config-reader'),
   require('path'),
   require('http'),
   require('https'),
   require('fs'));
<|endoftext|>


<commit_before>"use strict";

var _ = require('underscore');
var redis = require('redis');
var async = require('async');

function Run() {

  var self = this;

  var Node, node, prefix;

  this.running = false;
  this.stoppedCallback = null;

  if(!process.argv[2]){
    // needs to be run as a child process
    console.log('no node definition provided');
    return;
  }

  // node definition
  this.node = JSON.parse(process.argv[2]);

  if(!process.argv[3]){
    // needs to be run as a child process
    console.log('no options provided');
    return;
  }

  // straw options from topology
  this.opts = JSON.parse(process.argv[3]);

  prefix = this.opts.redis.prefix + ':';

  // one redis client for run.js to use to communicate with the rest
  // of the topollgy, and one for the node to use however it wants.

  this.clients = {
    io: false,
    node: false
  };

  // catching errors here means node-redis will try to reconnect if
  // the Redis server has issues

  this.clients.io = redis.createClient(this.opts.redis.port, this.opts.redis.host);

  this.clients.io.on('error', function(err){
    console.log(err, 'run.js io client');
  });

  this.clients.node = redis.createClient(this.opts.redis.port, this.opts.redis.host);

  this.clients.node.on('error', function(err){
    console.log(err, 'run.js node client');
  });

  // give the node a redis client to use with if it needs one. pass
  // in the prefix so it can keep it's keys namespaced.

  this.node.redis = {
    client: this.clients.node,
    prefix: this.opts.redis.prefix
  };

  this.statsKey = this.opts.redis.prefix + ':stats:' + this.node.id;

  // inbound pipes will push to this redis channel. process must
  // execute the callback to signal it's ready to process another
  // message

  this.lkeys = false;

  if(this.node.input){
    this.lkeys = [];
   this.node.input.forEach(function(x){
      self.lkeys.push(prefix + x);
    });
    // last element is polling timeout for Redis (1 second)
    this.lkeys.push(1);
  }

  // Node is the worker node to run -- this has been created with
  // straw.node({def}) and exported

  Node = require(this.node.node);

  // create an instance of the worker node, passing in pipe names,
  // redis client, options

  node = new Node(this.node);

  // when node emits a message distribute it to the appropriate pipes

  node.on('message', function(data){

    var outlet, message;

    if(!data.hasOwnProperty('message') || !data.message){
      // no message, nothing to do
      return false;
    }

    message = data.message;

    outlet = false;

    if(data.hasOwnProperty('outlet') && data.outlet){
      outlet = data.outlet;
    }

    if (!outlet) {
      // no outlet specified - send out the default(s)
      self.node.output.forEach(function(x){
        self.clients.io.lpush(prefix + x, JSON.stringify(message) );
      });
      self.clients.io.incr(self.statsKey + ':output');
      return;
    }

    if (self.node.outputs.hasOwnProperty(outlet)) {
      _.each(self.node.outputs[outlet], function(x){
        self.clients.io.lpush(prefix + x, JSON.stringify(message) );
      });
      self.clients.io.incr(self.statsKey + ':outputs:' + outlet);
    }
  });

  // get the node to set itself up
  node.initialize(this.node, function(){
    process.send('INITIALIZED');
  });

  // reset the nodes's stats
  this.clients.io.set(this.statsKey + ':input', 0);
  this.clients.io.set(this.statsKey + ':output', 0);

  _.each(this.node.outputs, function(x, id){
    self.clients.io.set(self.statsKey + ':outputs:' + id, 0);
  });

  // receive command from controlling process (runner.js)
  process.on('message', function(data){

    if ( data === 'START' ) {
      if(self.running){
        // already running
        return;
      }
      process.send('STARTING');
      self.start();
    }

    if ( data === 'STOP' ) {
      // tell the node to stop any self-managed processing it does
      // when the current message is finished processsing or long-poll
      // stops on the queue then we're done
      process.send('STOPPING');
      async.parallel([
        node.stop,
        self.stop
      ], function(){
        self.stoppedCallback = null;
        process.send('STOPPED');
      });
    }

    if ( data === 'QUIT' ) {
      process.send('QUITTING');
      async.parallel([
        node.stop,
        self.stop
      ], function(){
        self.stoppedCallback = null;
        self.clients.io.quit();
        self.clients.node.quit();
        process.send('STOPPED');
        process.send('QUIT');
        process.exit(0);
      });
    }

  });

  this.stop = function(done){

    if(!self.running){
      return done();
    }

    if(!self.lkeys){
      // no polling to do -- we're done
      self.running = false;
      return done();
    }

    self.stoppedCallback = function(){
      done();
    };

    // let brpop know we want to stop
    self.running = false;
  };

  this.start = function(){
    self.running = true;
    // get the node to start any self-managed processing it does
    node.start(function() {
      process.send('STARTED');
    });
    // start consuming messages from inbound pipes connected to this
    // node

    // if there is at least one input (last element in lkeys is Redis
    // polling timeout, so length > 1) then star polling
    // start pulling data from the pipes
    self.brpop();
  };

  this.brpop = function() {
    // lkeys will be false if no inbound pipes
    if(!self.lkeys){
      return;
    }
    if(!self.running){
      if (self.stoppedCallback){
        return self.stoppedCallback();
      }
      return;
    }
    self.clients.io.brpop(self.lkeys, function(err, reply){
      if(err){
        // console.log('info', err);
        // error -- hold off for a second then try again
        setTimeout(self.brpop, 1000);
        return;
      }
      if (!reply){
        // brpop timed out
        self.brpop();
        return;
      }
      var msg = false;
      if(!err){
        try {
          msg = JSON.parse(reply[1]);
        } catch (e) {
          // bad json
          self.brpop();
          return;
        }
        self.clients.io.incr(self.statsKey + ':input');
        node.process(msg, function(err){
          self.brpop();
        });
      }
    });
  };

}

module.exports = new Run();
<commit_msg>To execute node stop method in proper context<commit_after>"use strict";

var _ = require('underscore');
var redis = require('redis');
var async = require('async');

function Run() {

  var self = this;

  var Node, node, prefix;

  this.running = false;
  this.stoppedCallback = null;

  if(!process.argv[2]){
    // needs to be run as a child process
    console.log('no node definition provided');
    return;
  }

  // node definition
  this.node = JSON.parse(process.argv[2]);

  if(!process.argv[3]){
    // needs to be run as a child process
    console.log('no options provided');
    return;
  }

  // straw options from topology
  this.opts = JSON.parse(process.argv[3]);

  prefix = this.opts.redis.prefix + ':';

  // one redis client for run.js to use to communicate with the rest
  // of the topollgy, and one for the node to use however it wants.

  this.clients = {
    io: false,
    node: false
  };

  // catching errors here means node-redis will try to reconnect if
  // the Redis server has issues

  this.clients.io = redis.createClient(this.opts.redis.port, this.opts.redis.host);

  this.clients.io.on('error', function(err){
    console.log(err, 'run.js io client');
  });

  this.clients.node = redis.createClient(this.opts.redis.port, this.opts.redis.host);

  this.clients.node.on('error', function(err){
    console.log(err, 'run.js node client');
  });

  // give the node a redis client to use with if it needs one. pass
  // in the prefix so it can keep it's keys namespaced.

  this.node.redis = {
    client: this.clients.node,
    prefix: this.opts.redis.prefix
  };

  this.statsKey = this.opts.redis.prefix + ':stats:' + this.node.id;

  // inbound pipes will push to this redis channel. process must
  // execute the callback to signal it's ready to process another
  // message

  this.lkeys = false;

  if(this.node.input){
    this.lkeys = [];
   this.node.input.forEach(function(x){
      self.lkeys.push(prefix + x);
    });
    // last element is polling timeout for Redis (1 second)
    this.lkeys.push(1);
  }

  // Node is the worker node to run -- this has been created with
  // straw.node({def}) and exported

  Node = require(this.node.node);

  // create an instance of the worker node, passing in pipe names,
  // redis client, options

  node = new Node(this.node);

  // when node emits a message distribute it to the appropriate pipes

  node.on('message', function(data){

    var outlet, message;

    if(!data.hasOwnProperty('message') || !data.message){
      // no message, nothing to do
      return false;
    }

    message = data.message;

    outlet = false;

    if(data.hasOwnProperty('outlet') && data.outlet){
      outlet = data.outlet;
    }

    if (!outlet) {
      // no outlet specified - send out the default(s)
      self.node.output.forEach(function(x){
        self.clients.io.lpush(prefix + x, JSON.stringify(message) );
      });
      self.clients.io.incr(self.statsKey + ':output');
      return;
    }

    if (self.node.outputs.hasOwnProperty(outlet)) {
      _.each(self.node.outputs[outlet], function(x){
        self.clients.io.lpush(prefix + x, JSON.stringify(message) );
      });
      self.clients.io.incr(self.statsKey + ':outputs:' + outlet);
    }
  });

  // get the node to set itself up
  node.initialize(this.node, function(){
    process.send('INITIALIZED');
  });

  // reset the nodes's stats
  this.clients.io.set(this.statsKey + ':input', 0);
  this.clients.io.set(this.statsKey + ':output', 0);

  _.each(this.node.outputs, function(x, id){
    self.clients.io.set(self.statsKey + ':outputs:' + id, 0);
  });

  // receive command from controlling process (runner.js)
  process.on('message', function(data){

    if ( data === 'START' ) {
      if(self.running){
        // already running
        return;
      }
      process.send('STARTING');
      self.start();
    }

    if ( data === 'STOP' ) {
      // tell the node to stop any self-managed processing it does
      // when the current message is finished processsing or long-poll
      // stops on the queue then we're done
      process.send('STOPPING');
      async.parallel([
        node.stop.bind(node),
        self.stop
      ], function(){
        self.stoppedCallback = null;
        process.send('STOPPED');
      });
    }

    if ( data === 'QUIT' ) {
      process.send('QUITTING');
      async.parallel([
        node.stop,
        self.stop
      ], function(){
        self.stoppedCallback = null;
        self.clients.io.quit();
        self.clients.node.quit();
        process.send('STOPPED');
        process.send('QUIT');
        process.exit(0);
      });
    }

  });

  this.stop = function(done){

    if(!self.running){
      return done();
    }

    if(!self.lkeys){
      // no polling to do -- we're done
      self.running = false;
      return done();
    }

    self.stoppedCallback = function(){
      done();
    };

    // let brpop know we want to stop
    self.running = false;
  };

  this.start = function(){
    self.running = true;
    // get the node to start any self-managed processing it does
    node.start(function() {
      process.send('STARTED');
    });
    // start consuming messages from inbound pipes connected to this
    // node

    // if there is at least one input (last element in lkeys is Redis
    // polling timeout, so length > 1) then star polling
    // start pulling data from the pipes
    self.brpop();
  };

  this.brpop = function() {
    // lkeys will be false if no inbound pipes
    if(!self.lkeys){
      return;
    }
    if(!self.running){
      if (self.stoppedCallback){
        return self.stoppedCallback();
      }
      return;
    }
    self.clients.io.brpop(self.lkeys, function(err, reply){
      if(err){
        // console.log('info', err);
        // error -- hold off for a second then try again
        setTimeout(self.brpop, 1000);
        return;
      }
      if (!reply){
        // brpop timed out
        self.brpop();
        return;
      }
      var msg = false;
      if(!err){
        try {
          msg = JSON.parse(reply[1]);
        } catch (e) {
          // bad json
          self.brpop();
          return;
        }
        self.clients.io.incr(self.statsKey + ':input');
        node.process(msg, function(err){
          self.brpop();
        });
      }
    });
  };

}

module.exports = new Run();
<|endoftext|>


<commit_before>
var sbCaptureOptions = {

    param: null,

    init: function() {
        if (window.arguments) {
            // opened from capture detail
            this.param = window.arguments[0];
        } else {
            // opened for default capture options
            // this.param.item = undefined
            this.param = {
                option: {},
                result: 1,
            };
        }

        // load from preference
        document.getElementById("sbDetailOptionImages").checked = sbCommonUtils.getPref("capture.default.images", true);
        document.getElementById("sbDetailOptionMedia").checked = sbCommonUtils.getPref("capture.default.media", true);
        document.getElementById("sbDetailOptionFonts").checked = sbCommonUtils.getPref("capture.default.fonts", true);
        document.getElementById("sbDetailOptionFrames").checked = sbCommonUtils.getPref("capture.default.frames", true);
        document.getElementById("sbDetailOptionStyles").checked = sbCommonUtils.getPref("capture.default.styles", true);
        document.getElementById("sbDetailOptionScript").checked = sbCommonUtils.getPref("capture.default.script", false);
        document.getElementById("sbDetailOptionAsHtml").checked = sbCommonUtils.getPref("capture.default.fileAsHtml", false);
        document.getElementById("sbDetailOptionSaveDataURI").checked = sbCommonUtils.getPref("capture.default.saveDataUri", false);
        document.getElementById("sbDetailDownLinkMethod").value = sbCommonUtils.getPref("capture.default.downLinkMethod", 0);
        document.getElementById("sbDetailDownLinkFilter").value = sbCommonUtils.getPref("capture.default.downLinkFilter", "");
        document.getElementById("sbDetailInDepth").value = sbCommonUtils.getPref("capture.default.inDepthLevels", 0);

        // init UI
        this.updateScriptWarning();
        if (this.param.item) {
            document.documentElement.getButton("accept").label = sbCommonUtils.lang("CAPTURE_OK_BUTTON");
            this.fillTitleList();
            if ( this.param.context == "capture-again" || this.param.context == "capture-again-deep" ) {
                document.getElementById("sbDetailFolderRow").collapsed = true;
                document.getElementById("sbDetailCommentRow").collapsed = true;
                if ( this.param.context == "capture-again-deep" ) {
                    document.getElementById("sbDetailInDepthBox").collapsed = true;
                }
                document.getElementById("sbDetailWarnAboutRenew").hidden = false;
            } else {
                sbFolderSelector.init();
                document.getElementById("sbDetailComment").value = this.param.item.comment.replace(/ __BR__ /g, "\n");
            }
        } else {
            document.getElementById("sbDetailTabs").selectedIndex = 1;
            document.getElementById("sbDetailTabGeneral").collapsed = true;
            document.getElementById("sbDetailInDepthBox").collapsed = true;
        }
    },

    fillTitleList: function() {
        var isPartial = this.param.titles.length > 1;
        var list = document.getElementById("sbDetailTitle");
        if ( this.param.context == "capture-again" ) {
            var res = sbCommonUtils.RDF.GetResource("urn:scrapbook:item" + this.param.item.id);
            list.appendItem(sbDataSource.getProperty(res, "title"));
        }
        for ( var i = 0; i < this.param.titles.length; i++ ) {
            list.appendItem(this.param.titles[i]);
            if ( i == 0 && this.param.titles.length > 1 ) list.firstChild.appendChild(document.createElement("menuseparator"));
        }
        list.selectedIndex = isPartial ? 2 : 0;
    },

    updateScriptWarning: function() {
        document.getElementById("sbDetailWarnAboutScript").hidden = !document.getElementById("sbDetailOptionScript").checked;
    },

    resetDownLinkFilters: function() {
        var _filter = document.getElementById("sbDetailDownLinkFilter").value;
        sbCommonUtils.resetPref("capture.default.downLinkFilter");
        document.getElementById("sbDetailDownLinkFilter").value = sbCommonUtils.getPref("capture.default.downLinkFilter", "");
        sbCommonUtils.setPref("capture.default.downLinkFilter", _filter);
    },

    accept: function() {
        // set return values
        if (this.param.item) {
            this.param.item.title = document.getElementById("sbDetailTitle").value;
            this.param.item.comment = sbCommonUtils.escapeComment(document.getElementById("sbDetailComment").value);
        }
        this.param.option["images"] = document.getElementById("sbDetailOptionImages").checked;
        this.param.option["media"] = document.getElementById("sbDetailOptionMedia").checked;
        this.param.option["fonts"] = document.getElementById("sbDetailOptionFonts").checked;
        this.param.option["frames"] = document.getElementById("sbDetailOptionFrames").checked;
        this.param.option["styles"] = document.getElementById("sbDetailOptionStyles").checked;
        this.param.option["script"] = document.getElementById("sbDetailOptionScript").checked;
        this.param.option["fileAsHtml"] = document.getElementById("sbDetailOptionAsHtml").checked;
        this.param.option["saveDataUri"] = document.getElementById("sbDetailOptionSaveDataURI").checked;
        this.param.option["downLinkMethod"] = parseInt("0" + document.getElementById("sbDetailDownLinkMethod").value, 10);
        this.param.option["downLinkFilter"] = document.getElementById("sbDetailDownLinkFilter").value;
        this.param.option["inDepth"] = parseInt(document.getElementById("sbDetailInDepth").value, 10);

        // save to preference
        sbCommonUtils.setPref("capture.default.images", this.param.option["images"]);
        sbCommonUtils.setPref("capture.default.media", this.param.option["media"]);
        sbCommonUtils.setPref("capture.default.fonts", this.param.option["fonts"]);
        sbCommonUtils.setPref("capture.default.frames", this.param.option["frames"]);
        sbCommonUtils.setPref("capture.default.styles", this.param.option["styles"]);
        sbCommonUtils.setPref("capture.default.script", this.param.option["script"]);
        sbCommonUtils.setPref("capture.default.fileAsHtml", this.param.option["fileAsHtml"]);
        sbCommonUtils.setPref("capture.default.saveDataUri", this.param.option["saveDataUri"]);
        sbCommonUtils.setPref("capture.default.downLinkMethod", this.param.option["downLinkMethod"]);
        sbCommonUtils.setPref("capture.default.downLinkFilter", this.param.option["downLinkFilter"]);
        sbCommonUtils.setPref("capture.default.inDepthLevels", this.param.option["inDepth"]);

        // post-fix for special cases
        if ( this.param.context === "capture-again-deep" ) {
            this.param.option["inDepth"] = 0;
        }

        // check for regex error
        var errors = [];
        this.param.option["downLinkFilter"].split(/[\r\n]/).forEach(function (srcLine, index) {
            if (srcLine.charAt(0) === "#") return;
            var line = srcLine.trim();
            if (line === "") return;
            try {
                new RegExp("^(?:" + line + ")$", "i");
            } catch (ex) {
                line =  sbCommonUtils.lang("ERR_CAPTURE_DOWNLINKFILTER_LINE", index+1, srcLine);
                errors.push(line);
            }
        });
        if (errors.length) {
            var button = sbCommonUtils.PROMPT.STD_YES_NO_BUTTONS;
            var text = sbCommonUtils.lang("ERR_CAPTURE_DOWNLINKFILTER", errors.join("\n\n"));
            // yes => 0, no => 1, close => 1
            return sbCommonUtils.PROMPT.confirmEx(null, "[ScrapBook]", text, button, null, null, null, null, {});
        }

        return true;
    },

    cancel: function() {
        this.param.result = 0;
    },

};

var sbFolderSelector = {

    get MENU_LIST()  { return document.getElementById("sbFolderList"); },
    get MENU_POPUP() { return document.getElementById("sbFolderPopup"); },

    nest: 0,

    init: function() {
        if ( !sbCaptureOptions.param.resURI ) sbCaptureOptions.param.resURI = "urn:scrapbook:root";
        this.refresh(sbCaptureOptions.param.resURI);
    },

    refresh: function(aResID) {
        if ( document.getElementById(aResID) == null ) {
            this.nest = 0;
            this.clear();
            this.processRecent();
            this.processRoot();
            this.processRecursive(sbCommonUtils.RDF.GetResource("urn:scrapbook:root"));
        }
        this.MENU_LIST.selectedItem = document.getElementById(aResID);
        this.MENU_LIST.disabled = false;
    },

    clear: function() {
        var oldItems = this.MENU_POPUP.childNodes;
        for ( var i = oldItems.length - 1; i >= 0; i-- ) {
            this.MENU_POPUP.removeChild(oldItems[i]);
        }
    },

    fill: function(aID, aTitle) {
        var item = document.createElement("menuitem");
        item.setAttribute("id",    aID);
        item.setAttribute("label", aTitle);
        item.setAttribute("nest", this.nest);
        item.setAttribute("class", "menuitem-iconic folder-icon");
        item.setAttribute("style", "padding-left:" + (20 * this.nest + 3) + "px;");
        this.MENU_POPUP.appendChild(item);
    },

    processRoot: function() {
        this.fill("urn:scrapbook:root", sbCommonUtils.lang("ROOT_FOLDER"));
        this.MENU_POPUP.appendChild(document.createElement("menuseparator"));
    },

    processRecent: function() {
        var ids = sbCommonUtils.getPref("ui.folderList", "");
        ids = ids ? ids.split("|") : [];
        var shownItems = 0;
        var maxEntries = sbCommonUtils.getPref("ui.folderList.maxEntries", 5);
        for (var i = 0; i < ids.length && shownItems < maxEntries; i++) {
            if (!sbCommonUtils.validateID(ids[i])) continue;
            var res = sbCommonUtils.RDF.GetResource("urn:scrapbook:item" + ids[i]);
            if (!sbDataSource.exists(res)) continue;
            this.fill(res.Value, sbDataSource.getProperty(res, "title"));
            shownItems++;
        }
        if (shownItems > 0)
            this.MENU_POPUP.appendChild(document.createElement("menuseparator"));
    },

    processRecursive: function(aContRes) {
        this.nest++;
        var resList = sbDataSource.flattenResources(aContRes, 1, false);
        resList.shift();
        for ( var i = 0; i < resList.length; i++ ) {
            var res = resList[i];
            this.fill(res.Value, sbDataSource.getProperty(res, "title"));
            this.processRecursive(res);
        }
        this.nest--;
    },

    onChange: function(aResURI) {
        sbCaptureOptions.param.resURI = aResURI;
        sbCaptureOptions.param.result = 2;
    },

    onMiddleClick: function() {
        this.MENU_LIST.selectedIndex = 0;
        this.onChange(this.MENU_LIST.selectedItem.id);
    },

    pick: function() {
        var ret = {};
        window.openDialog('chrome://scrapbook/content/folderPicker.xul','','modal,chrome,centerscreen,resizable=yes', ret, sbCaptureOptions.param.resURI);
        if ( ret.resource ) {
            this.refresh(ret.resource.Value);
            this.onChange(ret.resource.Value);
        }
    },

};

<commit_msg>capture: don't sync inDepth if capture-again-deep<commit_after>
var sbCaptureOptions = {

    param: null,

    init: function() {
        if (window.arguments) {
            // opened from capture detail
            this.param = window.arguments[0];
        } else {
            // opened for default capture options
            // this.param.item = undefined
            this.param = {
                option: {},
                result: 1,
            };
        }

        // load from preference
        document.getElementById("sbDetailOptionImages").checked = sbCommonUtils.getPref("capture.default.images", true);
        document.getElementById("sbDetailOptionMedia").checked = sbCommonUtils.getPref("capture.default.media", true);
        document.getElementById("sbDetailOptionFonts").checked = sbCommonUtils.getPref("capture.default.fonts", true);
        document.getElementById("sbDetailOptionFrames").checked = sbCommonUtils.getPref("capture.default.frames", true);
        document.getElementById("sbDetailOptionStyles").checked = sbCommonUtils.getPref("capture.default.styles", true);
        document.getElementById("sbDetailOptionScript").checked = sbCommonUtils.getPref("capture.default.script", false);
        document.getElementById("sbDetailOptionAsHtml").checked = sbCommonUtils.getPref("capture.default.fileAsHtml", false);
        document.getElementById("sbDetailOptionSaveDataURI").checked = sbCommonUtils.getPref("capture.default.saveDataUri", false);
        document.getElementById("sbDetailDownLinkMethod").value = sbCommonUtils.getPref("capture.default.downLinkMethod", 0);
        document.getElementById("sbDetailDownLinkFilter").value = sbCommonUtils.getPref("capture.default.downLinkFilter", "");
        if ( this.param.context !== "capture-again-deep" ) {
            document.getElementById("sbDetailInDepth").value = sbCommonUtils.getPref("capture.default.inDepthLevels", 0);
        }

        // init UI
        this.updateScriptWarning();
        if (this.param.item) {
            document.documentElement.getButton("accept").label = sbCommonUtils.lang("CAPTURE_OK_BUTTON");
            this.fillTitleList();
            if ( this.param.context == "capture-again" || this.param.context == "capture-again-deep" ) {
                document.getElementById("sbDetailFolderRow").collapsed = true;
                document.getElementById("sbDetailCommentRow").collapsed = true;
                if ( this.param.context == "capture-again-deep" ) {
                    document.getElementById("sbDetailInDepthBox").collapsed = true;
                }
                document.getElementById("sbDetailWarnAboutRenew").hidden = false;
            } else {
                sbFolderSelector.init();
                document.getElementById("sbDetailComment").value = this.param.item.comment.replace(/ __BR__ /g, "\n");
            }
        } else {
            document.getElementById("sbDetailTabs").selectedIndex = 1;
            document.getElementById("sbDetailTabGeneral").collapsed = true;
            document.getElementById("sbDetailInDepthBox").collapsed = true;
        }
    },

    fillTitleList: function() {
        var isPartial = this.param.titles.length > 1;
        var list = document.getElementById("sbDetailTitle");
        if ( this.param.context == "capture-again" ) {
            var res = sbCommonUtils.RDF.GetResource("urn:scrapbook:item" + this.param.item.id);
            list.appendItem(sbDataSource.getProperty(res, "title"));
        }
        for ( var i = 0; i < this.param.titles.length; i++ ) {
            list.appendItem(this.param.titles[i]);
            if ( i == 0 && this.param.titles.length > 1 ) list.firstChild.appendChild(document.createElement("menuseparator"));
        }
        list.selectedIndex = isPartial ? 2 : 0;
    },

    updateScriptWarning: function() {
        document.getElementById("sbDetailWarnAboutScript").hidden = !document.getElementById("sbDetailOptionScript").checked;
    },

    resetDownLinkFilters: function() {
        var _filter = document.getElementById("sbDetailDownLinkFilter").value;
        sbCommonUtils.resetPref("capture.default.downLinkFilter");
        document.getElementById("sbDetailDownLinkFilter").value = sbCommonUtils.getPref("capture.default.downLinkFilter", "");
        sbCommonUtils.setPref("capture.default.downLinkFilter", _filter);
    },

    accept: function() {
        // set return values
        if (this.param.item) {
            this.param.item.title = document.getElementById("sbDetailTitle").value;
            this.param.item.comment = sbCommonUtils.escapeComment(document.getElementById("sbDetailComment").value);
        }
        this.param.option["images"] = document.getElementById("sbDetailOptionImages").checked;
        this.param.option["media"] = document.getElementById("sbDetailOptionMedia").checked;
        this.param.option["fonts"] = document.getElementById("sbDetailOptionFonts").checked;
        this.param.option["frames"] = document.getElementById("sbDetailOptionFrames").checked;
        this.param.option["styles"] = document.getElementById("sbDetailOptionStyles").checked;
        this.param.option["script"] = document.getElementById("sbDetailOptionScript").checked;
        this.param.option["fileAsHtml"] = document.getElementById("sbDetailOptionAsHtml").checked;
        this.param.option["saveDataUri"] = document.getElementById("sbDetailOptionSaveDataURI").checked;
        this.param.option["downLinkMethod"] = parseInt("0" + document.getElementById("sbDetailDownLinkMethod").value, 10);
        this.param.option["downLinkFilter"] = document.getElementById("sbDetailDownLinkFilter").value;
        if ( this.param.context !== "capture-again-deep" ) {
            this.param.option["inDepth"] = parseInt(document.getElementById("sbDetailInDepth").value, 10);
        }

        // save to preference
        sbCommonUtils.setPref("capture.default.images", this.param.option["images"]);
        sbCommonUtils.setPref("capture.default.media", this.param.option["media"]);
        sbCommonUtils.setPref("capture.default.fonts", this.param.option["fonts"]);
        sbCommonUtils.setPref("capture.default.frames", this.param.option["frames"]);
        sbCommonUtils.setPref("capture.default.styles", this.param.option["styles"]);
        sbCommonUtils.setPref("capture.default.script", this.param.option["script"]);
        sbCommonUtils.setPref("capture.default.fileAsHtml", this.param.option["fileAsHtml"]);
        sbCommonUtils.setPref("capture.default.saveDataUri", this.param.option["saveDataUri"]);
        sbCommonUtils.setPref("capture.default.downLinkMethod", this.param.option["downLinkMethod"]);
        sbCommonUtils.setPref("capture.default.downLinkFilter", this.param.option["downLinkFilter"]);
        if ( this.param.context !== "capture-again-deep" ) {
            sbCommonUtils.setPref("capture.default.inDepthLevels", this.param.option["inDepth"]);
        }

        // check for regex error
        var errors = [];
        this.param.option["downLinkFilter"].split(/[\r\n]/).forEach(function (srcLine, index) {
            if (srcLine.charAt(0) === "#") return;
            var line = srcLine.trim();
            if (line === "") return;
            try {
                new RegExp("^(?:" + line + ")$", "i");
            } catch (ex) {
                line =  sbCommonUtils.lang("ERR_CAPTURE_DOWNLINKFILTER_LINE", index+1, srcLine);
                errors.push(line);
            }
        });
        if (errors.length) {
            var button = sbCommonUtils.PROMPT.STD_YES_NO_BUTTONS;
            var text = sbCommonUtils.lang("ERR_CAPTURE_DOWNLINKFILTER", errors.join("\n\n"));
            // yes => 0, no => 1, close => 1
            return sbCommonUtils.PROMPT.confirmEx(null, "[ScrapBook]", text, button, null, null, null, null, {});
        }

        return true;
    },

    cancel: function() {
        this.param.result = 0;
    },

};

var sbFolderSelector = {

    get MENU_LIST()  { return document.getElementById("sbFolderList"); },
    get MENU_POPUP() { return document.getElementById("sbFolderPopup"); },

    nest: 0,

    init: function() {
        if ( !sbCaptureOptions.param.resURI ) sbCaptureOptions.param.resURI = "urn:scrapbook:root";
        this.refresh(sbCaptureOptions.param.resURI);
    },

    refresh: function(aResID) {
        if ( document.getElementById(aResID) == null ) {
            this.nest = 0;
            this.clear();
            this.processRecent();
            this.processRoot();
            this.processRecursive(sbCommonUtils.RDF.GetResource("urn:scrapbook:root"));
        }
        this.MENU_LIST.selectedItem = document.getElementById(aResID);
        this.MENU_LIST.disabled = false;
    },

    clear: function() {
        var oldItems = this.MENU_POPUP.childNodes;
        for ( var i = oldItems.length - 1; i >= 0; i-- ) {
            this.MENU_POPUP.removeChild(oldItems[i]);
        }
    },

    fill: function(aID, aTitle) {
        var item = document.createElement("menuitem");
        item.setAttribute("id",    aID);
        item.setAttribute("label", aTitle);
        item.setAttribute("nest", this.nest);
        item.setAttribute("class", "menuitem-iconic folder-icon");
        item.setAttribute("style", "padding-left:" + (20 * this.nest + 3) + "px;");
        this.MENU_POPUP.appendChild(item);
    },

    processRoot: function() {
        this.fill("urn:scrapbook:root", sbCommonUtils.lang("ROOT_FOLDER"));
        this.MENU_POPUP.appendChild(document.createElement("menuseparator"));
    },

    processRecent: function() {
        var ids = sbCommonUtils.getPref("ui.folderList", "");
        ids = ids ? ids.split("|") : [];
        var shownItems = 0;
        var maxEntries = sbCommonUtils.getPref("ui.folderList.maxEntries", 5);
        for (var i = 0; i < ids.length && shownItems < maxEntries; i++) {
            if (!sbCommonUtils.validateID(ids[i])) continue;
            var res = sbCommonUtils.RDF.GetResource("urn:scrapbook:item" + ids[i]);
            if (!sbDataSource.exists(res)) continue;
            this.fill(res.Value, sbDataSource.getProperty(res, "title"));
            shownItems++;
        }
        if (shownItems > 0)
            this.MENU_POPUP.appendChild(document.createElement("menuseparator"));
    },

    processRecursive: function(aContRes) {
        this.nest++;
        var resList = sbDataSource.flattenResources(aContRes, 1, false);
        resList.shift();
        for ( var i = 0; i < resList.length; i++ ) {
            var res = resList[i];
            this.fill(res.Value, sbDataSource.getProperty(res, "title"));
            this.processRecursive(res);
        }
        this.nest--;
    },

    onChange: function(aResURI) {
        sbCaptureOptions.param.resURI = aResURI;
        sbCaptureOptions.param.result = 2;
    },

    onMiddleClick: function() {
        this.MENU_LIST.selectedIndex = 0;
        this.onChange(this.MENU_LIST.selectedItem.id);
    },

    pick: function() {
        var ret = {};
        window.openDialog('chrome://scrapbook/content/folderPicker.xul','','modal,chrome,centerscreen,resizable=yes', ret, sbCaptureOptions.param.resURI);
        if ( ret.resource ) {
            this.refresh(ret.resource.Value);
            this.onChange(ret.resource.Value);
        }
    },

};

<|endoftext|>


<commit_before>"use strict";

var async = require("async");
var childProcess = require("child_process");
var filter = require("./filter");
var EventEmitter = require("./EventEmitter.js");

var defaultTestCmd = "npm test";

function sanitizeConfig(config) {
    config.reporter = config.reporter || Function.prototype;
    config.testCmd = config.testCmd || defaultTestCmd;
    config.exclude = config.exclude && config.exclude.split(",").map(function (name) {
        return name.trim();
    }) || [];
}

function run(config, done) {
    var emitter = new EventEmitter();
    var testCmd;
    var reporter;
    var cwd;

    function exec(cmd, cb) {
        childProcess.exec(cmd, { maxBuffer: Infinity, encoding: "utf8", cwd: config.cwd }, cb);
    }

    function finish(err) {
        emitter.removeAllListeners();
        done(err || null);
    }

    sanitizeConfig(config);

    reporter = config.reporter;
    cwd = config.cwd;
    testCmd = config.testCmd;

    if (typeof cwd !== "string") {
        throw new Error("Cannot run updtr: cwd missing");
    }

    reporter(emitter);

    emitter.emit("init", {
        cwd: config.cwd
    });
    exec("npm outdated --json --long --depth=0", function (err, stdout, stderr) {
        var outdated;
        var infos;
        var tasks;
        var modulesMissing;

        function createTask(info, index) {
            index++;

            return function (done) {
                var event = {
                    current: index,
                    total: tasks.length,
                    info: info,
                    testCmd: testCmd,
                    installCmd: installCmd = "npm i" + (config.registry ? (" --registry " + config.registry) : "")
                };
                var testStdout;
                var installCmd = event.installCmd + " " + info.name + "@" + info.updateTo + " " + info.saveCmd;

                if (config.saveExact) {
                    installCmd += " --save-exact";
                }

                emitter.emit("updating", event);

                async.series({
                    deleteOldVersion: async.apply(exec, "npm remove " + info.name + " " + info.saveCmd),
                    installNewVersion: async.apply(exec, installCmd),
                    emitTestingEvent: function (done) {
                        emitter.emit("testing", event);
                        setImmediate(done);
                    },
                    runTests: function runTests(callback) {
                        exec(testCmd, function (err, stdout, stderr) {
                            if (err) {
                                testStdout = stdout;
                                callback(err);
                                return;
                            }
                            callback(null, stdout, stderr);
                        });
                    }
                }, function (err) {
                    if (err) {
                        emitter.emit("rollback", event);
                        exec(event.installCmd + " " + info.name + "@" + info.current + " " + info.saveCmd + (config.saveExact ? " --save-exact" : ""), function (err) {
                            if (err) {
                                finish(err);
                                return;
                            }
                            emitter.emit("rollbackDone", event);
                            if (config.testStdout) {
                                event.testStdout = testStdout;
                                emitter.emit("testStdout", event);
                            }
                            done();
                        });
                        return;
                    }
                    emitter.emit("updatingDone", event);
                    done();
                });
            };
        }

        if (err) {
            finish(err);
            return;
        }

        if (!stdout) {
            emitter.emit("noop");
            finish();
            return;
        }

        outdated = JSON.parse(stdout);
        infos = Object.keys(outdated)
            .map(function (moduleName) {
                var info = outdated[moduleName];

                info.name = moduleName;
                info.saveCmd = info.type === "devDependencies" ? "--save-dev" : "--save";
                info.updateTo = config.wanted ? info.wanted : info.latest;

                return info;
            })
            .filter(filter(config));

        modulesMissing = infos.some(function (info) {
            return !info.current;
        });

        if (modulesMissing) {
            emitter.emit("modulesMissing");
            finish();
            return;
        }

        if (infos.length === 0) {
            emitter.emit("noop");
            finish();
            return;
        }

        emitter.emit("outdated", {
            infos: infos,
            total: infos.length
        });

        tasks = infos
            .map(function (info, index, outdatedModules) {
                return createTask(info, index, outdatedModules);
            });

        async.series(tasks, function (err) {
            if (err) {
                finish(err);
                return;
            }
            emitter.emit("finished");
            finish();
        });
    });
}

module.exports = run;
<commit_msg>Refactor small parts in run.js<commit_after>"use strict";

var async = require("async");
var childProcess = require("child_process");
var filter = require("./filter");
var EventEmitter = require("./EventEmitter.js");

var defaultTestCmd = "npm test";

function run(config, done) {
    var emitter = new EventEmitter();
    var testCmd;
    var reporter;
    var cwd;

    function exec(cmd, cb) {
        childProcess.exec(cmd, { maxBuffer: Infinity, encoding: "utf8", cwd: config.cwd }, cb);
    }

    function finish(err) {
        emitter.removeAllListeners();
        done(err || null);
    }

    sanitizeConfig(config);

    reporter = config.reporter;
    cwd = config.cwd;
    testCmd = config.testCmd;

    if (typeof cwd !== "string") {
        throw new Error("Cannot run updtr: cwd missing");
    }

    reporter(emitter);

    emitter.emit("init", {
        cwd: config.cwd
    });
    exec("npm outdated --json --long --depth=0", function (err, stdout) {
        var outdated;
        var infos;
        var tasks;

        function createTask(info, index) {
            return function (done) {
                var event = {
                    current: index + 1, // index is zero-based
                    total: tasks.length,
                    info: info,
                    testCmd: testCmd,
                    installCmd: "npm i" + (config.registry ? (" --registry " + config.registry) : "")
                };
                var testStdout;
                var installCmd = event.installCmd + " " + info.name + "@" + info.updateTo + " " + info.saveCmd;

                if (config.saveExact) {
                    installCmd += " --save-exact";
                }

                emitter.emit("updating", event);

                async.series({
                    deleteOldVersion: async.apply(exec, "npm remove " + info.name + " " + info.saveCmd),
                    installNewVersion: async.apply(exec, installCmd),
                    emitTestingEvent: function (done) {
                        emitter.emit("testing", event);
                        setImmediate(done);
                    },
                    runTests: function runTests(callback) {
                        exec(testCmd, function (err, stdout, stderr) {
                            if (err) {
                                testStdout = stdout;
                                callback(err);
                                return;
                            }
                            callback(null, stdout, stderr);
                        });
                    }
                }, function (err) {
                    if (err) {
                        emitter.emit("rollback", event);
                        exec(event.installCmd + " " + info.name + "@" + info.current + " " + info.saveCmd + (config.saveExact ? " --save-exact" : ""), function (err) {
                            if (err) {
                                finish(err);
                                return;
                            }
                            emitter.emit("rollbackDone", event);
                            if (config.testStdout) {
                                event.testStdout = testStdout;
                                emitter.emit("testStdout", event);
                            }
                            done();
                        });
                        return;
                    }
                    emitter.emit("updatingDone", event);
                    done();
                });
            };
        }

        if (err) {
            finish(err);
            return;
        }

        if (!stdout) {
            emitter.emit("noop");
            finish();
            return;
        }

        outdated = JSON.parse(stdout);
        infos = Object.keys(outdated)
            .map(function (moduleName) {
                var info = outdated[moduleName];

                info.name = moduleName;
                info.saveCmd = info.type === "devDependencies" ? "--save-dev" : "--save";
                info.updateTo = config.wanted ? info.wanted : info.latest;

                return info;
            })
            .filter(filter(config));

        if (thereAreModulesMissing(infos)) {
            emitter.emit("modulesMissing");
            finish();
            return;
        }

        if (infos.length === 0) {
            emitter.emit("noop");
            finish();
            return;
        }

        emitter.emit("outdated", {
            infos: infos,
            total: infos.length
        });

        tasks = infos
            .map(createTask);

        async.series(tasks, function (err) {
            if (err) {
                finish(err);
                return;
            }
            emitter.emit("finished");
            finish();
        });
    });
}

function thereAreModulesMissing(infos) {
    return infos.some(function (info) {
        return !info.current;
    });
}

function sanitizeConfig(config) {
    config.reporter = config.reporter || Function.prototype;
    config.testCmd = config.testCmd || defaultTestCmd;
    config.exclude = config.exclude && config.exclude.split(",").map(function (name) {
        return name.trim();
    }) || [];
}

module.exports = run;
<|endoftext|>


<commit_before>
var sbCaptureOptions = {

    param: null,

    init: function() {
        if (window.arguments) {
            // opened from capture detail
            this.param = window.arguments[0];
            document.documentElement.getButton("accept").label = sbCommonUtils.lang("CAPTURE_OK_BUTTON");
        } else {
            // opened for default capture options
            // this.param.item = undefined
            this.param = {
                option: {},
                result: 1,
            };
            document.getElementById("sbDetailTabs").selectedIndex = 1;
            document.getElementById("sbDetailTabGeneral").collapsed = true;
            document.getElementById("sbDetailInDepthBox").collapsed = true;
        }

        // load from preference
        document.getElementById("sbDetailOptionImages").checked = sbCommonUtils.getPref("capture.default.images", true);
        document.getElementById("sbDetailOptionMedia").checked = sbCommonUtils.getPref("capture.default.media", true);
        document.getElementById("sbDetailOptionFonts").checked = sbCommonUtils.getPref("capture.default.fonts", true);
        document.getElementById("sbDetailOptionFrames").checked = sbCommonUtils.getPref("capture.default.frames", true);
        document.getElementById("sbDetailOptionStyles").checked = sbCommonUtils.getPref("capture.default.styles", true);
        document.getElementById("sbDetailOptionScript").checked = sbCommonUtils.getPref("capture.default.script", false);
        document.getElementById("sbDetailOptionAsHtml").checked = sbCommonUtils.getPref("capture.default.fileAsHtml", false);
        document.getElementById("sbDetailOptionSaveDataURI").checked = sbCommonUtils.getPref("capture.default.saveDataUri", false);
        document.getElementById("sbDetailDownLinkMethod").value = sbCommonUtils.getPref("capture.default.downLinkMethod", 0);
        document.getElementById("sbDetailDownLinkFilter").value = sbCommonUtils.getPref("capture.default.downLinkFilter", "");
        document.getElementById("sbDetailInDepth").value = sbCommonUtils.getPref("capture.default.inDepthLevels", 0);

        // title
        if (this.param.item) {
            this.fillTitleList();
        }

        // script warning
        this.updateScriptWarning();

        // context specific settings
        if (this.param.item) {
            if ( this.param.context == "capture-again" || this.param.context == "capture-again-deep" ) {
                document.getElementById("sbDetailFolderRow").collapsed = true;
                document.getElementById("sbDetailCommentRow").collapsed = true;
                document.getElementById("sbDetailWarnAboutRenew").hidden = false;
                if ( this.param.context == "capture-again-deep" ) {
                    document.getElementById("sbDetailInDepthBox").collapsed = true;
                }
            } else {
                // make folder list
                setTimeout(function(){ sbFolderSelector.init(); }, 100);
                // comment
                document.getElementById("sbDetailComment").value = this.param.item.comment.replace(/ __BR__ /g, "\n");
            }
        }
    },

    fillTitleList: function() {
        var isPartial = this.param.titles.length > 1;
        var list = document.getElementById("sbDetailTitle");
        if ( this.param.context == "capture-again" ) {
            var res = sbCommonUtils.RDF.GetResource("urn:scrapbook:item" + this.param.item.id);
            list.appendItem(sbDataSource.getProperty(res, "title"));
        }
        for ( var i = 0; i < this.param.titles.length; i++ ) {
            list.appendItem(this.param.titles[i]);
            if ( i == 0 && this.param.titles.length > 1 ) list.firstChild.appendChild(document.createElement("menuseparator"));
        }
        list.selectedIndex = isPartial ? 2 : 0;
    },

    updateScriptWarning: function() {
        document.getElementById("sbDetailWarnAboutScript").hidden = !document.getElementById("sbDetailOptionScript").checked;
    },

    resetDownLinkFilters: function() {
        var _filter = document.getElementById("sbDetailDownLinkFilter").value;
        sbCommonUtils.resetPref("capture.default.downLinkFilter");
        document.getElementById("sbDetailDownLinkFilter").value = sbCommonUtils.getPref("capture.default.downLinkFilter", "");
        sbCommonUtils.setPref("capture.default.downLinkFilter", _filter);
    },

    accept: function() {
        // set return values
        if (this.param.item) {
            this.param.item.title = document.getElementById("sbDetailTitle").value;
            this.param.item.comment = sbCommonUtils.escapeComment(document.getElementById("sbDetailComment").value);
        }
        this.param.option["images"] = document.getElementById("sbDetailOptionImages").checked;
        this.param.option["media"] = document.getElementById("sbDetailOptionMedia").checked;
        this.param.option["fonts"] = document.getElementById("sbDetailOptionFonts").checked;
        this.param.option["frames"] = document.getElementById("sbDetailOptionFrames").checked;
        this.param.option["styles"] = document.getElementById("sbDetailOptionStyles").checked;
        this.param.option["script"] = document.getElementById("sbDetailOptionScript").checked;
        this.param.option["fileAsHtml"] = document.getElementById("sbDetailOptionAsHtml").checked;
        this.param.option["saveDataUri"] = document.getElementById("sbDetailOptionSaveDataURI").checked;
        this.param.option["downLinkMethod"] = parseInt("0" + document.getElementById("sbDetailDownLinkMethod").value, 10);
        this.param.option["downLinkFilter"] = document.getElementById("sbDetailDownLinkFilter").value;
        this.param.option["inDepth"] = parseInt(document.getElementById("sbDetailInDepth").value, 10);

        // save to preference
        sbCommonUtils.setPref("capture.default.images", this.param.option["images"]);
        sbCommonUtils.setPref("capture.default.media", this.param.option["media"]);
        sbCommonUtils.setPref("capture.default.fonts", this.param.option["fonts"]);
        sbCommonUtils.setPref("capture.default.frames", this.param.option["frames"]);
        sbCommonUtils.setPref("capture.default.styles", this.param.option["styles"]);
        sbCommonUtils.setPref("capture.default.script", this.param.option["script"]);
        sbCommonUtils.setPref("capture.default.fileAsHtml", this.param.option["fileAsHtml"]);
        sbCommonUtils.setPref("capture.default.saveDataUri", this.param.option["saveDataUri"]);
        sbCommonUtils.setPref("capture.default.downLinkMethod", this.param.option["downLinkMethod"]);
        sbCommonUtils.setPref("capture.default.downLinkFilter", this.param.option["downLinkFilter"]);
        sbCommonUtils.setPref("capture.default.inDepthLevels", this.param.option["inDepth"]);

        // post-fix for special cases
        if ( this.param.context === "capture-again-deep" ) {
            this.param.option["inDepth"] = 0;
        }
        if ( this.param.context == "capture-again" ) {
            var res = sbCommonUtils.RDF.GetResource("urn:scrapbook:item" + this.param.item.id);
            sbDataSource.setProperty(res, "title", document.getElementById("sbDetailTitle").value);
        }

        // check for regex error
        var errors = [];
        this.param.option["downLinkFilter"].split(/[\r\n]/).forEach(function (srcLine, index) {
            if (srcLine.charAt(0) === "#") return;
            var line = srcLine.trim();
            if (line === "") return;
            try {
                new RegExp("^(?:" + line + ")$", "i");
            } catch (ex) {
                line =  sbCommonUtils.lang("ERR_CAPTURE_DOWNLINKFILTER_LINE", index+1, srcLine);
                errors.push(line);
            }
        });
        if (errors.length) {
            var button = sbCommonUtils.PROMPT.STD_YES_NO_BUTTONS;
            var text = sbCommonUtils.lang("ERR_CAPTURE_DOWNLINKFILTER", errors.join("\n\n"));
            // yes => 0, no => 1, close => 1
            return sbCommonUtils.PROMPT.confirmEx(null, "[ScrapBook]", text, button, null, null, null, null, {});
        }

        return true;
    },

    cancel: function() {
        this.param.result = 0;
    },

};

var sbFolderSelector = {

    get MENU_LIST()  { return document.getElementById("sbFolderList"); },
    get MENU_POPUP() { return document.getElementById("sbFolderPopup"); },

    nest: 0,

    init: function() {
        if ( !sbCaptureOptions.param.resURI ) sbCaptureOptions.param.resURI = "urn:scrapbook:root";
        this.refresh(sbCaptureOptions.param.resURI);
    },

    refresh: function(aResID) {
        if ( document.getElementById(aResID) == null ) {
            this.nest = 0;
            this.clear();
            this.processRecent();
            this.processRoot();
            this.processRecursive(sbCommonUtils.RDF.GetResource("urn:scrapbook:root"));
        }
        this.MENU_LIST.selectedItem = document.getElementById(aResID);
        this.MENU_LIST.disabled = false;
    },

    clear: function() {
        var oldItems = this.MENU_POPUP.childNodes;
        for ( var i = oldItems.length - 1; i >= 0; i-- ) {
            this.MENU_POPUP.removeChild(oldItems[i]);
        }
    },

    fill: function(aID, aTitle) {
        var item = document.createElement("menuitem");
        item.setAttribute("id",    aID);
        item.setAttribute("label", aTitle);
        item.setAttribute("nest", this.nest);
        item.setAttribute("class", "menuitem-iconic folder-icon");
        item.setAttribute("style", "padding-left:" + (20 * this.nest + 3) + "px;");
        this.MENU_POPUP.appendChild(item);
    },

    processRoot: function() {
        this.fill("urn:scrapbook:root", sbCommonUtils.lang("ROOT_FOLDER"));
        this.MENU_POPUP.appendChild(document.createElement("menuseparator"));
    },

    processRecent: function() {
        var ids = sbCommonUtils.getPref("ui.folderList", "");
        ids = ids ? ids.split("|") : [];
        var shownItems = 0;
        var maxEntries = sbCommonUtils.getPref("ui.folderList.maxEntries", 5);
        for (var i = 0; i < ids.length && shownItems < maxEntries; i++) {
            if (!sbCommonUtils.validateID(ids[i])) continue;
            var res = sbCommonUtils.RDF.GetResource("urn:scrapbook:item" + ids[i]);
            if (!sbDataSource.exists(res)) continue;
            this.fill(res.Value, sbDataSource.getProperty(res, "title"));
            shownItems++;
        }
        if (shownItems > 0)
            this.MENU_POPUP.appendChild(document.createElement("menuseparator"));
    },

    processRecursive: function(aContRes) {
        this.nest++;
        var resList = sbDataSource.flattenResources(aContRes, 1, false);
        resList.shift();
        for ( var i = 0; i < resList.length; i++ ) {
            var res = resList[i];
            this.fill(res.Value, sbDataSource.getProperty(res, "title"));
            this.processRecursive(res);
        }
        this.nest--;
    },

    onChange: function(aResURI) {
        sbCaptureOptions.param.resURI = aResURI;
        sbCaptureOptions.param.result = 2;
    },

    onMiddleClick: function() {
        this.MENU_LIST.selectedIndex = 0;
        this.onChange(this.MENU_LIST.selectedItem.id);
    },

    pick: function() {
        var ret = {};
        window.openDialog('chrome://scrapbook/content/folderPicker.xul','','modal,chrome,centerscreen,resizable=yes', ret, sbCaptureOptions.param.resURI);
        if ( ret.resource ) {
            this.refresh(ret.resource.Value);
            this.onChange(ret.resource.Value);
        }
    },

};

<commit_msg>capture: resort settings<commit_after>
var sbCaptureOptions = {

    param: null,

    init: function() {
        if (window.arguments) {
            // opened from capture detail
            this.param = window.arguments[0];
            document.documentElement.getButton("accept").label = sbCommonUtils.lang("CAPTURE_OK_BUTTON");
        } else {
            // opened for default capture options
            // this.param.item = undefined
            this.param = {
                option: {},
                result: 1,
            };
            document.getElementById("sbDetailTabs").selectedIndex = 1;
            document.getElementById("sbDetailTabGeneral").collapsed = true;
            document.getElementById("sbDetailInDepthBox").collapsed = true;
        }

        // load from preference
        document.getElementById("sbDetailOptionImages").checked = sbCommonUtils.getPref("capture.default.images", true);
        document.getElementById("sbDetailOptionMedia").checked = sbCommonUtils.getPref("capture.default.media", true);
        document.getElementById("sbDetailOptionFonts").checked = sbCommonUtils.getPref("capture.default.fonts", true);
        document.getElementById("sbDetailOptionFrames").checked = sbCommonUtils.getPref("capture.default.frames", true);
        document.getElementById("sbDetailOptionStyles").checked = sbCommonUtils.getPref("capture.default.styles", true);
        document.getElementById("sbDetailOptionScript").checked = sbCommonUtils.getPref("capture.default.script", false);
        document.getElementById("sbDetailOptionAsHtml").checked = sbCommonUtils.getPref("capture.default.fileAsHtml", false);
        document.getElementById("sbDetailOptionSaveDataURI").checked = sbCommonUtils.getPref("capture.default.saveDataUri", false);
        document.getElementById("sbDetailDownLinkMethod").value = sbCommonUtils.getPref("capture.default.downLinkMethod", 0);
        document.getElementById("sbDetailDownLinkFilter").value = sbCommonUtils.getPref("capture.default.downLinkFilter", "");
        document.getElementById("sbDetailInDepth").value = sbCommonUtils.getPref("capture.default.inDepthLevels", 0);

        // title
        if (this.param.item) {
            this.fillTitleList();
        }

        // script warning
        this.updateScriptWarning();

        // context specific settings
        if (this.param.item) {
            if ( this.param.context == "capture-again" || this.param.context == "capture-again-deep" ) {
                document.getElementById("sbDetailFolderRow").collapsed = true;
                document.getElementById("sbDetailCommentRow").collapsed = true;
                if ( this.param.context == "capture-again-deep" ) {
                    document.getElementById("sbDetailInDepthBox").collapsed = true;
                }
                document.getElementById("sbDetailWarnAboutRenew").hidden = false;
            } else {
                // make folder list
                setTimeout(function(){ sbFolderSelector.init(); }, 100);
                // comment
                document.getElementById("sbDetailComment").value = this.param.item.comment.replace(/ __BR__ /g, "\n");
            }
        }
    },

    fillTitleList: function() {
        var isPartial = this.param.titles.length > 1;
        var list = document.getElementById("sbDetailTitle");
        if ( this.param.context == "capture-again" ) {
            var res = sbCommonUtils.RDF.GetResource("urn:scrapbook:item" + this.param.item.id);
            list.appendItem(sbDataSource.getProperty(res, "title"));
        }
        for ( var i = 0; i < this.param.titles.length; i++ ) {
            list.appendItem(this.param.titles[i]);
            if ( i == 0 && this.param.titles.length > 1 ) list.firstChild.appendChild(document.createElement("menuseparator"));
        }
        list.selectedIndex = isPartial ? 2 : 0;
    },

    updateScriptWarning: function() {
        document.getElementById("sbDetailWarnAboutScript").hidden = !document.getElementById("sbDetailOptionScript").checked;
    },

    resetDownLinkFilters: function() {
        var _filter = document.getElementById("sbDetailDownLinkFilter").value;
        sbCommonUtils.resetPref("capture.default.downLinkFilter");
        document.getElementById("sbDetailDownLinkFilter").value = sbCommonUtils.getPref("capture.default.downLinkFilter", "");
        sbCommonUtils.setPref("capture.default.downLinkFilter", _filter);
    },

    accept: function() {
        // set return values
        if (this.param.item) {
            this.param.item.title = document.getElementById("sbDetailTitle").value;
            this.param.item.comment = sbCommonUtils.escapeComment(document.getElementById("sbDetailComment").value);
        }
        this.param.option["images"] = document.getElementById("sbDetailOptionImages").checked;
        this.param.option["media"] = document.getElementById("sbDetailOptionMedia").checked;
        this.param.option["fonts"] = document.getElementById("sbDetailOptionFonts").checked;
        this.param.option["frames"] = document.getElementById("sbDetailOptionFrames").checked;
        this.param.option["styles"] = document.getElementById("sbDetailOptionStyles").checked;
        this.param.option["script"] = document.getElementById("sbDetailOptionScript").checked;
        this.param.option["fileAsHtml"] = document.getElementById("sbDetailOptionAsHtml").checked;
        this.param.option["saveDataUri"] = document.getElementById("sbDetailOptionSaveDataURI").checked;
        this.param.option["downLinkMethod"] = parseInt("0" + document.getElementById("sbDetailDownLinkMethod").value, 10);
        this.param.option["downLinkFilter"] = document.getElementById("sbDetailDownLinkFilter").value;
        this.param.option["inDepth"] = parseInt(document.getElementById("sbDetailInDepth").value, 10);

        // save to preference
        sbCommonUtils.setPref("capture.default.images", this.param.option["images"]);
        sbCommonUtils.setPref("capture.default.media", this.param.option["media"]);
        sbCommonUtils.setPref("capture.default.fonts", this.param.option["fonts"]);
        sbCommonUtils.setPref("capture.default.frames", this.param.option["frames"]);
        sbCommonUtils.setPref("capture.default.styles", this.param.option["styles"]);
        sbCommonUtils.setPref("capture.default.script", this.param.option["script"]);
        sbCommonUtils.setPref("capture.default.fileAsHtml", this.param.option["fileAsHtml"]);
        sbCommonUtils.setPref("capture.default.saveDataUri", this.param.option["saveDataUri"]);
        sbCommonUtils.setPref("capture.default.downLinkMethod", this.param.option["downLinkMethod"]);
        sbCommonUtils.setPref("capture.default.downLinkFilter", this.param.option["downLinkFilter"]);
        sbCommonUtils.setPref("capture.default.inDepthLevels", this.param.option["inDepth"]);

        // post-fix for special cases
        if ( this.param.context === "capture-again-deep" ) {
            this.param.option["inDepth"] = 0;
        }
        if ( this.param.context == "capture-again" ) {
            var res = sbCommonUtils.RDF.GetResource("urn:scrapbook:item" + this.param.item.id);
            sbDataSource.setProperty(res, "title", document.getElementById("sbDetailTitle").value);
        }

        // check for regex error
        var errors = [];
        this.param.option["downLinkFilter"].split(/[\r\n]/).forEach(function (srcLine, index) {
            if (srcLine.charAt(0) === "#") return;
            var line = srcLine.trim();
            if (line === "") return;
            try {
                new RegExp("^(?:" + line + ")$", "i");
            } catch (ex) {
                line =  sbCommonUtils.lang("ERR_CAPTURE_DOWNLINKFILTER_LINE", index+1, srcLine);
                errors.push(line);
            }
        });
        if (errors.length) {
            var button = sbCommonUtils.PROMPT.STD_YES_NO_BUTTONS;
            var text = sbCommonUtils.lang("ERR_CAPTURE_DOWNLINKFILTER", errors.join("\n\n"));
            // yes => 0, no => 1, close => 1
            return sbCommonUtils.PROMPT.confirmEx(null, "[ScrapBook]", text, button, null, null, null, null, {});
        }

        return true;
    },

    cancel: function() {
        this.param.result = 0;
    },

};

var sbFolderSelector = {

    get MENU_LIST()  { return document.getElementById("sbFolderList"); },
    get MENU_POPUP() { return document.getElementById("sbFolderPopup"); },

    nest: 0,

    init: function() {
        if ( !sbCaptureOptions.param.resURI ) sbCaptureOptions.param.resURI = "urn:scrapbook:root";
        this.refresh(sbCaptureOptions.param.resURI);
    },

    refresh: function(aResID) {
        if ( document.getElementById(aResID) == null ) {
            this.nest = 0;
            this.clear();
            this.processRecent();
            this.processRoot();
            this.processRecursive(sbCommonUtils.RDF.GetResource("urn:scrapbook:root"));
        }
        this.MENU_LIST.selectedItem = document.getElementById(aResID);
        this.MENU_LIST.disabled = false;
    },

    clear: function() {
        var oldItems = this.MENU_POPUP.childNodes;
        for ( var i = oldItems.length - 1; i >= 0; i-- ) {
            this.MENU_POPUP.removeChild(oldItems[i]);
        }
    },

    fill: function(aID, aTitle) {
        var item = document.createElement("menuitem");
        item.setAttribute("id",    aID);
        item.setAttribute("label", aTitle);
        item.setAttribute("nest", this.nest);
        item.setAttribute("class", "menuitem-iconic folder-icon");
        item.setAttribute("style", "padding-left:" + (20 * this.nest + 3) + "px;");
        this.MENU_POPUP.appendChild(item);
    },

    processRoot: function() {
        this.fill("urn:scrapbook:root", sbCommonUtils.lang("ROOT_FOLDER"));
        this.MENU_POPUP.appendChild(document.createElement("menuseparator"));
    },

    processRecent: function() {
        var ids = sbCommonUtils.getPref("ui.folderList", "");
        ids = ids ? ids.split("|") : [];
        var shownItems = 0;
        var maxEntries = sbCommonUtils.getPref("ui.folderList.maxEntries", 5);
        for (var i = 0; i < ids.length && shownItems < maxEntries; i++) {
            if (!sbCommonUtils.validateID(ids[i])) continue;
            var res = sbCommonUtils.RDF.GetResource("urn:scrapbook:item" + ids[i]);
            if (!sbDataSource.exists(res)) continue;
            this.fill(res.Value, sbDataSource.getProperty(res, "title"));
            shownItems++;
        }
        if (shownItems > 0)
            this.MENU_POPUP.appendChild(document.createElement("menuseparator"));
    },

    processRecursive: function(aContRes) {
        this.nest++;
        var resList = sbDataSource.flattenResources(aContRes, 1, false);
        resList.shift();
        for ( var i = 0; i < resList.length; i++ ) {
            var res = resList[i];
            this.fill(res.Value, sbDataSource.getProperty(res, "title"));
            this.processRecursive(res);
        }
        this.nest--;
    },

    onChange: function(aResURI) {
        sbCaptureOptions.param.resURI = aResURI;
        sbCaptureOptions.param.result = 2;
    },

    onMiddleClick: function() {
        this.MENU_LIST.selectedIndex = 0;
        this.onChange(this.MENU_LIST.selectedItem.id);
    },

    pick: function() {
        var ret = {};
        window.openDialog('chrome://scrapbook/content/folderPicker.xul','','modal,chrome,centerscreen,resizable=yes', ret, sbCaptureOptions.param.resURI);
        if ( ret.resource ) {
            this.refresh(ret.resource.Value);
            this.onChange(ret.resource.Value);
        }
    },

};

<|endoftext|>


<commit_before>/**
 * Add the capability to load CMD modules in node environment
 * @author lifesinger@gmail.com
 */

var fs = require("fs")
var path = require("path")
var vm = require("vm")

var moduleStack = []
var uriCache = {}
var nativeLoad

fixWinOS()
runSeaJS("../dist/sea-debug.js")

hackNative()
attach()
keep()

seajs.cwd(process.cwd())

function fixWinOS() {
  if (process.cwd().indexOf("\\") === -1) return

  var join = path.join
  var cwd = process.cwd

  path.join = function() {
    return normalize(join.apply(path, arguments))
  }

  process.cwd = function() {
    return normalize(cwd.call(process))
  }
}

function runSeaJS(filepath) {
  var code = fs.readFileSync(path.join(__dirname, filepath), "utf8")
  code = code.replace("})(this);", "})(exports);")

  // Run "sea.js" code in a fake browser environment
  var sandbox = require("./sandbox")
  vm.runInNewContext(code, sandbox, "sea-debug.vm")

  global.seajs = sandbox.exports.seajs
  global.define = sandbox.exports.define
}

function hackNative() {
  var Module = module.constructor
  nativeLoad = Module._load

  Module._load = function(request, parent, isMain) {
    var exports = nativeLoad(request, parent, isMain)

    var filename = Module._resolveFilename(request, parent)
    var mod = seajs.cache[filename]

    if (mod) {
      if (mod.status < 4) { // < STATUS_EXECUTING
        mod.constructor.load([filename], function() {})
      }
      exports = Module._cache[filename] = mod.exports
    }

    return exports
  }

  var _compile = Module.prototype._compile

  Module.prototype._compile = function(content, filename) {
    moduleStack.push(this)
    try {
      return _compile.call(this, content, filename)
    }
    finally {
      moduleStack.pop()
    }
  }
}

function attach() {
  seajs.on("request", requestListener)
  seajs.on("define", defineListener)
}

function requestListener(data) {
  var requestUri =  pure(data.requestUri)
  var ext = path.extname(requestUri)
  //process.stdout.write("requestUri = " + requestUri + "\n")

  if (ext === ".js") {
    // Use native `require` instead of script-inserted version
    nativeLoad(requestUri)
    data.callback()
    data.requested = true
  }
  // Throw error if this function is the last request handler
  else if (seajs.events["request"].length === 1) {
    throw new Error("Do NOT support to load this file in node environment: "
        + requestUri)
  }
}

function defineListener(data) {
  if (!data.uri) {
    var derivedUri = normalize(moduleStack[moduleStack.length - 1].id)
    data.uri = uriCache[derivedUri] || derivedUri
  }
}

function keep() {
  var _off = seajs.off

  seajs.off = function() {
    _off()
    attach()
    return seajs
  }
}

function pure(uri) {
  // Remove timestamp etc
  var ret = uri.replace(/\?.*$/, "")

  // Cache it
  if (ret !== uri) {
    uriCache[ret] = uri
  }
  return ret
}

function normalize(path) {
  return (path || "").replace(/\\/g, "/")
}

<commit_msg>Fix seajs bug in Windows OS<commit_after>/**
 * Add the capability to load CMD modules in node environment
 * @author lifesinger@gmail.com
 */

var fs = require("fs")
var path = require("path")
var vm = require("vm")

var moduleStack = []
var uriCache = {}
var nativeLoad

fixWinOS()
runSeaJS("../dist/sea-debug.js")

hackNative()
attach()
keep()

seajs.cwd(process.cwd())

function fixWinOS() {
  if (process.execPath.indexOf('node.exe') === -1) return

  var join = path.join
  var cwd = process.cwd

  path.join = function() {
    return normalize(join.apply(path, arguments))
  }

  process.cwd = function() {
    return normalize(cwd.call(process))
  }
}

function runSeaJS(filepath) {
  var code = fs.readFileSync(path.join(__dirname, filepath), "utf8")
  code = code.replace("})(this);", "})(exports);")

  // Run "sea.js" code in a fake browser environment
  var sandbox = require("./sandbox")
  vm.runInNewContext(code, sandbox, "sea-debug.vm")

  global.seajs = sandbox.exports.seajs
  global.define = sandbox.exports.define
}

function hackNative() {
  var Module = module.constructor
  nativeLoad = Module._load

  Module._load = function(request, parent, isMain) {
    var exports = nativeLoad(request, parent, isMain)

    var filename = Module._resolveFilename(request, parent)
    var mod = seajs.cache[filename]

    if (mod) {
      if (mod.status < 4) { // < STATUS_EXECUTING
        mod.constructor.load([filename], function() {})
      }
      exports = Module._cache[filename] = mod.exports
    }

    return exports
  }

  var _compile = Module.prototype._compile

  Module.prototype._compile = function(content, filename) {
    moduleStack.push(this)
    try {
      return _compile.call(this, content, filename)
    }
    finally {
      moduleStack.pop()
    }
  }
}

function attach() {
  seajs.on("request", requestListener)
  seajs.on("define", defineListener)
}

function requestListener(data) {
  var requestUri = pure(data.requestUri)
  var ext = path.extname(requestUri)
  //process.stdout.write("requestUri = " + requestUri + "\n")

  if (ext === ".js") {
    // Use native `require` instead of script-inserted version
    nativeLoad(requestUri)
    data.callback()
    data.requested = true
  }
  // Throw error if this function is the last request handler
  else if (seajs.events["request"].length === 1) {
    throw new Error("Do NOT support to load this file in node environment: "
        + requestUri)
  }
}

function defineListener(data) {
  if (!data.uri) {
    var derivedUri = normalize(moduleStack[moduleStack.length - 1].id)
    data.uri = uriCache[derivedUri] || derivedUri
  }
}

function keep() {
  var _off = seajs.off

  seajs.off = function() {
    _off()
    attach()
    return seajs
  }
}

function pure(uri) {
  // Remove timestamp etc
  var ret = uri.replace(/\?.*$/, "")

  // Cache it
  if (ret !== uri) {
    uriCache[ret] = uri
  }
  return ret
}

function normalize(path) {
  return (path || "").replace(/\\/g, "/")
}

<|endoftext|>