<commit_before>var chalk = require('chalk');
var prompt = require('prompt');
var sprintf = require('sprintf-js').sprintf;

var core = require('../core');

var cmd = {
  command: 'user',
  desc:    'login/logout with leetcode account',
  builder: {
    login: {
      alias:    'l',
      type:     'boolean',
      describe: 'Login'
    },
    logout: {
      alias:    'L',
      type:     'boolean',
      describe: 'Logout'
    },
    stat: {
      alias:    's',
      type:     'boolean',
      describe: 'Show user statistics'
    }
  }
};

function bar(c, n) {
  return new Buffer(n).fill(c).toString();
}

function prettyLine(key, done, all) {
  var n = 30;
  var x = Math.ceil(n * done / all);
  return sprintf('%-8s %3d/%-3d (%.2f%%)\t%s%s',
      key, done, all, done * 100 / all,
      chalk.green('[' + bar(chalk.enabled ? '.' : '+', x)),
      chalk.red(bar('.', n - x) + ']'));
}

cmd.handler = function(argv) {
  var user = null;
  if (argv.login) {
    // login
    prompt.colors = false;
    prompt.message = '';
    prompt.start();
    prompt.get([
      {name: 'login', required: true},
      {name: 'pass', required: true, hidden: true}
    ], function(e, user) {
      if (e) return console.log('Login failed:', e);

      core.login(user, function(e, user) {
        if (e) return console.log('Login failed:', e);

        console.log('Successfully login as', chalk.yellow(user.name));
      });
    });
  } else if (argv.logout) {
    // logout
    user = core.logout(null);
    if (user)
      console.log('Successfully logout as', chalk.yellow(user.name));
    else
      console.log('You are not login yet?');
  } else {
    // show current user
    user = core.getUser();
    if (user)
      console.log('You are now login as', chalk.yellow(user.name));
    else
      return console.log('You are not login yet?');

    if (argv.stat) {
      core.getProblems(function(e, problems) {
        if (e) return console.log('Get stats failed:', e);

        var stats = {};
        problems.forEach(function(problem) {
          var keyAll = 'all' + problem.level;
          var keyAC = problem.state + problem.level;
          stats[keyAll] = (stats[keyAll] || 0) + 1;
          stats[keyAC] = (stats[keyAC] || 0) + 1;
        });

        console.log();
        console.log(prettyLine('Easy', stats.acEasy, stats.allEasy));
        console.log(prettyLine('Medium', stats.acMedium, stats.allMedium));
        console.log(prettyLine('Hard', stats.acHard, stats.allHard));
      });
    }
  }
};

module.exports = cmd;
<commit_msg>fix user status done undefined<commit_after>var chalk = require('chalk');
var prompt = require('prompt');
var sprintf = require('sprintf-js').sprintf;

var core = require('../core');

var cmd = {
  command: 'user',
  desc:    'login/logout with leetcode account',
  builder: {
    login: {
      alias:    'l',
      type:     'boolean',
      describe: 'Login'
    },
    logout: {
      alias:    'L',
      type:     'boolean',
      describe: 'Logout'
    },
    stat: {
      alias:    's',
      type:     'boolean',
      describe: 'Show user statistics'
    }
  }
};

function bar(c, n) {
  return new Buffer(n).fill(c).toString();
}

function prettyLine(key, done, all) {
  done = done || 0;
  var n = 30;
  var x = Math.ceil(n * done / all);
  return sprintf('%-8s %3d/%-3d (%.2f%%)\t%s%s',
      key, done, all, done * 100 / all,
      chalk.green('[' + bar(chalk.enabled ? '.' : '+', x)),
      chalk.red(bar('.', n - x) + ']'));
}

cmd.handler = function(argv) {
  var user = null;
  if (argv.login) {
    // login
    prompt.colors = false;
    prompt.message = '';
    prompt.start();
    prompt.get([
      {name: 'login', required: true},
      {name: 'pass', required: true, hidden: true}
    ], function(e, user) {
      if (e) return console.log('Login failed:', e);

      core.login(user, function(e, user) {
        if (e) return console.log('Login failed:', e);

        console.log('Successfully login as', chalk.yellow(user.name));
      });
    });
  } else if (argv.logout) {
    // logout
    user = core.logout(null);
    if (user)
      console.log('Successfully logout as', chalk.yellow(user.name));
    else
      console.log('You are not login yet?');
  } else {
    // show current user
    user = core.getUser();
    if (user)
      console.log('You are now login as', chalk.yellow(user.name));
    else
      return console.log('You are not login yet?');

    if (argv.stat) {
      core.getProblems(function(e, problems) {
        if (e) return console.log('Get stats failed:', e);

        var stats = {};
        problems.forEach(function(problem) {
          var keyAll = 'all' + problem.level;
          var keyAC = problem.state + problem.level;
          stats[keyAll] = (stats[keyAll] || 0) + 1;
          stats[keyAC] = (stats[keyAC] || 0) + 1;
        });

        console.log();
        console.log(prettyLine('Easy', stats.acEasy, stats.allEasy));
        console.log(prettyLine('Medium', stats.acMedium, stats.allMedium));
        console.log(prettyLine('Hard', stats.acHard, stats.allHard));
      });
    }
  }
};

module.exports = cmd;
<|endoftext|>


<commit_before>'use strict';

var protobufjs = require('protobufjs/dist/ProtoBuf');
var Message = require('../Message');

var RootCerts = require('../common/RootCerts');

// BIP 70 - payment protocol
function PayPro() {
  this.messageType = null;
  this.message = null;
}

PayPro.PAYMENT_REQUEST_MAX_SIZE = 50000;
PayPro.PAYMENT_MAX_SIZE = 50000;
PayPro.PAYMENT_ACK_MAX_SIZE = 60000;
PayPro.PAYMENT_REQUEST_CONTENT_TYPE = "application/bitcoin-paymentrequest";
PayPro.PAYMENT_CONTENT_TYPE = "application/bitcoin-payment";
PayPro.PAYMENT_ACK_CONTENT_TYPE = "application/bitcoin-paymentack";

PayPro.proto = {};

PayPro.proto.Output = "message Output {\
  optional uint64 amount = 1 [default = 0];\
  optional bytes script = 2;\
}\n";

PayPro.proto.PaymentDetails = "message PaymentDetails {\
  optional string network = 1 [default = \"main\"];\
  repeated Output outputs = 2;\
  required uint64 time = 3;\
  optional uint64 expires = 4;\
  optional string memo = 5;\
  optional string payment_url = 6;\
  optional bytes merchant_data = 7;\
}\n";

PayPro.proto.PaymentRequest = "message PaymentRequest {\
  optional uint32 payment_details_version = 1 [default = 1];\
  optional string pki_type = 2 [default = \"none\"];\
  optional bytes pki_data = 3;\
  required bytes serialized_payment_details = 4;\
  optional bytes signature = 5;\
}\n";

PayPro.proto.Payment = "message Payment {\
  optional bytes merchant_data = 1;\
  repeated bytes transactions = 2;\
  repeated Output refund_to = 3;\
  optional string memo = 4;\
}\n";

PayPro.proto.PaymentACK = "message PaymentACK {\
  required Payment payment = 1;\
  optional string memo = 2;\
}\n";

PayPro.proto.X509Certificates = "message X509Certificates {\
  repeated bytes certificate = 1;\
}\n";

PayPro.proto.all = "";
PayPro.proto.all = PayPro.proto.all + PayPro.proto.Output;
PayPro.proto.all = PayPro.proto.all + PayPro.proto.PaymentDetails;
PayPro.proto.all = PayPro.proto.all + PayPro.proto.PaymentRequest;
PayPro.proto.all = PayPro.proto.all + PayPro.proto.Payment;
PayPro.proto.all = PayPro.proto.all + PayPro.proto.PaymentACK;
PayPro.proto.all = PayPro.proto.all + PayPro.proto.X509Certificates;

PayPro.builder = protobufjs.loadProto(PayPro.proto.all);

PayPro.Output = PayPro.builder.build("Output");
PayPro.PaymentDetails = PayPro.builder.build("PaymentDetails");
PayPro.PaymentRequest = PayPro.builder.build("PaymentRequest");
PayPro.Payment = PayPro.builder.build("Payment");
PayPro.PaymentACK = PayPro.builder.build("PaymentACK");
PayPro.X509Certificates = PayPro.builder.build("X509Certificates");

PayPro.prototype.makeOutput = function(obj) {
  this.messageType = 'Output';
  this.message = new PayPro.Output();
  this.setObj(obj);
  return this;
};

PayPro.prototype.makePaymentDetails = function(obj) {
  this.messageType = 'PaymentDetails';
  this.message = new PayPro.PaymentDetails();
  this.setObj(obj);
  return this;
};

PayPro.prototype.makePaymentRequest = function(obj) {
  this.messageType = 'PaymentRequest';
  this.message = new PayPro.PaymentRequest();
  this.setObj(obj);
  return this;
};

PayPro.prototype.makePayment = function(obj) {
  this.messageType = 'Payment';
  this.message = new PayPro.Payment();
  this.setObj(obj);
  return this;
};

PayPro.prototype.makePaymentACK = function(obj) {
  this.messageType = 'PaymentACK';
  this.message = new PayPro.PaymentACK();
  this.setObj(obj);
  return this;
};

PayPro.prototype.makeX509Certificates = function(obj) {
  this.messageType = 'X509Certificates';
  this.message = new PayPro.X509Certificates();
  this.setObj(obj);
  return this;
};

PayPro.prototype.isValidSize = function() {
  var s = this.serialize();
  if (this.messageType == 'PaymentRequest')
    return s.length < PayPro.PAYMENT_REQUEST_MAX_SIZE;
  if (this.messageType == 'Payment')
    return s.length < PayPro.PAYMENT_MAX_SIZE;
  if (this.messageType == 'PaymentACK')
    return s.length < PayPro.PAYMENT_ACK_MAX_SIZE;
  return true;
};

PayPro.prototype.getContentType = function() {
  if (this.messageType == 'PaymentRequest')
    return PayPro.PAYMENT_REQUEST_CONTENT_TYPE;

  if (this.messageType == 'Payment')
    return PayPro.PAYMENT_CONTENT_TYPE;

  if (this.messageType == 'PaymentACK')
    return PayPro.PAYMENT_ACK_CONTENT_TYPE;

  throw new Error('No known content type for this message type');
};

PayPro.prototype.set = function(key, val) {
  this.message.set(key, val);
  return this;
};

PayPro.prototype.get = function(key) {
  var v = this.message.get(key);

  if (v === null)
    return v;

  //protobuf supports longs, javascript naturally does not
  //convert longs (see long.js, e.g. require('long')) to Numbers
  if (typeof v.low !== 'undefined' && typeof v.high !== 'undefined')
    return v.toInt();

  if (typeof v.toBuffer !== 'undefined') {
    var maybebuf = v.toBuffer();
    return Buffer.isBuffer(maybebuf) ? maybebuf : new Buffer(new Uint8Array(maybebuf));
  }

  return v;
};

PayPro.prototype.setObj = function(obj) {
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      var val = obj[key];
      this.message.set(key, val);
    }
  }
  return this;
};

PayPro.prototype.serializeForSig = function() {
  if (this.messageType !== 'PaymentRequest')
    throw new Error('serializeForSig is only for PaymentRequest');

  var save = this.message.get('signature');
  this.message.set('signature', new Buffer([]));
  var buf = this.serialize();
  this.message.set('signature', save);
  return buf;
};

PayPro.prototype.serialize = function() {
  //protobufjs returns either a Buffer or an ArrayBuffer
  //but we always want a Buffer (which browserify understands, browser or no)
  var maybebuf = this.message.toBuffer();
  var buf = (Buffer.isBuffer(maybebuf)) ? maybebuf : new Buffer(new Uint8Array(maybebuf));
  return buf;
};

PayPro.prototype.deserialize = function(buf, messageType) {
  this.messageType = messageType || this.messageType;
  if (!this.messageType)
    throw new Error('Must specify messageType');
  this.message = PayPro[this.messageType].decode(buf);
  return this;
};

PayPro.prototype.sign = function(key) {
  if (this.messageType !== 'PaymentRequest')
    throw new Error('Signing can only be performed on a PaymentRequest');

  var pki_type = this.get('pki_type');

  if (pki_type === 'SIN') {
    var sig = this.sinSign(key);
  } else if (pki_type === 'x509+sha1' || pki_type === 'x509+sha256') {
    var sig = this.x509Sign(key);
  } else if (pki_type === 'none') {
    return this;
  } else {
    throw new Error('Unsupported pki_type');
  }

  this.set('signature', sig);

  return this;
};

PayPro.prototype.verify = function() {
  if (this.messageType !== 'PaymentRequest')
    throw new Error('Verifying can only be performed on a PaymentRequest');

  var pki_type = this.get('pki_type');

  if (pki_type === 'SIN') {
    return this.sinVerify();
  } else if (pki_type === 'x509+sha1' || pki_type === 'x509+sha256') {
    return this.x509Verify();
  } else if (pki_type === 'none') {
    return true;
  }

  throw new Error('Unsupported pki_type');
};

//default signing function for prototype.sign
PayPro.prototype.sinSign = function(key) {
  this.set('pki_data', key.public)
  var buf = this.serializeForSig();
  return Message.sign(buf, key);
};

//default verify function
PayPro.prototype.sinVerify = function() {
  var sig = this.get('signature');
  var pubkey = this.get('pki_data');
  var buf = this.serializeForSig();
  return Message.verifyWithPubKey(pubkey, buf, sig);
};

// Helpers

PayPro.prototype._PEMtoDER = function(pem) {
  return this._PEMtoDERParam(pem);
};

PayPro.prototype._PEMtoDERParam = function(pem, param) {
  if (Buffer.isBuffer(pem)) {
    pem = pem.toString();
  }
  var start = new RegExp('(?=-----BEGIN ' + (param || '[^-]+') + '-----)', 'i');
  var end = new RegExp('^-----END ' + (param || '[^-]+') + '-----$', 'gmi');
  pem = pem.replace(end, '');
  var parts = pem.split(start);
  return parts.map(function(part) {
    var type = /-----BEGIN ([^-]+)-----/.exec(part)[1];
    part = part.replace(/-----BEGIN ([^-]+)-----/g, '');
    part = part.replace(/\s+/g, '');
    if (!param || type !== param) return;
    return new Buffer(part, 'base64');
  }).filter(Boolean);
};

PayPro.prototype._DERtoPEM = function(der, type) {
  if (typeof der === 'string') {
    der = new Buffer(der, 'hex');
  }
  var type = type || 'UNKNOWN';
  der = der.toString('base64');
  der = der.replace(/(.{64})/g, '$1\r\n');
  der = der.replace(/\r\n$/, '');
  return ''
    + '-----BEGIN ' + type + '-----\r\n'
    + der
    + '\r\n-----END ' + type + '-----\r\n';
};

module.exports = PayPro;
<commit_msg>paypro: expose RootCerts on PayPro.<commit_after>'use strict';

var protobufjs = require('protobufjs/dist/ProtoBuf');
var Message = require('../Message');

var RootCerts = require('../common/RootCerts');

// BIP 70 - payment protocol
function PayPro() {
  this.messageType = null;
  this.message = null;
}

PayPro.PAYMENT_REQUEST_MAX_SIZE = 50000;
PayPro.PAYMENT_MAX_SIZE = 50000;
PayPro.PAYMENT_ACK_MAX_SIZE = 60000;
PayPro.PAYMENT_REQUEST_CONTENT_TYPE = "application/bitcoin-paymentrequest";
PayPro.PAYMENT_CONTENT_TYPE = "application/bitcoin-payment";
PayPro.PAYMENT_ACK_CONTENT_TYPE = "application/bitcoin-paymentack";

PayPro.RootCerts = RootCerts;

PayPro.proto = {};

PayPro.proto.Output = "message Output {\
  optional uint64 amount = 1 [default = 0];\
  optional bytes script = 2;\
}\n";

PayPro.proto.PaymentDetails = "message PaymentDetails {\
  optional string network = 1 [default = \"main\"];\
  repeated Output outputs = 2;\
  required uint64 time = 3;\
  optional uint64 expires = 4;\
  optional string memo = 5;\
  optional string payment_url = 6;\
  optional bytes merchant_data = 7;\
}\n";

PayPro.proto.PaymentRequest = "message PaymentRequest {\
  optional uint32 payment_details_version = 1 [default = 1];\
  optional string pki_type = 2 [default = \"none\"];\
  optional bytes pki_data = 3;\
  required bytes serialized_payment_details = 4;\
  optional bytes signature = 5;\
}\n";

PayPro.proto.Payment = "message Payment {\
  optional bytes merchant_data = 1;\
  repeated bytes transactions = 2;\
  repeated Output refund_to = 3;\
  optional string memo = 4;\
}\n";

PayPro.proto.PaymentACK = "message PaymentACK {\
  required Payment payment = 1;\
  optional string memo = 2;\
}\n";

PayPro.proto.X509Certificates = "message X509Certificates {\
  repeated bytes certificate = 1;\
}\n";

PayPro.proto.all = "";
PayPro.proto.all = PayPro.proto.all + PayPro.proto.Output;
PayPro.proto.all = PayPro.proto.all + PayPro.proto.PaymentDetails;
PayPro.proto.all = PayPro.proto.all + PayPro.proto.PaymentRequest;
PayPro.proto.all = PayPro.proto.all + PayPro.proto.Payment;
PayPro.proto.all = PayPro.proto.all + PayPro.proto.PaymentACK;
PayPro.proto.all = PayPro.proto.all + PayPro.proto.X509Certificates;

PayPro.builder = protobufjs.loadProto(PayPro.proto.all);

PayPro.Output = PayPro.builder.build("Output");
PayPro.PaymentDetails = PayPro.builder.build("PaymentDetails");
PayPro.PaymentRequest = PayPro.builder.build("PaymentRequest");
PayPro.Payment = PayPro.builder.build("Payment");
PayPro.PaymentACK = PayPro.builder.build("PaymentACK");
PayPro.X509Certificates = PayPro.builder.build("X509Certificates");

PayPro.prototype.makeOutput = function(obj) {
  this.messageType = 'Output';
  this.message = new PayPro.Output();
  this.setObj(obj);
  return this;
};

PayPro.prototype.makePaymentDetails = function(obj) {
  this.messageType = 'PaymentDetails';
  this.message = new PayPro.PaymentDetails();
  this.setObj(obj);
  return this;
};

PayPro.prototype.makePaymentRequest = function(obj) {
  this.messageType = 'PaymentRequest';
  this.message = new PayPro.PaymentRequest();
  this.setObj(obj);
  return this;
};

PayPro.prototype.makePayment = function(obj) {
  this.messageType = 'Payment';
  this.message = new PayPro.Payment();
  this.setObj(obj);
  return this;
};

PayPro.prototype.makePaymentACK = function(obj) {
  this.messageType = 'PaymentACK';
  this.message = new PayPro.PaymentACK();
  this.setObj(obj);
  return this;
};

PayPro.prototype.makeX509Certificates = function(obj) {
  this.messageType = 'X509Certificates';
  this.message = new PayPro.X509Certificates();
  this.setObj(obj);
  return this;
};

PayPro.prototype.isValidSize = function() {
  var s = this.serialize();
  if (this.messageType == 'PaymentRequest')
    return s.length < PayPro.PAYMENT_REQUEST_MAX_SIZE;
  if (this.messageType == 'Payment')
    return s.length < PayPro.PAYMENT_MAX_SIZE;
  if (this.messageType == 'PaymentACK')
    return s.length < PayPro.PAYMENT_ACK_MAX_SIZE;
  return true;
};

PayPro.prototype.getContentType = function() {
  if (this.messageType == 'PaymentRequest')
    return PayPro.PAYMENT_REQUEST_CONTENT_TYPE;

  if (this.messageType == 'Payment')
    return PayPro.PAYMENT_CONTENT_TYPE;

  if (this.messageType == 'PaymentACK')
    return PayPro.PAYMENT_ACK_CONTENT_TYPE;

  throw new Error('No known content type for this message type');
};

PayPro.prototype.set = function(key, val) {
  this.message.set(key, val);
  return this;
};

PayPro.prototype.get = function(key) {
  var v = this.message.get(key);

  if (v === null)
    return v;

  //protobuf supports longs, javascript naturally does not
  //convert longs (see long.js, e.g. require('long')) to Numbers
  if (typeof v.low !== 'undefined' && typeof v.high !== 'undefined')
    return v.toInt();

  if (typeof v.toBuffer !== 'undefined') {
    var maybebuf = v.toBuffer();
    return Buffer.isBuffer(maybebuf) ? maybebuf : new Buffer(new Uint8Array(maybebuf));
  }

  return v;
};

PayPro.prototype.setObj = function(obj) {
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      var val = obj[key];
      this.message.set(key, val);
    }
  }
  return this;
};

PayPro.prototype.serializeForSig = function() {
  if (this.messageType !== 'PaymentRequest')
    throw new Error('serializeForSig is only for PaymentRequest');

  var save = this.message.get('signature');
  this.message.set('signature', new Buffer([]));
  var buf = this.serialize();
  this.message.set('signature', save);
  return buf;
};

PayPro.prototype.serialize = function() {
  //protobufjs returns either a Buffer or an ArrayBuffer
  //but we always want a Buffer (which browserify understands, browser or no)
  var maybebuf = this.message.toBuffer();
  var buf = (Buffer.isBuffer(maybebuf)) ? maybebuf : new Buffer(new Uint8Array(maybebuf));
  return buf;
};

PayPro.prototype.deserialize = function(buf, messageType) {
  this.messageType = messageType || this.messageType;
  if (!this.messageType)
    throw new Error('Must specify messageType');
  this.message = PayPro[this.messageType].decode(buf);
  return this;
};

PayPro.prototype.sign = function(key) {
  if (this.messageType !== 'PaymentRequest')
    throw new Error('Signing can only be performed on a PaymentRequest');

  var pki_type = this.get('pki_type');

  if (pki_type === 'SIN') {
    var sig = this.sinSign(key);
  } else if (pki_type === 'x509+sha1' || pki_type === 'x509+sha256') {
    var sig = this.x509Sign(key);
  } else if (pki_type === 'none') {
    return this;
  } else {
    throw new Error('Unsupported pki_type');
  }

  this.set('signature', sig);

  return this;
};

PayPro.prototype.verify = function() {
  if (this.messageType !== 'PaymentRequest')
    throw new Error('Verifying can only be performed on a PaymentRequest');

  var pki_type = this.get('pki_type');

  if (pki_type === 'SIN') {
    return this.sinVerify();
  } else if (pki_type === 'x509+sha1' || pki_type === 'x509+sha256') {
    return this.x509Verify();
  } else if (pki_type === 'none') {
    return true;
  }

  throw new Error('Unsupported pki_type');
};

//default signing function for prototype.sign
PayPro.prototype.sinSign = function(key) {
  this.set('pki_data', key.public)
  var buf = this.serializeForSig();
  return Message.sign(buf, key);
};

//default verify function
PayPro.prototype.sinVerify = function() {
  var sig = this.get('signature');
  var pubkey = this.get('pki_data');
  var buf = this.serializeForSig();
  return Message.verifyWithPubKey(pubkey, buf, sig);
};

// Helpers

PayPro.prototype._PEMtoDER = function(pem) {
  return this._PEMtoDERParam(pem);
};

PayPro.prototype._PEMtoDERParam = function(pem, param) {
  if (Buffer.isBuffer(pem)) {
    pem = pem.toString();
  }
  var start = new RegExp('(?=-----BEGIN ' + (param || '[^-]+') + '-----)', 'i');
  var end = new RegExp('^-----END ' + (param || '[^-]+') + '-----$', 'gmi');
  pem = pem.replace(end, '');
  var parts = pem.split(start);
  return parts.map(function(part) {
    var type = /-----BEGIN ([^-]+)-----/.exec(part)[1];
    part = part.replace(/-----BEGIN ([^-]+)-----/g, '');
    part = part.replace(/\s+/g, '');
    if (!param || type !== param) return;
    return new Buffer(part, 'base64');
  }).filter(Boolean);
};

PayPro.prototype._DERtoPEM = function(der, type) {
  if (typeof der === 'string') {
    der = new Buffer(der, 'hex');
  }
  var type = type || 'UNKNOWN';
  der = der.toString('base64');
  der = der.replace(/(.{64})/g, '$1\r\n');
  der = der.replace(/\r\n$/, '');
  return ''
    + '-----BEGIN ' + type + '-----\r\n'
    + der
    + '\r\n-----END ' + type + '-----\r\n';
};

module.exports = PayPro;
<|endoftext|>


<commit_before>// Copyright (c) 2016, Matt Godbolt
// 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.
//
// 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 HOLDER 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.

const BaseCompiler = require('../base-compiler'),
    argumentParsers = require("./argument-parsers"),
    compilerOptInfo = require("compiler-opt-info"),
    fs = require('fs-extra');

class LDCCompiler extends BaseCompiler {
    constructor(info, env) {
        super(info, env);
        this.compiler.supportsIntel = true;
    }

    optionsForFilter(filters, outputFilename) {
        let options = ['-g', '-of', this.filename(outputFilename)];
        if (filters.intel && !filters.binary) options = options.concat('-x86-asm-syntax=intel');
        if (!filters.binary) options = options.concat('-output-s');
        return options;
    }

    getArgumentParser() {
        return argumentParsers.Clang;
    }

    filterUserOptions(userOptions) {
        return userOptions.filter(option => option !== '-run');
    }

    isCfgCompiler() {
        return true;
    }

    couldSupportASTDump(version) {
        const versionRegex = /\((\d\.\d+)\.\d+/;
        const versionMatch = versionRegex.exec(version);

        if (versionMatch) {
            const versionNum = parseFloat(versionMatch[1]);
            return versionNum >= 1.4;
        }

        return false;
    }

    generateAST(inputFilename, options) {
        // These options make LDC produce an AST dump in a separate file `<inputFilename>.cg`.
        let newOptions = options.concat("-vcg-ast");
        let execOptions = this.getDefaultExecOptions();
        return this.runCompiler(this.compiler.exe, newOptions, this.filename(inputFilename), execOptions)
            .then(this.loadASTOutput);
    }

    loadASTOutput(output) {
        // Load the AST output from the `.cg` file.
        // Demangling is not needed.
        return fs.readFileSync(output.inputFilename.concat(".cg"), 'utf-8');
    }

    processOptOutput(hasOptOutput, optPath, demangle) {
        let output = [];
        return new Promise(resolve => {
            fs.createReadStream(optPath, {encoding: "utf-8"})
                .pipe(new compilerOptInfo.LLVMOptTransformer())
                .on("data", opt => {
                    if (opt.DebugLoc && opt.DebugLoc.File && opt.DebugLoc.File.indexOf(this.compileFilename) > -1) {
                        output.push(opt);
                    }
                })
                .on("end", () => resolve(output));
        });
    }
}

module.exports = LDCCompiler;
<commit_msg>Add some logging for missing .cg file<commit_after>// Copyright (c) 2016, Matt Godbolt
// 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.
//
// 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 HOLDER 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.

const BaseCompiler = require('../base-compiler'),
    argumentParsers = require("./argument-parsers"),
    compilerOptInfo = require("compiler-opt-info"),
    fs = require('fs-extra');

class LDCCompiler extends BaseCompiler {
    constructor(info, env) {
        super(info, env);
        this.compiler.supportsIntel = true;
    }

    optionsForFilter(filters, outputFilename) {
        let options = ['-g', '-of', this.filename(outputFilename)];
        if (filters.intel && !filters.binary) options = options.concat('-x86-asm-syntax=intel');
        if (!filters.binary) options = options.concat('-output-s');
        return options;
    }

    getArgumentParser() {
        return argumentParsers.Clang;
    }

    filterUserOptions(userOptions) {
        return userOptions.filter(option => option !== '-run');
    }

    isCfgCompiler() {
        return true;
    }

    couldSupportASTDump(version) {
        const versionRegex = /\((\d\.\d+)\.\d+/;
        const versionMatch = versionRegex.exec(version);

        if (versionMatch) {
            const versionNum = parseFloat(versionMatch[1]);
            return versionNum >= 1.4;
        }

        return false;
    }

    generateAST(inputFilename, options) {
        // These options make LDC produce an AST dump in a separate file `<inputFilename>.cg`.
        let newOptions = options.concat("-vcg-ast");
        let execOptions = this.getDefaultExecOptions();
        return this.runCompiler(this.compiler.exe, newOptions, this.filename(inputFilename), execOptions)
            .then(this.loadASTOutput);
    }

    loadASTOutput(output) {
        // Load the AST output from the `.cg` file.
        // Demangling is not needed.
        const astFilename = output.inputFilename.concat(".cg");
        if (!fs.existsSync(astFilename)) {
            logger.warning(`LDC AST file ${astFilename} requested but it does not exist`);
            return "";
        }
        return fs.readFileSync(astFilename, 'utf-8');
    }

    processOptOutput(hasOptOutput, optPath, demangle) {
        let output = [];
        return new Promise(resolve => {
            fs.createReadStream(optPath, {encoding: "utf-8"})
                .pipe(new compilerOptInfo.LLVMOptTransformer())
                .on("data", opt => {
                    if (opt.DebugLoc && opt.DebugLoc.File && opt.DebugLoc.File.indexOf(this.compileFilename) > -1) {
                        output.push(opt);
                    }
                })
                .on("end", () => resolve(output));
        });
    }
}

module.exports = LDCCompiler;
<|endoftext|>


<commit_before>/*
 *   Copyright 2014-2015 Guy Bedford (http://guybedford.com)
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

var registry = require('../registry');
var config = require('../config');
var extend = require('../common').extend;
var hasProperties = require('../common').hasProperties;
var fs = require('graceful-fs');
var asp = require('rsvp').denodeify;
var path = require('path');
var PackageName = require('./package-name');
var alphabetize = require('../common').alphabetize;
var stringify = require('../common').stringify;
var ui = require('../ui');
var extractObj = require('./utils').extractObj;
var globalConfig = require('../global-config');

/*
 * Loader Configuration Class
 *
 * baseURL
 * registries
 * transpiler
 * babelOptions
 * traceurOptions
 *
 * paths
 * bundles
 * depCache
 *
 * baseMap
 * depMap
 * versions
 *
 */
// and registry is a path rule ending in ':*'
var registryRegEx = /\:\*$/;
function Config(fileName) {
  this.__fileName = fileName;
}
Config.prototype.read = function(prompts, sync) {
  if (this.__read)
    throw 'Config already read';
  this.__read = true;

  var self = this;
  var source;
  try {
    source = fs.readFileSync(this.__fileName);
  }
  catch(e) {
    source = '';
  }

  var cfg = {};
  var System = {
    config: function(_cfg) {
      for (var c in _cfg) {
        if (!_cfg.hasOwnProperty(c))
          continue;

        var v = _cfg[c];
        if (typeof v === 'object') {
          cfg[c] = cfg[c] || {};
          for (var p in v) {
            if (!v.hasOwnProperty(p))
              continue;
            cfg[c][p] = v[p];
          }
        }
        else
          cfg[c] = v;
      }
    },
    paths: {},
    map: {},
    versions: {}
  };
  eval(source.toString());

  // allow declarative form too
  var config = System.config;
  delete System.config;
  config(System);

  self.__originalConfig = cfg;

  self.baseURL = cfg.baseURL;

  // NB deprecate cfg.parser with 0.11.0
  self.transpiler = cfg.transpiler || cfg.parser || globalConfig.config.defaultTranspiler;
  // NB deprecate babel rename with 0.13
  if (self.transpiler === '6to5')
    self.transpiler = 'babel';

  self.babelOptions = cfg.babelOptions || {};
  self.traceurOptions = cfg.traceurOptions || {};

  // separate paths into registries and paths
  self.registries = {};
  self.paths = {};
  for (var p in cfg.paths) {
    if (p.match(registryRegEx)) {
      var registryName = p.substr(0, p.length - 2);
      var registryPath = new RegistryPath(registryName, cfg.paths[p]);
      self.registries[registryName] = registryPath;
      if (self.__local === undefined) {
        if (registryPath.mode === 'local')
          self.__local = true;
        else
          self.__local = false;
      }
    }
    else {
      self.paths[p] = cfg.paths[p];
    }
  }

  self.paths = cfg.paths;

  self.shim = cfg.shim;
  self.bundles = cfg.bundles;
  self.depCache = cfg.depCache;

  // separate map into baseMap and depMap
  self.baseMap = {};
  self.depMap = {};
  for (var d in cfg.map) {
    if (typeof cfg.map[d] === 'string')
      self.baseMap[d] = new PackageName(cfg.map[d]);
    else {
      var depMap = cfg.map[d];
      self.depMap[d] = {};
      for (var m in depMap)
        if (depMap.hasOwnProperty(m)) {
          self.depMap[d][m] = new PackageName(depMap[m]);
        }
    }
  }

  // ensure that everything in baseMap has a depMap, even if empty
  var baseMap = self.baseMap, exactName;
  for (var n in baseMap) {
    if (baseMap.hasOwnProperty(n)) {
      exactName = baseMap[n].exactName;
      self.depMap[exactName] = self.depMap[exactName] || {};
    }
  }

  self.versions = self.versions || {};
  for (var v in cfg.versions) {
    if (typeof cfg.versions[v] === 'string')
      self.versions[v] = [cfg.versions[v]];
    else
      self.versions[v] = cfg.versions[v];
  }

  if (hasProperties(self.versions))
    upgradeToExactVersionResolution(self);

  if (!prompts)
    return;

  if (sync)
    throw 'Configuration file has not been initialized. Run jspm init first.';

  return ui.input('Enter client baseURL (public folder URL)', self.baseURL || '/')
  .then(function(baseURL) {
    self.baseURL = baseURL;

    return ui.input('Which ES6 transpiler would you like to use, %Traceur% or %Babel%?', self.transpiler);
  })
  .then(function(transpiler) {
    transpiler = transpiler.toLowerCase();
    if (transpiler !== 'babel')
      transpiler = 'traceur';
    self.transpiler = transpiler;
    globalConfig.config.defaultTranspiler = transpiler;
  });
};

Config.prototype.ensureRegistry = function(registryName, remote) {
  var registries = this.registries;

  if (typeof remote === 'undefined') {
    // detect the registry mode from the first registry
    var registryKeys = Object.keys(registries);
    if (registryKeys.length > 0) {
      remote = registries[registryKeys[0]].mode === 'remote';
    } else {
      remote = false;
    }
  }

  if (registries[registryName]) {
    if (remote)
      registries[registryName].setRemote();
    else
      registries[registryName].setLocal();
    return;
  }

  var ep = registries[registryName] = new RegistryPath(registryName);
  if (remote)
    ep.setRemote();
  else
    ep.setLocal();
};

// return the loader configuration for a server loading use
Config.prototype.getConfig = function() {
  var cfg = extend({}, this.__originalConfig);

  // set all registry paths to be local paths
  cfg.paths = extend({}, cfg.paths);
  var registries = this.registries;
  for (var e in registries) {
    if (registries.hasOwnProperty(e))
      cfg.paths[e + ':*'] = registries[e].local;
  }
  return cfg;
};

/*
 * RegistryPath object
 */
var jspmPackages;
function RegistryPath(name, registryPath) {
  jspmPackages = jspmPackages || path.relative(config.pjson.baseURL, config.pjson.packages).replace(/\\/g, '/');
  var registryRemote = registry.load(name).remote;
  this.remote = registryRemote + '/*.js';
  this.local = jspmPackages + '/' + name + '/*.js';

  this.mode = 'local';
  if (registryPath === this.remote)
    this.mode = 'remote';
  this.path = registryPath;
}
RegistryPath.prototype.setLocal = function() {
  this.path = this.local;
  this.mode = 'local';
};
RegistryPath.prototype.setRemote = function() {
  this.path = this.remote;
  this.mode = 'remote';
};
RegistryPath.prototype.write = function() {
  return this.path;
};

Config.prototype.write = function() {
  // extract over original config to keep initial values
  var cfg = extractObj(this, this.__originalConfig),
      cfgRegistries, cfgMap, cfgVersions;

  // allow * path to be overridden
  if (!cfg.paths['*'])
    cfg.paths['*'] = '*.js';

  cfgRegistries = cfg.registries;
  for (var e in cfgRegistries) {
    if (!cfgRegistries.hasOwnProperty(e))
      continue;
    var val = cfgRegistries[e];
    delete cfgRegistries[e];
    cfgRegistries[e + ':*'] = val;
  }

  extend(cfg.paths, alphabetize(cfg.registries));
  delete cfg.registries;

  cfg.baseMap = alphabetize(cfg.baseMap);
  cfg.map = extend(cfg.baseMap, alphabetize(cfg.depMap));
  delete cfg.baseMap;
  delete cfg.depMap;

  cfgMap = cfg.map;
  for (var p in cfgMap) {
    if (!cfgMap.hasOwnProperty(p))
      continue;
    var subMap = cfgMap[p];
    if (typeof subMap === 'object') {
      if (!hasProperties(subMap))
        delete cfgMap[p];
      else
        cfgMap[p] = alphabetize(cfgMap[p]);
    }
  }

  cfgVersions = cfg.versions;
  for (var v in cfgVersions) {
    if (!cfgVersions.hasOwnProperty(v))
      continue;
    var version = cfgVersions[v];
    if (version.length === 1)
      cfgVersions[v] = version[0];
    if (version.length === 0)
      delete cfgVersions[v];
  }

  var configContent = '';

  var meta = cfg.meta;
  var depCache = cfg.depCache;
  var map = cfg.map;
  var versions = alphabetize(cfg.versions);

  delete cfg.meta;
  delete cfg.depCache;
  delete cfg.map;
  delete cfg.versions;

  if (cfg.transpiler === 'traceur')
    delete cfg.transpiler;

  if (!hasProperties(cfg.babelOptions))
    delete cfg.babelOptions;
  if (!hasProperties(cfg.traceurOptions))
    delete cfg.traceurOptions;

  if (cfg.bundles && !hasProperties(cfg.bundles))
    delete cfg.bundles;

  if (hasProperties(cfg))
    configContent += 'System.config(' + stringify(cfg) + ');' + config.newLine + config.newLine;

  cfg.meta = meta;
  cfg.depCache = depCache;
  cfg.map = map;
  cfg.versions = versions;

  if (hasProperties(meta))
    configContent += 'System.config(' + stringify({ meta: meta }) + ');' + config.newLine + config.newLine;

  if (hasProperties(depCache))
    configContent += 'System.config(' + stringify({ depCache: depCache }) + ');' + config.newLine + config.newLine;

  if (hasProperties(map))
    configContent += 'System.config(' + stringify({ map: map }) + ');' + config.newLine + config.newLine;

  if (hasProperties(versions))
    configContent += 'System.config(' + stringify({ versions: versions }) + ');' + config.newLine + config.newLine;

  return asp(fs.writeFile)(this.__fileName, configContent);
};
module.exports = Config;

// --- can be removed after jspm@0.8 is fully deprecated --
var semver = require('../semver');
function upgradeToExactVersionResolution(config) {
  // run through depMap and baseMap, and assign exact version matches
  Object.keys(config.baseMap).forEach(function(p) {
    upgradeToExactVersionResolveRange(config.baseMap[p], config);
  });

  Object.keys(config.depMap).forEach(function(p) {
    var curMap = config.depMap[p];
    Object.keys(curMap).forEach(function(p) {
      upgradeToExactVersionResolveRange(curMap[p], config);
    });
  });

  config.versions = {};
}
function upgradeToExactVersionResolveRange(range, config) {
  var versions = config.versions[range.name];
  if (versions)
  versions.sort(semver.compare).reverse().some(function(version) {
    if (semver.match(range.version, version)) {
      range.setVersion(version);
      return true;
    }
  });
}
<commit_msg>default transpiler fix<commit_after>/*
 *   Copyright 2014-2015 Guy Bedford (http://guybedford.com)
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

var registry = require('../registry');
var config = require('../config');
var extend = require('../common').extend;
var hasProperties = require('../common').hasProperties;
var fs = require('graceful-fs');
var asp = require('rsvp').denodeify;
var path = require('path');
var PackageName = require('./package-name');
var alphabetize = require('../common').alphabetize;
var stringify = require('../common').stringify;
var ui = require('../ui');
var extractObj = require('./utils').extractObj;
var globalConfig = require('../global-config');

/*
 * Loader Configuration Class
 *
 * baseURL
 * registries
 * transpiler
 * babelOptions
 * traceurOptions
 *
 * paths
 * bundles
 * depCache
 *
 * baseMap
 * depMap
 * versions
 *
 */
// and registry is a path rule ending in ':*'
var registryRegEx = /\:\*$/;
function Config(fileName) {
  this.__fileName = fileName;
}
Config.prototype.read = function(prompts, sync) {
  if (this.__read)
    throw 'Config already read';
  this.__read = true;

  var self = this;
  var source;
  try {
    source = fs.readFileSync(this.__fileName);
  }
  catch(e) {
    source = '';
  }

  var cfg = {};
  var System = {
    config: function(_cfg) {
      for (var c in _cfg) {
        if (!_cfg.hasOwnProperty(c))
          continue;

        var v = _cfg[c];
        if (typeof v === 'object') {
          cfg[c] = cfg[c] || {};
          for (var p in v) {
            if (!v.hasOwnProperty(p))
              continue;
            cfg[c][p] = v[p];
          }
        }
        else
          cfg[c] = v;
      }
    },
    paths: {},
    map: {},
    versions: {}
  };
  eval(source.toString());

  // allow declarative form too
  var config = System.config;
  delete System.config;
  config(System);

  self.__originalConfig = cfg;

  self.baseURL = cfg.baseURL;

  // NB deprecate cfg.parser with 0.11.0
  self.transpiler = cfg.transpiler || cfg.parser || globalConfig.config.defaultTranspiler;
  // NB deprecate babel rename with 0.13
  if (self.transpiler === '6to5')
    self.transpiler = 'babel';

  self.babelOptions = cfg.babelOptions || {};
  self.traceurOptions = cfg.traceurOptions || {};

  // separate paths into registries and paths
  self.registries = {};
  self.paths = {};
  for (var p in cfg.paths) {
    if (p.match(registryRegEx)) {
      var registryName = p.substr(0, p.length - 2);
      var registryPath = new RegistryPath(registryName, cfg.paths[p]);
      self.registries[registryName] = registryPath;
      if (self.__local === undefined) {
        if (registryPath.mode === 'local')
          self.__local = true;
        else
          self.__local = false;
      }
    }
    else {
      self.paths[p] = cfg.paths[p];
    }
  }

  self.paths = cfg.paths;

  self.shim = cfg.shim;
  self.bundles = cfg.bundles;
  self.depCache = cfg.depCache;

  // separate map into baseMap and depMap
  self.baseMap = {};
  self.depMap = {};
  for (var d in cfg.map) {
    if (typeof cfg.map[d] === 'string')
      self.baseMap[d] = new PackageName(cfg.map[d]);
    else {
      var depMap = cfg.map[d];
      self.depMap[d] = {};
      for (var m in depMap)
        if (depMap.hasOwnProperty(m)) {
          self.depMap[d][m] = new PackageName(depMap[m]);
        }
    }
  }

  // ensure that everything in baseMap has a depMap, even if empty
  var baseMap = self.baseMap, exactName;
  for (var n in baseMap) {
    if (baseMap.hasOwnProperty(n)) {
      exactName = baseMap[n].exactName;
      self.depMap[exactName] = self.depMap[exactName] || {};
    }
  }

  self.versions = self.versions || {};
  for (var v in cfg.versions) {
    if (typeof cfg.versions[v] === 'string')
      self.versions[v] = [cfg.versions[v]];
    else
      self.versions[v] = cfg.versions[v];
  }

  if (hasProperties(self.versions))
    upgradeToExactVersionResolution(self);

  if (!prompts)
    return;

  if (sync)
    throw 'Configuration file has not been initialized. Run jspm init first.';

  return ui.input('Enter client baseURL (public folder URL)', self.baseURL || '/')
  .then(function(baseURL) {
    self.baseURL = baseURL;

    return ui.input('Which ES6 transpiler would you like to use, %Traceur% or %Babel%?', self.transpiler);
  })
  .then(function(transpiler) {
    transpiler = transpiler.toLowerCase();
    if (transpiler !== 'babel' && transpiler !== 'traceur')
      transpiler = globalConfig.config.defaultTranspiler;
    self.transpiler = transpiler;
    globalConfig.config.defaultTranspiler = transpiler;
  });
};

Config.prototype.ensureRegistry = function(registryName, remote) {
  var registries = this.registries;

  if (typeof remote === 'undefined') {
    // detect the registry mode from the first registry
    var registryKeys = Object.keys(registries);
    if (registryKeys.length > 0) {
      remote = registries[registryKeys[0]].mode === 'remote';
    } else {
      remote = false;
    }
  }

  if (registries[registryName]) {
    if (remote)
      registries[registryName].setRemote();
    else
      registries[registryName].setLocal();
    return;
  }

  var ep = registries[registryName] = new RegistryPath(registryName);
  if (remote)
    ep.setRemote();
  else
    ep.setLocal();
};

// return the loader configuration for a server loading use
Config.prototype.getConfig = function() {
  var cfg = extend({}, this.__originalConfig);

  // set all registry paths to be local paths
  cfg.paths = extend({}, cfg.paths);
  var registries = this.registries;
  for (var e in registries) {
    if (registries.hasOwnProperty(e))
      cfg.paths[e + ':*'] = registries[e].local;
  }
  return cfg;
};

/*
 * RegistryPath object
 */
var jspmPackages;
function RegistryPath(name, registryPath) {
  jspmPackages = jspmPackages || path.relative(config.pjson.baseURL, config.pjson.packages).replace(/\\/g, '/');
  var registryRemote = registry.load(name).remote;
  this.remote = registryRemote + '/*.js';
  this.local = jspmPackages + '/' + name + '/*.js';

  this.mode = 'local';
  if (registryPath === this.remote)
    this.mode = 'remote';
  this.path = registryPath;
}
RegistryPath.prototype.setLocal = function() {
  this.path = this.local;
  this.mode = 'local';
};
RegistryPath.prototype.setRemote = function() {
  this.path = this.remote;
  this.mode = 'remote';
};
RegistryPath.prototype.write = function() {
  return this.path;
};

Config.prototype.write = function() {
  // extract over original config to keep initial values
  var cfg = extractObj(this, this.__originalConfig),
      cfgRegistries, cfgMap, cfgVersions;

  // allow * path to be overridden
  if (!cfg.paths['*'])
    cfg.paths['*'] = '*.js';

  cfgRegistries = cfg.registries;
  for (var e in cfgRegistries) {
    if (!cfgRegistries.hasOwnProperty(e))
      continue;
    var val = cfgRegistries[e];
    delete cfgRegistries[e];
    cfgRegistries[e + ':*'] = val;
  }

  extend(cfg.paths, alphabetize(cfg.registries));
  delete cfg.registries;

  cfg.baseMap = alphabetize(cfg.baseMap);
  cfg.map = extend(cfg.baseMap, alphabetize(cfg.depMap));
  delete cfg.baseMap;
  delete cfg.depMap;

  cfgMap = cfg.map;
  for (var p in cfgMap) {
    if (!cfgMap.hasOwnProperty(p))
      continue;
    var subMap = cfgMap[p];
    if (typeof subMap === 'object') {
      if (!hasProperties(subMap))
        delete cfgMap[p];
      else
        cfgMap[p] = alphabetize(cfgMap[p]);
    }
  }

  cfgVersions = cfg.versions;
  for (var v in cfgVersions) {
    if (!cfgVersions.hasOwnProperty(v))
      continue;
    var version = cfgVersions[v];
    if (version.length === 1)
      cfgVersions[v] = version[0];
    if (version.length === 0)
      delete cfgVersions[v];
  }

  var configContent = '';

  var meta = cfg.meta;
  var depCache = cfg.depCache;
  var map = cfg.map;
  var versions = alphabetize(cfg.versions);

  delete cfg.meta;
  delete cfg.depCache;
  delete cfg.map;
  delete cfg.versions;

  if (!hasProperties(cfg.babelOptions))
    delete cfg.babelOptions;
  if (!hasProperties(cfg.traceurOptions))
    delete cfg.traceurOptions;

  if (cfg.bundles && !hasProperties(cfg.bundles))
    delete cfg.bundles;

  if (hasProperties(cfg))
    configContent += 'System.config(' + stringify(cfg) + ');' + config.newLine + config.newLine;

  cfg.meta = meta;
  cfg.depCache = depCache;
  cfg.map = map;
  cfg.versions = versions;

  if (hasProperties(meta))
    configContent += 'System.config(' + stringify({ meta: meta }) + ');' + config.newLine + config.newLine;

  if (hasProperties(depCache))
    configContent += 'System.config(' + stringify({ depCache: depCache }) + ');' + config.newLine + config.newLine;

  if (hasProperties(map))
    configContent += 'System.config(' + stringify({ map: map }) + ');' + config.newLine + config.newLine;

  if (hasProperties(versions))
    configContent += 'System.config(' + stringify({ versions: versions }) + ');' + config.newLine + config.newLine;

  return asp(fs.writeFile)(this.__fileName, configContent);
};
module.exports = Config;

// --- can be removed after jspm@0.8 is fully deprecated --
var semver = require('../semver');
function upgradeToExactVersionResolution(config) {
  // run through depMap and baseMap, and assign exact version matches
  Object.keys(config.baseMap).forEach(function(p) {
    upgradeToExactVersionResolveRange(config.baseMap[p], config);
  });

  Object.keys(config.depMap).forEach(function(p) {
    var curMap = config.depMap[p];
    Object.keys(curMap).forEach(function(p) {
      upgradeToExactVersionResolveRange(curMap[p], config);
    });
  });

  config.versions = {};
}
function upgradeToExactVersionResolveRange(range, config) {
  var versions = config.versions[range.name];
  if (versions)
  versions.sort(semver.compare).reverse().some(function(version) {
    if (semver.match(range.version, version)) {
      range.setVersion(version);
      return true;
    }
  });
}
<|endoftext|>


<commit_before>'use strict';
/* jshint camelcase: false */

/**
 * Module dependencies
 */
var _ = require('lodash');
var crypto = require('crypto');
var mongo = require('mongodb');
var util = require('util');
var debug = require('debug')('connect-mongo');
var deprecate = require('depd')('connect-mongo');

var MongoClient = mongo.MongoClient;

/**
 * Default options
 */
var defaultOptions = {
  // Legacy strategy default options
  host: '127.0.0.1',
  port: 27017,
  autoReconnect: true,
  ssl: false,
  w: 1,

  // Global options
  collection: 'sessions',
  stringify: true,
  hash: false,
  ttl:  60 * 60 * 24 * 14, // 14 days
  autoRemove: 'native',
  autoRemoveInterval: 10
};

var defaultHashOptions = {
  salt: 'connect-mongo',
  algorithm: 'sha1'
};

var defaultSerializationOptions = {
  serialize: function (session) {
    // Copy each property of the session to a new object
    var obj = {};
    for (var prop in session) {
      if (prop === 'cookie') {

      // Convert the cookie instance to an object, if possible
      // This gets rid of the duplicate object under session.cookie.data property

        obj.cookie = session.cookie.toJSON ? session.cookie.toJSON() : session.cookie;
      } else {
        obj[prop] = session[prop];
      }
    }

    return obj;
  },
  unserialize: _.identity
};

var stringifySerializationOptions = {
  serialize: JSON.stringify,
  unserialize: JSON.parse
};

module.exports = function(connect) {
  var Store = connect.Store || connect.session.Store;
  var MemoryStore = connect.MemoryStore || connect.session.MemoryStore;

  /**
   * Initialize MongoStore with the given `options`.
   *
   * @param {Object} options
   * @api public
   */

  function MongoStore(options) {

    /* Deprecated options */

    if ('auto_reconnect' in options) {
      deprecate('auto_reconnect option is deprecated. Use autoReconnect instead');
      options.autoReconnect = options.auto_reconnect;
    }

    if ('mongoose_connection' in options) {
      deprecate('mongoose_connection option is deprecated. Use mongooseConnection instead');
      options.mongooseConnection = options.mongoose_connection;
    }

    if ('defaultExpirationTime' in options) {
      deprecate('defaultExpirationTime option is deprecated. Use ttl instead');
      options.ttl = options.defaultExpirationTime / 1000;
    }

    /* Fallback */

    if (options.fallbackMemory && MemoryStore) {
      return new MemoryStore();
    }

    /* Options */

    options = _.defaults(options || {}, defaultOptions);

    if (options.hash) {
      options.hash = _.defaults(options.hash, defaultHashOptions);
    }

    if (!options.stringify || options.serialize || options.unserialize) {
      options = _.defaults(options, defaultSerializationOptions);
    } else {
      options = _.assign(options, stringifySerializationOptions);
    }

    this.options =  options;

    Store.call(this, options);

    var self = this;

    function changeState(newState) {
      debug('switched to state: %s', newState);
      self.state = newState;
      self.emit(newState);
    }

    function connectionReady(err) {
      if (err) {
          debug('not able to connect to the database');
          changeState('disconnected');
          throw err;
      }

      self.collection = self.db.collection(options.collection);

      switch (options.autoRemove) {

        case 'native':
          self.collection.ensureIndex({ expires: 1 }, { expireAfterSeconds: 0 }, function (err) {
            if (err) throw err;
            changeState('connected');
          });
          break;

        case 'interval':
          setInterval(function () {
            self.collection.remove({ expires: { $lt: new Date() } }, { w: 0 });
          }, options.autoRemoveInterval * 1000 * 60);
          changeState('connected');
          break;

        default:
          changeState('connected');
          break;

      }
    }

    function buildUrlFromOptions() {
      if(!options.db || typeof options.db !== 'string') {
        throw new Error('Required MongoStore option `db` missing or is not a string.');
      }

      options.url = 'mongodb://';

      if (options.username) {
        options.url += options.username + ':' + (options.password || '') + '@';
      }

      options.url += options.host + ':' + options.port + '/' + options.db;

      if (options.ssl) options.url += '?ssl=true';

      if (!options.mongoOptions) {
        options.mongoOptions = {
          server: { auto_reconnect: options.autoReconnect },
          db: { w: options.w }
        };
      }
    }

    function initWithUrl() {
      MongoClient.connect(options.url, options.mongoOptions || {}, function(err, db) {
        if (!err) self.db = db;
        connectionReady(err);
      });
    }

    function initWithMongooseConnection() {
      if (options.mongooseConnection.readyState === 1) {
        self.db = options.mongooseConnection.db;
        process.nextTick(connectionReady);
      } else {
        options.mongooseConnection.once('open', function() {
          self.db = options.mongooseConnection.db;
          connectionReady();
        });
      }
    }

    function initWithNativeDb() {
      self.db = options.db;

      if (options.db.openCalled || options.db.openCalled === undefined) { // openCalled is undefined in mongodb@2.x
        options.db.collection(options.collection, connectionReady);
      } else {
        options.db.open(connectionReady);
      }
    }

    this.getCollection = function (done) {
      switch (self.state) {
        case 'connected':
          done(null, self.collection);
          break;
        case 'connecting':
          self.once('connected', function () {
            done(null, self.collection);
          });
          break;
        case 'disconnected':
          done(new Error('Not connected'));
          break;
      }
    };

    this.getSessionId = function (sid) {
      if (options.hash) {
        return crypto.createHash(options.hash.algorithm).update(options.hash.salt + sid).digest('hex');
      } else {
        return sid;
      }
    };

    changeState('init');

    if (options.url) {
      debug('use strategy: `url`');
      initWithUrl();
    } else if (options.mongooseConnection) {
      debug('use strategy: `mongoose_connection`');
      initWithMongooseConnection();
    } else if (options.db && options.db.listCollections) {
      debug('use strategy: `native_db`');
      process.nextTick(initWithNativeDb);
    } else {
      debug('use strategy: `legacy`');
      buildUrlFromOptions();
      initWithUrl();
    }

    changeState('connecting');

  }

  /**
   * Inherit from `Store`.
   */
   util.inherits(MongoStore, Store);

  /**
   * Attempt to fetch session by the given `sid`.
   *
   * @param {String} sid
   * @param {Function} callback
   * @api public
   */

  MongoStore.prototype.get = function(sid, callback) {
    if (!callback) callback = _.noop;
    sid = this.getSessionId(sid);

    var self = this;

    var query = {
      _id: sid,
      $or: [
        { expires: { $exists: false } },
        { expires: { $gt: new Date() } }
      ]
    };

    this.getCollection(function(err, collection) {
      if (err) return callback(err);
      collection.findOne(query, function(err, session) {
        if (err) {
          debug('not able to execute `find` query for session: ' + sid);
          return callback(err);
        }

        if (session) {
          var s;
          try {
            s = self.options.unserialize(session.session);
            if(self.options.touchAfter > 0 && session.lastModified){
              s.lastModified = session.lastModified;
            }
          } catch (err) {
            debug('unable to deserialize session');
            return callback(err);
          }
          self.emit('touch');
          callback(null, s);
        } else {
          callback();
        }
      });
    });
  };

  /**
   * Commit the given `sess` object associated with the given `sid`.
   *
   * @param {String} sid
   * @param {Session} sess
   * @param {Function} callback
   * @api public
   */

  MongoStore.prototype.set = function(sid, session, callback) {
    if (!callback) callback = _.noop;
    sid = this.getSessionId(sid);

    // removing the lastModified prop from the session object before update
    if(this.options.touchAfter > 0 && session && session.lastModified){
      delete session.lastModified;
    }

    var self = this;
    var s;

    try {
      s = {_id: sid, session: this.options.serialize(session)};
    } catch (err) {
      debug('unable to serialize session');
      return callback(err);
    }

    if (session && session.cookie && session.cookie.expires) {
      s.expires = new Date(session.cookie.expires);
    } else {
      // If there's no expiration date specified, it is
      // browser-session cookie or there is no cookie at all,
      // as per the connect docs.
      //
      // So we set the expiration to two-weeks from now
      // - as is common practice in the industry (e.g Django) -
      // or the default specified in the options.
      s.expires = new Date(Date.now() + this.options.ttl * 1000);
    }

    if(this.options.touchAfter > 0){
      s.lastModified = new Date();
    }

    this.getCollection(function(err, collection) {
      if (err) return callback(err);
      collection.update({_id: sid}, s, {upsert: true, safe: true}, function(err) {
        if (err) {debug('not able to set/update session: ' + sid);}
        else {
          self.emit('set');
        }
        callback(err);
      });
    });
  };

  /**
   * Touch the given `sess` object associated with the given `sid`.
   *
   * @param {String} sid
   * @param {Session} session
   * @param {Function} callback
   * @api public
   */
  MongoStore.prototype.touch = function (sid, session, callback) {

    var updateFields = {},
      touchAfter = this.options.touchAfter * 1000,
      lastModified = session.lastModified ? session.lastModified.getTime() : 0,
      currentDate = new Date();

    sid = this.getSessionId(sid);

    callback = callback ? callback : _.noop;

    // if the given options has a touchAfter property, check if the
    // current timestamp - lastModified timestamp is bigger than
    // the specified, if it's not, don't touch the session
    if(touchAfter > 0 && lastModified > 0){

      var timeElapsed = currentDate.getTime() - session.lastModified;

      if(timeElapsed < touchAfter){
        return callback();
      } else {
        updateFields.lastModified = currentDate;
      }

    }

    if (session && session.cookie && session.cookie.expires) {
      updateFields.expires = new Date(session.cookie.expires);
    } else {
      updateFields.expires = new Date(Date.now() + this.options.ttl * 1000);
    }

    this.getCollection(function(err, collection) {
      if (err) return callback(err);
      collection.update({ _id: sid }, { $set: updateFields }, { safe: true }, function (err, result) {
        if (err) {
          debug('not able to touch session: %s (error)', sid);
          callback(err);
        } else if (result.nModified === 0) {
          debug('not able to touch session: %s (not found)', sid);
          callback(new Error('Unable to find the session to touch'));
        } else {
          callback();
        }
      });
    });
  };

  /**
   * Destroy the session associated with the given `sid`.
   *
   * @param {String} sid
   * @param {Function} callback
   * @api public
   */

  MongoStore.prototype.destroy = function(sid, callback) {
    if (!callback) callback = _.noop;
    sid = this.getSessionId(sid);
    var self = this;

    this.getCollection(function(err, collection) {
      if (err) return callback(err);
      collection.remove({_id: sid}, function(err) {
        if (err) {
          debug('not able to destroy session: ' + sid);
        }else {
          self.emit('destroy');
        }
        callback(err);
      });
    });
  };

  /**
   * Fetch number of sessions.
   *
   * @param {Function} callback
   * @api public
   */

  MongoStore.prototype.length = function(callback) {
    if (!callback) callback = _.noop;
    this.getCollection(function(err, collection) {
      if (err) return callback(err);
      collection.count({}, function(err, count) {
        if (err) debug('not able to count sessions');
        callback(err, count);
      });
    });
  };

  /**
   * Clear all sessions.
   *
   * @param {Function} callback
   * @api public
   */

  MongoStore.prototype.clear = function(callback) {
    if (!callback) callback = _.noop;
    this.getCollection(function(err, collection) {
      if (err) return callback(err);
      collection.drop(function(err) {
        if (err) debug('not able to clear sessions');
        callback(err);
      });
    });
  };

  return MongoStore;
};
<commit_msg>Exposing timer as self.timer. Added timer.unref()<commit_after>'use strict';
/* jshint camelcase: false */

/**
 * Module dependencies
 */
var _ = require('lodash');
var crypto = require('crypto');
var mongo = require('mongodb');
var util = require('util');
var debug = require('debug')('connect-mongo');
var deprecate = require('depd')('connect-mongo');

var MongoClient = mongo.MongoClient;

/**
 * Default options
 */
var defaultOptions = {
  // Legacy strategy default options
  host: '127.0.0.1',
  port: 27017,
  autoReconnect: true,
  ssl: false,
  w: 1,

  // Global options
  collection: 'sessions',
  stringify: true,
  hash: false,
  ttl:  60 * 60 * 24 * 14, // 14 days
  autoRemove: 'native',
  autoRemoveInterval: 10
};

var defaultHashOptions = {
  salt: 'connect-mongo',
  algorithm: 'sha1'
};

var defaultSerializationOptions = {
  serialize: function (session) {
    // Copy each property of the session to a new object
    var obj = {};
    for (var prop in session) {
      if (prop === 'cookie') {

      // Convert the cookie instance to an object, if possible
      // This gets rid of the duplicate object under session.cookie.data property

        obj.cookie = session.cookie.toJSON ? session.cookie.toJSON() : session.cookie;
      } else {
        obj[prop] = session[prop];
      }
    }

    return obj;
  },
  unserialize: _.identity
};

var stringifySerializationOptions = {
  serialize: JSON.stringify,
  unserialize: JSON.parse
};

module.exports = function(connect) {
  var Store = connect.Store || connect.session.Store;
  var MemoryStore = connect.MemoryStore || connect.session.MemoryStore;

  /**
   * Initialize MongoStore with the given `options`.
   *
   * @param {Object} options
   * @api public
   */

  function MongoStore(options) {

    /* Deprecated options */

    if ('auto_reconnect' in options) {
      deprecate('auto_reconnect option is deprecated. Use autoReconnect instead');
      options.autoReconnect = options.auto_reconnect;
    }

    if ('mongoose_connection' in options) {
      deprecate('mongoose_connection option is deprecated. Use mongooseConnection instead');
      options.mongooseConnection = options.mongoose_connection;
    }

    if ('defaultExpirationTime' in options) {
      deprecate('defaultExpirationTime option is deprecated. Use ttl instead');
      options.ttl = options.defaultExpirationTime / 1000;
    }

    /* Fallback */

    if (options.fallbackMemory && MemoryStore) {
      return new MemoryStore();
    }

    /* Options */

    options = _.defaults(options || {}, defaultOptions);

    if (options.hash) {
      options.hash = _.defaults(options.hash, defaultHashOptions);
    }

    if (!options.stringify || options.serialize || options.unserialize) {
      options = _.defaults(options, defaultSerializationOptions);
    } else {
      options = _.assign(options, stringifySerializationOptions);
    }

    this.options =  options;

    Store.call(this, options);

    var self = this;

    function changeState(newState) {
      debug('switched to state: %s', newState);
      self.state = newState;
      self.emit(newState);
    }

    function connectionReady(err) {
      if (err) {
          debug('not able to connect to the database');
          changeState('disconnected');
          throw err;
      }

      self.collection = self.db.collection(options.collection);

      switch (options.autoRemove) {

        case 'native':
          self.collection.ensureIndex({ expires: 1 }, { expireAfterSeconds: 0 }, function (err) {
            if (err) throw err;
            changeState('connected');
          });
          break;

        case 'interval':
          self.timer = setInterval(function () {
            self.collection.remove({ expires: { $lt: new Date() } }, { w: 0 });
          }, options.autoRemoveInterval * 1000 * 60);
          // node <0.8 compatibility
          if (typeof self.timer.unref === 'function') {
            self.timer.unref();
          }
          changeState('connected');
          break;

        default:
          changeState('connected');
          break;

      }
    }

    function buildUrlFromOptions() {
      if(!options.db || typeof options.db !== 'string') {
        throw new Error('Required MongoStore option `db` missing or is not a string.');
      }

      options.url = 'mongodb://';

      if (options.username) {
        options.url += options.username + ':' + (options.password || '') + '@';
      }

      options.url += options.host + ':' + options.port + '/' + options.db;

      if (options.ssl) options.url += '?ssl=true';

      if (!options.mongoOptions) {
        options.mongoOptions = {
          server: { auto_reconnect: options.autoReconnect },
          db: { w: options.w }
        };
      }
    }

    function initWithUrl() {
      MongoClient.connect(options.url, options.mongoOptions || {}, function(err, db) {
        if (!err) self.db = db;
        connectionReady(err);
      });
    }

    function initWithMongooseConnection() {
      if (options.mongooseConnection.readyState === 1) {
        self.db = options.mongooseConnection.db;
        process.nextTick(connectionReady);
      } else {
        options.mongooseConnection.once('open', function() {
          self.db = options.mongooseConnection.db;
          connectionReady();
        });
      }
    }

    function initWithNativeDb() {
      self.db = options.db;

      if (options.db.openCalled || options.db.openCalled === undefined) { // openCalled is undefined in mongodb@2.x
        options.db.collection(options.collection, connectionReady);
      } else {
        options.db.open(connectionReady);
      }
    }

    this.getCollection = function (done) {
      switch (self.state) {
        case 'connected':
          done(null, self.collection);
          break;
        case 'connecting':
          self.once('connected', function () {
            done(null, self.collection);
          });
          break;
        case 'disconnected':
          done(new Error('Not connected'));
          break;
      }
    };

    this.getSessionId = function (sid) {
      if (options.hash) {
        return crypto.createHash(options.hash.algorithm).update(options.hash.salt + sid).digest('hex');
      } else {
        return sid;
      }
    };

    changeState('init');

    if (options.url) {
      debug('use strategy: `url`');
      initWithUrl();
    } else if (options.mongooseConnection) {
      debug('use strategy: `mongoose_connection`');
      initWithMongooseConnection();
    } else if (options.db && options.db.listCollections) {
      debug('use strategy: `native_db`');
      process.nextTick(initWithNativeDb);
    } else {
      debug('use strategy: `legacy`');
      buildUrlFromOptions();
      initWithUrl();
    }

    changeState('connecting');

  }

  /**
   * Inherit from `Store`.
   */
   util.inherits(MongoStore, Store);

  /**
   * Attempt to fetch session by the given `sid`.
   *
   * @param {String} sid
   * @param {Function} callback
   * @api public
   */

  MongoStore.prototype.get = function(sid, callback) {
    if (!callback) callback = _.noop;
    sid = this.getSessionId(sid);

    var self = this;

    var query = {
      _id: sid,
      $or: [
        { expires: { $exists: false } },
        { expires: { $gt: new Date() } }
      ]
    };

    this.getCollection(function(err, collection) {
      if (err) return callback(err);
      collection.findOne(query, function(err, session) {
        if (err) {
          debug('not able to execute `find` query for session: ' + sid);
          return callback(err);
        }

        if (session) {
          var s;
          try {
            s = self.options.unserialize(session.session);
            if(self.options.touchAfter > 0 && session.lastModified){
              s.lastModified = session.lastModified;
            }
          } catch (err) {
            debug('unable to deserialize session');
            return callback(err);
          }
          self.emit('touch');
          callback(null, s);
        } else {
          callback();
        }
      });
    });
  };

  /**
   * Commit the given `sess` object associated with the given `sid`.
   *
   * @param {String} sid
   * @param {Session} sess
   * @param {Function} callback
   * @api public
   */

  MongoStore.prototype.set = function(sid, session, callback) {
    if (!callback) callback = _.noop;
    sid = this.getSessionId(sid);

    // removing the lastModified prop from the session object before update
    if(this.options.touchAfter > 0 && session && session.lastModified){
      delete session.lastModified;
    }

    var self = this;
    var s;

    try {
      s = {_id: sid, session: this.options.serialize(session)};
    } catch (err) {
      debug('unable to serialize session');
      return callback(err);
    }

    if (session && session.cookie && session.cookie.expires) {
      s.expires = new Date(session.cookie.expires);
    } else {
      // If there's no expiration date specified, it is
      // browser-session cookie or there is no cookie at all,
      // as per the connect docs.
      //
      // So we set the expiration to two-weeks from now
      // - as is common practice in the industry (e.g Django) -
      // or the default specified in the options.
      s.expires = new Date(Date.now() + this.options.ttl * 1000);
    }

    if(this.options.touchAfter > 0){
      s.lastModified = new Date();
    }

    this.getCollection(function(err, collection) {
      if (err) return callback(err);
      collection.update({_id: sid}, s, {upsert: true, safe: true}, function(err) {
        if (err) {debug('not able to set/update session: ' + sid);}
        else {
          self.emit('set');
        }
        callback(err);
      });
    });
  };

  /**
   * Touch the given `sess` object associated with the given `sid`.
   *
   * @param {String} sid
   * @param {Session} session
   * @param {Function} callback
   * @api public
   */
  MongoStore.prototype.touch = function (sid, session, callback) {

    var updateFields = {},
      touchAfter = this.options.touchAfter * 1000,
      lastModified = session.lastModified ? session.lastModified.getTime() : 0,
      currentDate = new Date();

    sid = this.getSessionId(sid);

    callback = callback ? callback : _.noop;

    // if the given options has a touchAfter property, check if the
    // current timestamp - lastModified timestamp is bigger than
    // the specified, if it's not, don't touch the session
    if(touchAfter > 0 && lastModified > 0){

      var timeElapsed = currentDate.getTime() - session.lastModified;

      if(timeElapsed < touchAfter){
        return callback();
      } else {
        updateFields.lastModified = currentDate;
      }

    }

    if (session && session.cookie && session.cookie.expires) {
      updateFields.expires = new Date(session.cookie.expires);
    } else {
      updateFields.expires = new Date(Date.now() + this.options.ttl * 1000);
    }

    this.getCollection(function(err, collection) {
      if (err) return callback(err);
      collection.update({ _id: sid }, { $set: updateFields }, { safe: true }, function (err, result) {
        if (err) {
          debug('not able to touch session: %s (error)', sid);
          callback(err);
        } else if (result.nModified === 0) {
          debug('not able to touch session: %s (not found)', sid);
          callback(new Error('Unable to find the session to touch'));
        } else {
          callback();
        }
      });
    });
  };

  /**
   * Destroy the session associated with the given `sid`.
   *
   * @param {String} sid
   * @param {Function} callback
   * @api public
   */

  MongoStore.prototype.destroy = function(sid, callback) {
    if (!callback) callback = _.noop;
    sid = this.getSessionId(sid);
    var self = this;

    this.getCollection(function(err, collection) {
      if (err) return callback(err);
      collection.remove({_id: sid}, function(err) {
        if (err) {
          debug('not able to destroy session: ' + sid);
        }else {
          self.emit('destroy');
        }
        callback(err);
      });
    });
  };

  /**
   * Fetch number of sessions.
   *
   * @param {Function} callback
   * @api public
   */

  MongoStore.prototype.length = function(callback) {
    if (!callback) callback = _.noop;
    this.getCollection(function(err, collection) {
      if (err) return callback(err);
      collection.count({}, function(err, count) {
        if (err) debug('not able to count sessions');
        callback(err, count);
      });
    });
  };

  /**
   * Clear all sessions.
   *
   * @param {Function} callback
   * @api public
   */

  MongoStore.prototype.clear = function(callback) {
    if (!callback) callback = _.noop;
    this.getCollection(function(err, collection) {
      if (err) return callback(err);
      collection.drop(function(err) {
        if (err) debug('not able to clear sessions');
        callback(err);
      });
    });
  };

  return MongoStore;
};
<|endoftext|>


<commit_before>var Console = require('./console').Console;

function Context(worker, id){
  this.console = new Console(worker, id);
}

Context.prototype.module        = {}
Context.prototype.require       = require
// Context.prototype.eval          = eval
Context.prototype.setTimeout    = setTimeout
Context.prototype.setInterval   = setInterval
Context.prototype.clearTimeout  = clearTimeout
Context.prototype.clearInterval = clearInterval
Context.prototype.process       = {
   hrtime     : process.hrtime
}
Context.prototype.Buffer        = Buffer
Context.prototype.Error         = Error
Context.prototype.EvalError     = EvalError
// Context.prototype.InternalError = InternalError
Context.prototype.RangeError    = RangeError
Context.prototype.ReferenceError= ReferenceError
Context.prototype.SyntaxError   = SyntaxError
Context.prototype.TypeError     = TypeError
Context.prototype.URIError      = URIError
Context.prototype.Object        = Object
Context.prototype.JSON          = JSON

module.exports = {
    Context : Context
};

  // , fs                = require('fs')

  // , mock_fs   = require('mock-fs')

//
// mock_fs();
// var local_restore = fs.restore;

// fs.restore = function() { throw new Error('Unable to restore'); };<commit_msg>prototype on context break isolation between runs.<commit_after>var Console = require('./console').Console;

function Context(worker, id){
  // these need to be defined inside the create function to sandbox them
  this.console = new Console(worker, id);

  this.module        = {}
  this.require       = require
  // this.eval          = eval
  this.setTimeout    = setTimeout
  this.setInterval   = setInterval
  this.clearTimeout  = clearTimeout
  this.clearInterval = clearInterval
  this.process       = {
     hrtime     : process.hrtime
  }
  this.Buffer        = Buffer
  this.Error         = Error
  this.EvalError     = EvalError
  // this.InternalError = InternalError
  this.RangeError    = RangeError
  this.ReferenceError= ReferenceError
  this.SyntaxError   = SyntaxError
  this.TypeError     = TypeError
  this.URIError      = URIError
  this.Object        = Object
  this.JSON          = JSON
}

module.exports = {
    Context : Context
};

  // , fs                = require('fs')

  // , mock_fs   = require('mock-fs')

//
// mock_fs();
// var local_restore = fs.restore;

// fs.restore = function() { throw new Error('Unable to restore'); };<|endoftext|>


<commit_before>
var sql = require('../utils/sql'),
    query = require('../utils/query');

exports.update = function (args, cb) {
    switch (args.action) {
        case 'insert':
        case 'update':
            var types = ['view', 'oneToOne', 'manyToOne'];
            break;
        case 'remove':
            var types = ['oneToOne', 'manyToOne', 'view'];
            break;
    }
    args.queries = [];

    (function loopTypes (k) {
        if (k == types.length) return cb();

        args.type = types[k];
        args.tables = args.data[types[k]];
        if (!args.tables) return loopTypes(++k);
        var keys = Object.keys(args.tables);

        (function loopTables (i) {
            if (i == keys.length) return loopTypes(++k);

            var records = args.tables[keys[i]].records;
            if (!records) return loopTables(++i);

            (function loopRecords (j) {
                if (j == records.length) return loopTables(++i);

                var record = records[j],
                    settings = args.settings[keys[i]];
                updateRecord(args, settings, record, function (err) {
                    if (err) return cb(err);
                    loopRecords(++j);
                });
            }(0));
        }(0));
    }(0));
}

// settings - current table settings, record - current record data
function updateRecord (args, settings, record, cb) {
    if (args.type !== 'view') {
        var fk = args.settings[args.name].editview[args.type][settings.table.name];
        record.columns[fk] = args.id;
    }

    if (record.insert) {
        var data = kvp(args.name, record.columns, settings.columns),
            str = query.replace('insert',
                settings.table.name, data.keys.join(), data.values.join(), settings.table.pk);

        var action = 'insert';

    } else if (record.remove || args.action == 'remove') {
        var pk = settings.table.pk;
            str = query.replace('delete', settings.table.name, pk, record.pk);

        var action = 'remove';

    } else { // update
        var pk = settings.table.pk,
            data = kvp(args.name, record.columns, settings.columns),
            str = query.replace('update',
                settings.table.name, data.pairs.join(), pk, record.pk);

        var action = 'update';
    }

    execute(action, args, str, record, settings, cb);
}

function execute (action, args, str, record, settings, cb) {
    if (args.debug) {
        // insert or update
        if (action != 'remove') {
            args.queries.push(str);
            if (action == 'insert') {
                record.pk = '[PK]';
                if (args.type == 'view' && args.action == 'insert')
                    args.id = '[FK]';
            }
            var queries = manyToMany(action, args, record, settings.columns);
            args.queries = args.queries.concat(queries);
        }
        // remove
        else {
            var queries = manyToMany(action, args, record, settings.columns);
            args.queries = args.queries.concat(queries);
            args.queries.push(str);
        }
        return cb();
    }

    // insert or update
    if (action != 'remove') {
        args.db.client.query(str, function (err, result) {
            if (err) return cb(err);

            if (action == 'insert') {
                record.pk = result.insertId;
                if (args.type == 'view' && args.action == 'insert')
                    args.id = result.insertId;
            }

            var queries = manyToMany(action, args, record, settings.columns);
            spin(args, queries, function (err) {
                if (err) return cb(err);
                cb();
            });
        });
    }
    // remove
    else {
        var queries = manyToMany(action, args, record, settings.columns);
        spin(args, queries, function (err) {
            if (err) return cb(err);
            args.db.client.query(str, function (err, result) {
                if (err) return cb(err);
                cb();
            });
        });
    }
}

function spin (args, queries, cb) {
    (function loop (i) {
        if (i == queries.length) return cb();
        args.db.client.query(queries[i], function (err) {
            if (err) return cb(err);
            loop(++i);
        });
    }(0));
}

// sql string helpers

function kvp (table, data, columns) {
    var keys = [], values = [], pairs = [];

    for (var i=0; i < columns.length; i++) {
        if (columns[i].manyToMany) continue;

        var name = columns[i].name;
        if (!{}.hasOwnProperty.call(data, name)) continue;

        var just = sql.justName(name);

        keys.push(just);
        var value = escape(data[name], columns[i].type);

        values.push(value);
        pairs.push(just+'='+value);
    }
    return {keys: keys, values: values, pairs: pairs};
}

function escape (value, type) {
    if (/(?:var)?char|(?:tiny|medium|long)?text/i.test(type)) {
        return "\'"+value.replace(/('|")/g, '\\$1')+"\'";
    }
    else if (/date|time|timestamp|datetime|year/i.test(type)) {
        return (value === '' || value === null) ? 'NULL' : "\'"+value+"\'";
    }
    else if (/(?:tiny|medium|long)?blob|(?:var)?binary\(\d+\)/i.test(type)) {
        return "X\'"+value+"\'";
    }
    else if (/bytea/.test(type)) {
        return "\'\\x"+value+"\'";
    }
    else {
        return value;
    }
}

// many-to-many helpers

function manyToMany (action, args, record, columns) {
    var queries = [];

    for (var i=0; i < columns.length; i++) {
        if (!columns[i].manyToMany) continue;

        var link = columns[i].manyToMany.link,
            dbIds = record.ids[columns[i].name] || [],
            postIds = record.columns[columns[i].name] || [];
        postIds = (postIds instanceof Array) ? postIds : [postIds];

        var ins, del;
        switch (action) {
            case 'insert':
                ins = manyInsert(postIds, link, record);
                break;
            case 'remove':
                del = manyDelete(dbIds, link, record);
                break;
            case 'update':
                var delIds = difference(dbIds, postIds),
                    insIds = difference(postIds, dbIds);
                del = manyDelete(delIds, link, record);
                ins = manyInsert(insIds, link, record);
                break;
        }
        ins ? queries.push(ins) : null;
        del ? queries.push(del) : null;
    }
    return queries;
}

function manyInsert (ids, link, record) {
    if (!ids.length) return null;

    var values = [];
    for (var i=0; i < ids.length; i++) {
        values.push('('+record.pk+','+ids[i]+')');
    }

    var str = query.replace('insert-many',
        link.table, [link.parentPk, link.childPk].join(), values.join());

    return str;
}

function manyDelete (ids, link, record) {
    if (!ids.length) return null;

    var str = query.replace('delete-many',
        link.table, link.parentPk, record.pk, link.childPk, ids.join());

    return str;
}

function difference (source, target) {
    for (var i=0; i < source.length; i++) {
        source[i] = parseInt(source[i],10);
    }
    for (var i=0; i < target.length; i++) {
        target[i] = parseInt(target[i],10);
    }
    return source.filter(function (i) {
        return !(target.indexOf(i) > -1);
    });
}
<commit_msg>Quote field names in many-to-many insert queries<commit_after>
var sql = require('../utils/sql'),
    query = require('../utils/query');

exports.update = function (args, cb) {
    switch (args.action) {
        case 'insert':
        case 'update':
            var types = ['view', 'oneToOne', 'manyToOne'];
            break;
        case 'remove':
            var types = ['oneToOne', 'manyToOne', 'view'];
            break;
    }
    args.queries = [];

    (function loopTypes (k) {
        if (k == types.length) return cb();

        args.type = types[k];
        args.tables = args.data[types[k]];
        if (!args.tables) return loopTypes(++k);
        var keys = Object.keys(args.tables);

        (function loopTables (i) {
            if (i == keys.length) return loopTypes(++k);

            var records = args.tables[keys[i]].records;
            if (!records) return loopTables(++i);

            (function loopRecords (j) {
                if (j == records.length) return loopTables(++i);

                var record = records[j],
                    settings = args.settings[keys[i]];
                updateRecord(args, settings, record, function (err) {
                    if (err) return cb(err);
                    loopRecords(++j);
                });
            }(0));
        }(0));
    }(0));
}

// settings - current table settings, record - current record data
function updateRecord (args, settings, record, cb) {
    if (args.type !== 'view') {
        var fk = args.settings[args.name].editview[args.type][settings.table.name];
        record.columns[fk] = args.id;
    }

    if (record.insert) {
        var data = kvp(args.name, record.columns, settings.columns),
            str = query.replace('insert',
                settings.table.name, data.keys.join(), data.values.join(), settings.table.pk);

        var action = 'insert';

    } else if (record.remove || args.action == 'remove') {
        var pk = settings.table.pk;
            str = query.replace('delete', settings.table.name, pk, record.pk);

        var action = 'remove';

    } else { // update
        var pk = settings.table.pk,
            data = kvp(args.name, record.columns, settings.columns),
            str = query.replace('update',
                settings.table.name, data.pairs.join(), pk, record.pk);

        var action = 'update';
    }

    execute(action, args, str, record, settings, cb);
}

function execute (action, args, str, record, settings, cb) {
    if (args.debug) {
        // insert or update
        if (action != 'remove') {
            args.queries.push(str);
            if (action == 'insert') {
                record.pk = '[PK]';
                if (args.type == 'view' && args.action == 'insert')
                    args.id = '[FK]';
            }
            var queries = manyToMany(action, args, record, settings.columns);
            args.queries = args.queries.concat(queries);
        }
        // remove
        else {
            var queries = manyToMany(action, args, record, settings.columns);
            args.queries = args.queries.concat(queries);
            args.queries.push(str);
        }
        return cb();
    }

    // insert or update
    if (action != 'remove') {
        args.db.client.query(str, function (err, result) {
            if (err) return cb(err);

            if (action == 'insert') {
                record.pk = result.insertId;
                if (args.type == 'view' && args.action == 'insert')
                    args.id = result.insertId;
            }

            var queries = manyToMany(action, args, record, settings.columns);
            spin(args, queries, function (err) {
                if (err) return cb(err);
                cb();
            });
        });
    }
    // remove
    else {
        var queries = manyToMany(action, args, record, settings.columns);
        spin(args, queries, function (err) {
            if (err) return cb(err);
            args.db.client.query(str, function (err, result) {
                if (err) return cb(err);
                cb();
            });
        });
    }
}

function spin (args, queries, cb) {
    (function loop (i) {
        if (i == queries.length) return cb();
        args.db.client.query(queries[i], function (err) {
            if (err) return cb(err);
            loop(++i);
        });
    }(0));
}

// sql string helpers

function kvp (table, data, columns) {
    var keys = [], values = [], pairs = [];

    for (var i=0; i < columns.length; i++) {
        if (columns[i].manyToMany) continue;

        var name = columns[i].name;
        if (!{}.hasOwnProperty.call(data, name)) continue;

        var just = sql.justName(name);

        keys.push(just);
        var value = escape(data[name], columns[i].type);

        values.push(value);
        pairs.push(just+'='+value);
    }
    return {keys: keys, values: values, pairs: pairs};
}

function escape (value, type) {
    if (/(?:var)?char|(?:tiny|medium|long)?text/i.test(type)) {
        return "\'"+value.replace(/('|")/g, '\\$1')+"\'";
    }
    else if (/date|time|timestamp|datetime|year/i.test(type)) {
        return (value === '' || value === null) ? 'NULL' : "\'"+value+"\'";
    }
    else if (/(?:tiny|medium|long)?blob|(?:var)?binary\(\d+\)/i.test(type)) {
        return "X\'"+value+"\'";
    }
    else if (/bytea/.test(type)) {
        return "\'\\x"+value+"\'";
    }
    else {
        return value;
    }
}

// many-to-many helpers

function manyToMany (action, args, record, columns) {
    var queries = [];

    for (var i=0; i < columns.length; i++) {
        if (!columns[i].manyToMany) continue;

        var link = columns[i].manyToMany.link,
            dbIds = record.ids[columns[i].name] || [],
            postIds = record.columns[columns[i].name] || [];
        postIds = (postIds instanceof Array) ? postIds : [postIds];

        var ins, del;
        switch (action) {
            case 'insert':
                ins = manyInsert(postIds, link, record);
                break;
            case 'remove':
                del = manyDelete(dbIds, link, record);
                break;
            case 'update':
                var delIds = difference(dbIds, postIds),
                    insIds = difference(postIds, dbIds);
                del = manyDelete(delIds, link, record);
                ins = manyInsert(insIds, link, record);
                break;
        }
        ins ? queries.push(ins) : null;
        del ? queries.push(del) : null;
    }
    return queries;
}

function manyInsert (ids, link, record) {
    if (!ids.length) return null;

    var values = [];
    for (var i=0; i < ids.length; i++) {
        values.push('('+record.pk+','+ids[i]+')');
    }

    var str = query.replace('insert-many',
        link.table, [sql.justName(link.parentPk), sql.justName(link.childPk)].join(),
        values.join());

    return str;
}

function manyDelete (ids, link, record) {
    if (!ids.length) return null;

    var str = query.replace('delete-many',
        link.table, link.parentPk, record.pk, link.childPk, ids.join());

    return str;
}

function difference (source, target) {
    for (var i=0; i < source.length; i++) {
        source[i] = parseInt(source[i],10);
    }
    for (var i=0; i < target.length; i++) {
        target[i] = parseInt(target[i],10);
    }
    return source.filter(function (i) {
        return !(target.indexOf(i) > -1);
    });
}
<|endoftext|>