<commit_before>var postcss = require('postcss');
var webpackSources = require('webpack-sources');

function PostCSSAssetsPlugin(options) {
    this.options = options || {};

    if (options.test === undefined) {
        this.options.test = /\.css$/;
    }

    if (options.plugins === undefined) {
        this.options.plugins = [];
    }

    if (options.log === undefined) {
        this.options.log = true;
    }
}

PostCSSAssetsPlugin.prototype.apply = function(compiler) {
    var self = this;
    var options = this.options;

    compiler.plugin('emit', function(compilation, compileCallback) {
        var assets = compilation.assets;

        self.log('Start PostCSSAssetsPlugin');

        return Promise.all(Object.keys(assets).reduce(function (result, name) {
            if (!options.test.test(name)) {
                return result;
            }

            var asset = assets[name];
            var originalCss = asset.source();

            self.log('Processing ' + name + '...');

            result.push(
                postcss(options.plugins)
                    .process(originalCss)
                    .then(function handlePostCSSResult(result) {
                        var processedCss = result.css;
                        var warnings = result.warnings();

                        if (warnings && warnings.length) {
                            self.log(warnings.join('\n'));
                        }

                        assets[name] = new webpackSources.RawSource(processedCss);

                        self.log('Processed ' + name + '. Length before: ' + originalCss.length + ', length after: ' + processedCss.length);
                    })
                    .catch(function (error) {
                        self.log('Error processing file: ' + name, error);
                    })
            );

            return result;
        }, [])).then(function () {
            self.log('Finish PostCSSAssetsPlugin');
            compileCallback();
        }).catch(compileCallback);
    });
};

PostCSSAssetsPlugin.prototype.log = function () {
    if (this.options.log) {
        console.log.apply(console, arguments);
    }
};

module.exports = PostCSSAssetsPlugin;<commit_msg>Fix external sourcemaps<commit_after>var postcss = require('postcss');
var webpackSources = require('webpack-sources');

function PostCSSAssetsPlugin(options) {
    this.options = options || {};

    if (options.test === undefined) {
        this.options.test = /\.css$/;
    }

    if (options.plugins === undefined) {
        this.options.plugins = [];
    }

    if (options.log === undefined) {
        this.options.log = true;
    }
}

PostCSSAssetsPlugin.prototype.apply = function(compiler) {
    var self = this;
    var options = this.options;

    compiler.plugin('emit', function(compilation, compileCallback) {
        var assets = compilation.assets;

        self.log('Start PostCSSAssetsPlugin');

        return Promise.all(Object.keys(assets).reduce(function (result, name) {
            if (!options.test.test(name)) {
                return result;
            }

            var asset = assets[name];
            var originalCss = asset.source();

            var mapName = originalCss.match(/\/\*# sourceMappingURL=(.{1,200}).*\*\/$|$/)[1];

            var inlineMap = mapName ? mapName.search(/^data:/) === 0 : false;
            if (inlineMap) { self.log('Found inline source map'); }

            var mapAsset = mapName && !inlineMap ? assets[mapName] : null;
            var externalMap = mapAsset ? mapAsset.source() : undefined;
            if (externalMap) { self.log('Found external source map'); }

            var processOptions = {
                from: name,
                to: name,
                map: (inlineMap || externalMap) ? {
                    inline: inlineMap,
                    sourcesContent: true,
                    prev: externalMap
                } : false
            };

            self.log('Processing ' + name + '...');

            result.push(
                postcss(options.plugins)
                    .process(originalCss, processOptions)
                    .then(function handlePostCSSResult(result) {
                        var processedCss = result.css;
                        var warnings = result.warnings();

                        if (warnings && warnings.length) {
                            self.log(warnings.join('\n'));
                        }

                        assets[name] = new webpackSources.RawSource(processedCss);
                        if (mapAsset) {
                            assets[mapName] = new webpackSources.RawSource(JSON.stringify(result.map));
                        }

                        self.log('Processed ' + name + '. Length before: ' + originalCss.length + ', length after: ' + processedCss.length);
                    })
                    .catch(function (error) {
                        self.log('Error processing file: ' + name, error);
                    })
            );

            return result;
        }, [])).then(function () {
            self.log('Finish PostCSSAssetsPlugin');
            compileCallback();
        }).catch(compileCallback);
    });
};

PostCSSAssetsPlugin.prototype.log = function () {
    if (this.options.log) {
        console.log.apply(console, arguments);
    }
};

module.exports = PostCSSAssetsPlugin;<|endoftext|>


<commit_before>var Q = require('q');
var fs = require('fs');
var path = require('path');
var crc = require('crc');
var exec = require('child_process').exec;
var mjAPI = require('MathJax-node/lib/mj-single.js');

var started = false;
var countMath = 0;
var parsed = {};

function convertTexToSvg(tex, outputPath, options) {
    var d = Q.defer();
    options = options || {};

    if (!started) {
        mjAPI.config({MathJax: {SVG: {font: 'TeX'}}});
        mjAPI.start();
        started = true;
    }

    mjAPI.typeset({
        math: tex,
        format: (options.inline ? 'inline-TeX' : 'TeX'),
        svg: true,
        speakText: options.speakText || "default",
        speakRuleset: (options.speechrules || "mathspeak").replace(/^chromevox$/i, 'default'),
        speakStyle: options.speechstyle || "default",
        ex: options.ex || 6,
        width: options.width || 100,
        linebreaks: !!options.linebreaks
    }, function (data) {
        if (data.errors) {
            console.log(data.errors)
            return d.reject(new Error(data.errors));
        }

        fs.writeFileSync(outputPath, data.svg);
        d.resolve();
    });

    return d.promise;
}

module.exports = {
    blocks: {
        math: {
            shortcuts: {
                parsers: ["markdown"],
                start: "$$",
                end: "$$"
            },
            process: function(blk) {
                var that = this;
                var tex = blk.body;
                var fileOutput = "_mathjax/"+countMath+".svg";

                var hashTex = crc.crc32(tex).toString(16);

                that.book.log.info("process TeX using MathJAX", countMath, "...");
                return Q()
                .then(function() {
                    if (parsed[hashTex]) {
                        fileOutput = "_mathjax/"+parsed[hashTex]+".svg";
                        return;
                    }

                    parsed[hashTex] = countMath;
                    countMath = countMath + 1;
                    return convertTexToSvg(tex, path.resolve(that.book.options.output, fileOutput))
                })
                .then(function() {
                    that.book.log.info.ok();
                    return "";
                }, function(err) {
                    that.book.log.info.fail();
                    throw err;
                });
            }
        }
    },
    hooks: {
        init: function() {
            fs.mkdirSync(path.join(this.options.output, "_mathjax"));
        }
    }
};
<commit_msg>Use mathjax inside website for preview<commit_after>var Q = require('q');
var fs = require('fs');
var path = require('path');
var crc = require('crc');
var exec = require('child_process').exec;
var mjAPI = require('MathJax-node/lib/mj-single.js');

var started = false;
var countMath = 0;
var parsed = {};

function convertTexToSvg(tex, outputPath, options) {
    var d = Q.defer();
    options = options || {};

    if (!started) {
        mjAPI.config({MathJax: {SVG: {font: 'TeX'}}});
        mjAPI.start();
        started = true;
    }

    mjAPI.typeset({
        math: tex,
        format: (options.inline ? 'inline-TeX' : 'TeX'),
        svg: true,
        speakText: options.speakText || "default",
        speakRuleset: (options.speechrules || "mathspeak").replace(/^chromevox$/i, 'default'),
        speakStyle: options.speechstyle || "default",
        ex: options.ex || 6,
        width: options.width || 100,
        linebreaks: !!options.linebreaks
    }, function (data) {
        if (data.errors) {
            console.log(data.errors)
            return d.reject(new Error(data.errors));
        }

        fs.writeFileSync(outputPath, data.svg);
        d.resolve();
    });

    return d.promise;
}

module.exports = {
    book: {
        assets: "./book",
        js: [
            "https://cdn.mathjax.org/mathjax/2.4-latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML",
            "plugin.js"
        ]
    },
    blocks: {
        math: {
            shortcuts: {
                parsers: ["markdown"],
                start: "$$",
                end: "$$"
            },
            process: function(blk) {
                // For website return as script
                if (this.book.options.generator == "website") return '';

                // For ebook, return as an image
                var that = this;
                var tex = blk.body;
                var fileOutput = "_mathjax/"+countMath+".svg";

                var hashTex = crc.crc32(tex).toString(16);

                that.book.log.info("process TeX using MathJAX", countMath, "...");
                return Q()
                .then(function() {
                    if (parsed[hashTex]) {
                        fileOutput = "_mathjax/"+parsed[hashTex]+".svg";
                        return;
                    }

                    parsed[hashTex] = countMath;
                    countMath = countMath + 1;
                    return convertTexToSvg(tex, path.resolve(that.book.options.output, fileOutput))
                })
                .then(function() {
                    that.book.log.info.ok();
                    return "";
                }, function(err) {
                    that.book.log.info.fail();
                    throw err;
                });
            }
        }
    },
    hooks: {
        init: function() {
            fs.mkdirSync(path.join(this.options.output, "_mathjax"));
        }
    }
};
<|endoftext|>


<commit_before>var Launcher = require("ensime-launcher-js");
var WebSocket = require("ws");

function Controller(dotEnsime, ensimeInstallDir, options) {
  this.dotEnsime = dotEnsime;

  if (options && "sbt" in options) this.sbtCmd = options.sbt;
  else this.sbtCmd = "sbt";
  if (options && "ensimeVersion" in options) this.ensimeVersion = options.ensimeVersion;
  else this.ensimeVersion = "0.9.10-SNAPSHOT";

  this.connection = null;
  this.nextCallId = 0;
  this.callMap = {};

  this.launcher = new Launcher(this.dotEnsime, this.ensimeVersion, ensimeInstallDir, this.sbtCmd);
}

/** Connect to ensime, starting it first if necessary.
  * @param output {out: Stream, err: Stream}
  * @return {ports: {http: Int}, info: ensime-ConnectionInfo} */
Controller.prototype.connect = function(output, callback) {
  if (this.connection) return this.status(callback);

  this.launcher.cleanup(function() {
    this.launcher.start(output, function(err, ports) {
      if (err) return callback(err);
      console.log("ensime now running on port " + ports.http);
      this.connectWebsocket(ports, callback)
    }.bind(this));
  }.bind(this));
}

/** Try to attach to a currently running ensime.
 * @return {ports: {http: Int}, info: ensime-ConnectionInfo} */
Controller.prototype.attach = function(callback) {
  this.launcher.ports(function(err, ports) {
    if (err) return callback("not running");
    console.log("Detected ensime on port "+ports.http);
    this.connectWebsocket(ports, callback);
  }.bind(this));
}

Controller.prototype.connectWebsocket = function(ports, callback) {
  this.connection = new WebSocket("ws://localhost:" + ports.http + "/jerky");
  this.connection.on("open", function() {
    console.log("now connected to ensime...");
    this.status(function(err, data) {
      if (err) return callback(err);
      callback(false, {
        ports: ports,
        info: data
      });
    }.bind(this));
  }.bind(this));
  this.connection.on("message", this.handleIncoming.bind(this));
  this.connection.on("error", function (error) {
    this.handleGeneral({disconnected: error});
  }.bind(this));
};

/** Update ensime to the specified version. Can also be used to fix installations.
  * @param output {out: Stream, err: Stream}
  * @return nothing */
Controller.prototype.update = function(output, callback) {
  this.launcher.update(output, callback);
}

/** Send a command to ensime. */
Controller.prototype.send = function(cmd, callback) {
  if (!this.connection) return callback("connection not open.");

  var callId = this.nextCallId++;
  this.callMap[callId] = callback;
  var req = {
    req: cmd,
    callId: callId
  }
  //console.debug("Sending "+JSON.stringify(req));
  this.connection.send(JSON.stringify(req));
}

/** Handle an incoming message from ensime. */
Controller.prototype.handleIncoming = function(data) {
  var resp = JSON.parse(data);
  if ("callId" in resp) {
    if (resp.callId in this.callMap) {
      try {
        this.callMap[resp.callId](false, resp.payload);
      } catch (e) {
        console.error("Error in callback: "+e)
      } finally {
        delete this.callMap[resp.callId];
      }
    }
  } else this.handleGeneral(resp.payload);
}

Controller.prototype.cancelPending = function(reason) {
  for (key in this.callMap) {
    this.callMap[key](reason);
  }
  this.callMap = {};
}

Controller.prototype.handleGeneral = function(response) {
  //TODO
  console.log("Received general message: "+JSON.stringify(response));
}

Controller.prototype.status = function(callback) {
  this.send({
      typehint: "ConnectionInfoReq"
  }, callback);
}

Controller.prototype.stop = function(callback) {
  this.cancelPending("Stop requested.");

  //Disconnect
  if (this.connection) {
    try {
      this.connection.close();
    } catch (e) {
      //ignore
    }
  }

  this.launcher.stop(callback);
}

module.exports = Controller;<commit_msg>Cleanup and format.<commit_after>var Launcher = require("ensime-launcher-js");
var WebSocket = require("ws");

function Controller(dotEnsime, ensimeInstallDir, options) {
  this.dotEnsime = dotEnsime;

  if (options && "sbt" in options) this.sbtCmd = options.sbt;
  else this.sbtCmd = "sbt";
  if (options && "ensimeVersion" in options) this.ensimeVersion = options.ensimeVersion;
  else this.ensimeVersion = "0.9.10-SNAPSHOT";

  this.connection = null;
  this.nextCallId = 0;
  this.callMap = {};

  this.launcher = new Launcher(this.dotEnsime, this.ensimeVersion, ensimeInstallDir, this.sbtCmd);
}

/** Connect to ensime, starting it first if necessary.
 * @param output {out: Stream, err: Stream}
 * @return {ports: {http: Int}, info: ensime-ConnectionInfo} */
Controller.prototype.connect = function(output, callback) {
  if (this.connection) return this.status(callback);

  this.launcher.cleanup(function() {
    this.launcher.start(output, function(err, ports) {
      if (err) return callback(err);
      console.log("ensime now running on port " + ports.http);
      this.connectWebsocket(ports, callback);
    }.bind(this));
  }.bind(this));
};

/** Try to attach to a currently running ensime.
 * @return {ports: {http: Int}, info: ensime-ConnectionInfo} */
Controller.prototype.attach = function(callback) {
  this.launcher.ports(function(err, ports) {
    if (err) return callback("not running");
    console.log("Detected ensime on port " + ports.http);
    this.connectWebsocket(ports, callback);
  }.bind(this));
};

Controller.prototype.connectWebsocket = function(ports, callback) {
  this.connection = new WebSocket("ws://localhost:" + ports.http + "/jerky");
  this.connection.on("open", function() {
    console.log("now connected to ensime...");
    this.status(function(err, data) {
      if (err) return callback(err);
      callback(false, {
        ports: ports,
        info: data
      });
    }.bind(this));
  }.bind(this));
  this.connection.on("message", this.handleIncoming.bind(this));
  this.connection.on("error", function(error) {
    this.handleGeneral({
      disconnected: error
    });
  }.bind(this));
};

/** Update ensime to the specified version. Can also be used to fix installations.
 * @param output {out: Stream, err: Stream}
 * @return nothing */
Controller.prototype.update = function(output, callback) {
  this.launcher.update(output, callback);
};

/** Send a command to ensime. */
Controller.prototype.send = function(cmd, callback) {
  if (!this.connection) return callback("connection not open.");

  var callId = this.nextCallId++;
  this.callMap[callId] = callback;
  var req = {
    req: cmd,
    callId: callId
  };
  //console.debug("Sending "+JSON.stringify(req));
  this.connection.send(JSON.stringify(req));
};

/** Handle an incoming message from ensime. */
Controller.prototype.handleIncoming = function(data) {
  var resp = JSON.parse(data);
  if ("callId" in resp) {
    if (resp.callId in this.callMap) {
      try {
        this.callMap[resp.callId](false, resp.payload);
      }
      catch (e) {
        console.error("Error in callback: " + e);
      }
      finally {
        delete this.callMap[resp.callId];
      }
    }
  }
  else this.handleGeneral(resp.payload);
};

Controller.prototype.cancelPending = function(reason) {
  var key;
  for (key in this.callMap) {
    this.callMap[key](reason);
  }
  this.callMap = {};
};

Controller.prototype.handleGeneral = function(response) {
  //TODO
  console.log("Received general message: " + JSON.stringify(response));
};

Controller.prototype.status = function(callback) {
  this.send({
    typehint: "ConnectionInfoReq"
  }, callback);
};

Controller.prototype.stop = function(callback) {
  this.cancelPending("Stop requested.");

  //Disconnect
  if (this.connection) {
    try {
      this.connection.close();
    }
    catch (e) {
      //ignore
    }
  }

  this.launcher.stop(callback);
};

module.exports = Controller;<|endoftext|>


<commit_before>'use strict';

var fs = require('fs')
  , path = require('path')
  , url = require('url')
  , util = require('util')
  , events = require('events');

var async = require('async')
  , Nano = require('nano');

function Guy(options) {
  var _this = this;
  events.EventEmitter.call(this);

  this.options = options || {};
  this.options.database = this.options.database || 'user_databases';
  this.options.local = this.options.local || url.parse('http://127.0.0.1:5984');
  this.options.remote = this.options.remote;
  this.options.logger = this.options.logger || function() {};
  this.localNano = null;
  this.remoteNano = null;
  this.queueTasks = {};
  this.queue = async.queue(this._queueWorker.bind(this), this.options.concurrency || 4);
  this.ready = false;
  this._init();
}

util.inherits(Guy, events.EventEmitter);

Guy.prototype._init = function() {
  var _this = this;
  this.localNano = Nano(this.options.local.href);
  this.remoteNano = Nano(this.options.remote.href);

  this.logger.debug('checking if remote user database exists');
  this.remoteNano.db[this.options.createRemote ? 'create' : 'get'](this.options.database, function (err, body) {
    if (err && !/\bexists\b/i.test(err.message)) {
      _this.emit('error', new Error('Error communicating with remote database "' + _this._buildUrl(_this.options.remote, { auth: '****', pathname: _this.options.database }) + '". Use option createRemote: true to create it'));
      return;
    }
    _this._initDatabase(function(err) {
      if (err) {
        return _this.emit('error', err);
      }
      _this._syncLocal(function(err) {
        if (err) {
          return _this.emit('error', err);
        }
        _this.logger.debug('sync and watch has run; emitting ready as soon as queue drains');
        _this.queue.drain = function() {
          if (!_this.ready) {
            _this.emit('ready');
            _this.ready = true;
          }
        };
        // if the queue is empty, manually trigger drain (bug in async?)
        if (!_this.queue.length()) {
          _this.queue.drain();
        }
      });
    });
  });
};

Guy.prototype._initDatabase = function(callback) {
  var _this = this;
  _this.logger.debug('init local database');
  var _this = this;
  this.localNano.db.create(this.options.database, function(err, body) {
    // TODO: check error to make sure it's an "already exists" error?
    if (!err) {
      _this.logger.debug('init local database: creating local, replicating');
      _this._replicate(_this.options.database, function(err) {
        if (err) {
          return callback(err);
        }
        _this._watchLocal(callback);
      });
    }
    else {
      _this._watchLocal(callback);
    }
  });
};

Guy.prototype._watchLocal = function(callback) {
  var _this = this;
  var db = this.localNano.use(this.options.database);
  _this.logger.debug('init local database: watching for changes on ' + this.options.database);
  var feed = db.follow({ since: 'now' });
  feed.on('change', function (change) {
    _this.logger.debug(change, 'change');
    _this._enqueue(change.id, !change.deleted);
  });
  feed.on('error', function (err) {
    _this.emit('error', err);
  });
  feed.follow();
  callback(null);
};

// syncs the current data of options.database i.e. adds/removes databases
Guy.prototype._syncLocal = function(callback) {
  var _this = this;
  _this.logger.debug('starting to sync offline user database changes');
  this.localNano.db.list(function(err, allLocalDatabases) {
    if (err) {
      return callback(err);
    }
    // FIXME: convert to paging otherwise a large number of databases could spike the memory usage
    _this.localNano.use(_this.options.database).list(function(err, userDatabases) {
      if (err) {
        return callback(err);
      }
      userDatabases.rows.forEach(function(row) {
        var userDatabase = row.id;
        if (!(userDatabase in _this.queueTasks)) {
          if (allLocalDatabases.indexOf(userDatabase) < 0) {
            _this.logger.debug('user database created while offline ' + userDatabase);
            _this._enqueue(userDatabase, true);
          }
        }
      });
      // TODO: handle user databases that are deleted while offline
      callback(null);
    });
  });
};

Guy.prototype._enqueue = function(database, create) {
  if (!(database in this.queueTasks)) {
    // only add it to the queue if it doesn't already exist
    this.queue.push({ database: database });
  }
  this.queueTasks[database] = create;
};

Guy.prototype._queueWorker = function(task, callback) {
  var _this = this
    , create = this.queueTasks[task.database]
    , database = task.database;
  delete this.queueTasks[database];
  this[create ? '_create' : '_remove'](database, function(err) {
    if (err) {
      _this.emit('error', err);
      return callback(err);
    }
    _this.emit((create ? 'create:' : 'remove:') + database);
    _this.emit('database:' + database, create);
    _this.emit(create ? 'create' : 'remove', database);
    callback(null);
  });
};

// inserts two-way replication between database on local and remote
Guy.prototype._replicate = function(database, callback) {
  var _this = this;
  var rep = this.localNano.use('_replicator')
    , localUrl = this.databaseUrl('local', database)
    , remoteUrl = this.databaseUrl('remote', database);
  this.logger.debug('replicating database: ', database);

  this.remoteNano.db.create(database, function(err, body) {
    if (err && !/\bexists\b/i.test(err.message)) {
      return callback(err);
    }
    _this.logger.debug('replicating database: inserting replication task');
    rep.insert({
      source: localUrl,
      target: remoteUrl,
      continuous: true
    }, null, function(err, body) {
      if (err) {
        return callback(err);
      }
      _this.logger.debug('replicating database: replicated partially complete');
      rep.insert({
        target: localUrl,
        source: remoteUrl,
        continuous: true
      }, null, callback);
    });
  });
};

Guy.prototype._buildUrl = function(urlObj, updates, returnObject) {
  var clonedUrlObj = Object.create(urlObj);
  for (var k in updates) {
    clonedUrlObj[k] = updates[k];
  }
  return returnObject ? clonedUrlObj : url.format(clonedUrlObj);
};

Guy.prototype.databaseUrl = function(localOrRemote, database) {
  return this._buildUrl(this.options[localOrRemote], { pathname: database });
}

Guy.prototype._create = function(database, callback) {
  var _this = this;
  var db = this.localNano.use(this.options.database);

  _this.logger.debug('creating database: ' + database);

  // create database locally
  this.localNano.db.create(database, function(err) {
    if (err) {
      if (/\bexists\b/i.test(err.message)) {
        return callback(null);
      }
      else {
        return callback(err);
      }
    }
    _this.logger.debug('creating database: created locally; adding tracking row in user db');
    // insert it into the list of all user databases
    db.insert({ created: new Date() }, database, function(err, body) {
      if (err && !/\bconflict\b/i.test(err.message)) {
        return callback(err);
      }
      // replicate the newly created database
      _this.logger.debug('creating database: tracking row inserted and triggering replication for new db');
      _this._replicate(database, callback);
    });
  });
};

Guy.prototype._remove = function(database, callback) {
  var _this = this;
  this.localNano.db.destroy(database, function(err) {
    if (err && !/\bmissing\b/i.test(err.message)) {
      return  callback(err);
    }
    callback(null);
  });
};

Guy.prototype.create = function(database, callback) {
  this._enqueue(database, true);
  this.once('database:' + database, function(created) {
    if (!created) {
      return callback(new Error('Database "' + database + '" was removed before it could be created'));
    }
    callback(null);
  });
};

Guy.prototype.remove = function(database, callback) {
  this._enqueue(database, false);
  this.once('database:' + database, function(created) {
    if (created) {
      return callback(new Error('Database "' + database + '" was created before it could be removed'));
    }
    callback(null);
  });
};

Guy.prototype.get = function(database, callback) {
  return this.create(database, callback);
};

module.exports = Guy;

<commit_msg>logging<commit_after>'use strict';

var fs = require('fs')
  , path = require('path')
  , url = require('url')
  , util = require('util')
  , events = require('events');

var async = require('async')
  , Nano = require('nano');

function Guy(options) {
  var _this = this;
  events.EventEmitter.call(this);

  this.options = options || {};
  this.options.database = this.options.database || 'user_databases';
  this.options.local = this.options.local || url.parse('http://127.0.0.1:5984');
  this.options.remote = this.options.remote;
  this.logger = this.options.log || null;
  this.localNano = null;
  this.remoteNano = null;
  this.queueTasks = {};
  this.queue = async.queue(this._queueWorker.bind(this), this.options.concurrency || 4);
  this.ready = false;
  this._init();
}

util.inherits(Guy, events.EventEmitter);

Guy.prototype._init = function() {
  var _this = this;
  this.localNano = Nano(this.options.local.href);
  this.remoteNano = Nano(this.options.remote.href);

  this.logger && this.logger.debug('checking if remote user database exists');
  this.remoteNano.db[this.options.createRemote ? 'create' : 'get'](this.options.database, function (err, body) {
    if (err && !/\bexists\b/i.test(err.message)) {
      _this.emit('error', new Error('Error communicating with remote database "' + _this._buildUrl(_this.options.remote, { auth: '****', pathname: _this.options.database }) + '". Use option createRemote: true to create it'));
      return;
    }
    _this._initDatabase(function(err) {
      if (err) {
        return _this.emit('error', err);
      }
      _this._syncLocal(function(err) {
        if (err) {
          return _this.emit('error', err);
        }
        _this.logger && _this.logger.debug('sync and watch has run; emitting ready as soon as queue drains');
        _this.queue.drain = function() {
          if (!_this.ready) {
            _this.emit('ready');
            _this.ready = true;
          }
        };
        // if the queue is empty, manually trigger drain (bug in async?)
        if (!_this.queue.length()) {
          _this.queue.drain();
        }
      });
    });
  });
};

Guy.prototype._initDatabase = function(callback) {
  var _this = this;
  _this.logger && _this.logger.debug('init local database');
  var _this = this;
  this.localNano.db.create(this.options.database, function(err, body) {
    // TODO: check error to make sure it's an "already exists" error?
    if (!err) {
      _this.logger && _this.logger.debug('init local database: creating local, replicating');
      _this._replicate(_this.options.database, function(err) {
        if (err) {
          return callback(err);
        }
        _this._watchLocal(callback);
      });
    }
    else {
      _this._watchLocal(callback);
    }
  });
};

Guy.prototype._watchLocal = function(callback) {
  var _this = this;
  var db = this.localNano.use(this.options.database);
  _this.logger && _this.logger.debug('init local database: watching for changes on ' + this.options.database);
  var feed = db.follow({ since: 'now' });
  feed.on('change', function (change) {
    _this.logger && _this.logger.debug(change, 'change');
    _this._enqueue(change.id, !change.deleted);
  });
  feed.on('error', function (err) {
    _this.emit('error', err);
  });
  feed.follow();
  callback(null);
};

// syncs the current data of options.database i.e. adds/removes databases
Guy.prototype._syncLocal = function(callback) {
  var _this = this;
  _this.logger && _this.logger.debug('starting to sync offline user database changes');
  this.localNano.db.list(function(err, allLocalDatabases) {
    if (err) {
      return callback(err);
    }
    // FIXME: convert to paging otherwise a large number of databases could spike the memory usage
    _this.localNano.use(_this.options.database).list(function(err, userDatabases) {
      if (err) {
        return callback(err);
      }
      userDatabases.rows.forEach(function(row) {
        var userDatabase = row.id;
        if (!(userDatabase in _this.queueTasks)) {
          if (allLocalDatabases.indexOf(userDatabase) < 0) {
            _this.logger && _this.logger.debug('user database created while offline ' + userDatabase);
            _this._enqueue(userDatabase, true);
          }
        }
      });
      // TODO: handle user databases that are deleted while offline
      callback(null);
    });
  });
};

Guy.prototype._enqueue = function(database, create) {
  if (!(database in this.queueTasks)) {
    // only add it to the queue if it doesn't already exist
    this.queue.push({ database: database });
  }
  this.queueTasks[database] = create;
};

Guy.prototype._queueWorker = function(task, callback) {
  var _this = this
    , create = this.queueTasks[task.database]
    , database = task.database;
  delete this.queueTasks[database];
  this[create ? '_create' : '_remove'](database, function(err) {
    if (err) {
      _this.emit('error', err);
      return callback(err);
    }
    _this.emit((create ? 'create:' : 'remove:') + database);
    _this.emit('database:' + database, create);
    _this.emit(create ? 'create' : 'remove', database);
    callback(null);
  });
};

// inserts two-way replication between database on local and remote
Guy.prototype._replicate = function(database, callback) {
  var _this = this;
  var rep = this.localNano.use('_replicator')
    , localUrl = this.databaseUrl('local', database)
    , remoteUrl = this.databaseUrl('remote', database);
  _this.logger && _this.logger.debug('replicating database: ', database);

  this.remoteNano.db.create(database, function(err, body) {
    if (err && !/\bexists\b/i.test(err.message)) {
      return callback(err);
    }
    _this.logger && _this.logger.debug('replicating database: inserting replication task');
    rep.insert({
      source: localUrl,
      target: remoteUrl,
      continuous: true
    }, null, function(err, body) {
      if (err) {
        return callback(err);
      }
      _this.logger && _this.logger.debug('replicating database: replicated partially complete');
      rep.insert({
        target: localUrl,
        source: remoteUrl,
        continuous: true
      }, null, callback);
    });
  });
};

Guy.prototype._buildUrl = function(urlObj, updates, returnObject) {
  var clonedUrlObj = Object.create(urlObj);
  for (var k in updates) {
    clonedUrlObj[k] = updates[k];
  }
  return returnObject ? clonedUrlObj : url.format(clonedUrlObj);
};

Guy.prototype.databaseUrl = function(localOrRemote, database) {
  return this._buildUrl(this.options[localOrRemote], { pathname: database });
}

Guy.prototype._create = function(database, callback) {
  var _this = this;
  var db = this.localNano.use(this.options.database);

  _this.logger && _this.logger.debug('creating database: ' + database);

  // create database locally
  this.localNano.db.create(database, function(err) {
    if (err) {
      if (/\bexists\b/i.test(err.message)) {
        return callback(null);
      }
      return callback(err);
    }
    _this.logger && _this.logger.debug('creating database: created locally; adding tracking row in user db');
    // insert it into the list of all user databases
    db.insert({ created: new Date() }, database, function(err, body) {
      if (err && !/\bconflict\b/i.test(err.message)) {
        return callback(err);
      }
      // replicate the newly created database
      _this.logger && _this.logger.debug('creating database: tracking row inserted and triggering replication for new db');
      _this._replicate(database, callback);
    });
  });
};

Guy.prototype._remove = function(database, callback) {
  var _this = this;
  this.localNano.db.destroy(database, function(err) {
    if (err && !/\bmissing\b/i.test(err.message)) {
      return  callback(err);
    }
    callback(null);
  });
};

Guy.prototype.create = function(database, callback) {
  var _this = this;
  this._enqueue(database, true);
  this.once('database:' + database, function(created) {
    if (!created) {
      return callback(new Error('Database "' + database + '" was removed before it could be created'));
    }
    callback(null, _this.localNano.use(database));
  });
};

Guy.prototype.remove = function(database, callback) {
  this._enqueue(database, false);
  this.once('database:' + database, function(created) {
    if (created) {
      return callback(new Error('Database "' + database + '" was created before it could be removed'));
    }
    callback(null);
  });
};

Guy.prototype.get = function(database, create, callback) {
  var _this = this;
  if (typeof create === 'function') {
    callback = create;
    create = false;
  }
  if (true === create) {
    this.create(database, callback);
  }
  else {
    this.localNano.db.get(database, function(err, body) {
      if (err) {
        return callback(err);
      }
      callback(null, _this.localNano.use(database));
    });
  }
};

module.exports = Guy;

<|endoftext|>


<commit_before>var fs = require('fs');
var os = require('os');
var ps = require('path');
var cs = require('crypto');
var rm = require('rimraf');

var SYS_DIR_MODE = 0700;
var SYS_FILE_MODE = 0600;
var SYS_FILE_FLAGS = 'wx+';
var TEMPLATE_RE = /X+/g;
var CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';

var noop = function (callback) {
  callback && process.nextTick(callback);
};
var tracking = false;
var trackedDirs = {};
var trackedFiles = {};

process.addListener('exit', function (exitcode) {
  tracking && clearSync();
});

function track(on) {
  tracking = (on == null ? true : Boolean(on));
}

function clearSync() {
  for (var k in trackedFiles) {
    trackedFiles[k] && trackedFiles[k]();
  }
  for (var k in trackedDirs) {
    trackedDirs[k] && trackedDirs[k]();
  }
}

function clear(callback) {
  var jobs = [];
  for (var k in trackedFiles) {
    if (trackedFiles[k]) {
      jobs.push(function (next) {
        trackedFiles[k](next);
      });
    }
  }
  for (var k in trackedDirs) {
    if (trackedDirs[k]) {
      jobs.push(function (next) {
        trackedDirs[k](next);
      });
    }
  }
  callback && jobs.push(function (next) { callback(); });
  queue(jobs);
}

function generateFileUnlinker(fd, path) {
  var called = false;
  var unlink = function unlink(callback) {
    if (called) {
      callback && process.nextTick(callback);
      return;
    }
    called = true;
    this.called = true;
    if (callback) {
      fs.unlink(path, function (err) {
        if (trackedFiles[fd] === unlink) {
          delete trackedFiles[fd];
        }
        callback && callback();
      });
    } else {
      try {
        fs.unlinkSync(path);
      } finally {
        if (trackedFiles[fd] === unlink) {
          delete trackedFiles[fd];
        }
      }
    }
  };
  trackedFiles[fd] = unlink;
  return unlink;
}

function generateDirUnlinker(recursive, path) {
  var called = false;
  var unlink = function unlink(callback) {
    if (called) {
      callback && process.nextTick(callback);
      return;
    }
    called = true;
    if (callback) {
      var rmdir = recursive ? rm : fs.rmdir;
      rmdir(path, function (err) {
        if (trackedDirs[path] === unlink) {
          delete trackedDirs[path];
        }
        callback && callback();
      });
    } else {
      var rmdirSync = recursive ? rm.sync.bind(rm) : fs.rmdirSync.bind(fs);
      try {
        rmdirSync(path);
      } finally {
        if (trackedDirs[path] === unlink) {
          delete trackedDirs[path];
        }
      }
    }
  };
  trackedDirs[path] = unlink;
  return unlink;
}

function queue(jobs) {
  var next = function() {
    if (jobs.length && !this.called) {
      this.called = true;
      jobs.shift()(next.bind({}));
    }
  };
  next.call({});
}

function registerFilename(name, opts, callback) {
  fs.open(name, SYS_FILE_FLAGS, opts.mode || SYS_FILE_MODE, function (err, fd) {
    if (err) {
      callback(null);
      return;
    }
    fs.realpath(name, function (err, path) {
      if (err) {
        callback(null);
        return;
      }
      var unlink;
      if (opts.track || (opts.track == null && tracking)) {
        if (!trackedFiles[fd]) {
          unlink = generateFileUnlinker(fd, path);
        } else {
          throw new Error("Didn't you delete files via file.unlink()?");
        }
      } else {
        unlink = noop;
      }
      callback({path: path, fd: fd, unlink: unlink});
    });
  });
}

function generateFile() {
  var args = getArgs(arguments);
  var opts = args[0];
  var callback = args[1];
  var limit = opts.limit || 5;
  var registerCallback = function (file) {
    if (limit-- >= 0) {
      if (file) {
        callback && callback(null, file);
      } else {
        registerFilename(generateName(opts), opts, registerCallback);
      }
    } else {
      var err = new Error('Failed to get a temporary file within limits.');
      callback && callback(err, null);
    }
  };
  registerFilename(generateName(opts), opts, registerCallback);
}

function registerFilenameSync(name, opts) {
  try {
    var fd = fs.openSync(name, SYS_FILE_FLAGS, opts.mode || SYS_FILE_MODE);
    var path = fs.realpathSync(name);
    var unlink;
    if (opts.track || (opts.track == null && tracking)) {
      if (!trackedFiles[fd]) {
        unlink = generateFileUnlinker(fd, path);
        trackedFiles[fd] = unlink;
      } else {
        throw new Error("Didn't you delete files via file.unlink()?");
      }
    } else {
      unlink = noop;
    }
    return {path: path, fd: fd, unlink: unlink};
  } catch (err) {
    return null;
  }
}

function generateFileSync(opts) {
  opts = opts || {};
  var limit = opts.limit || 5;
  do {
    var file = registerFilenameSync(generateName(opts), opts);
    if (file) {
      return file;
    }
  } while (limit-- > 0);
  throw new Error('Failed to get a temporary file within limits.');
}

function registerDirname(name, opts, callback) {
  fs.mkdir(name, opts.mode || SYS_DIR_MODE, function (err) {
    if (err) {
      callback(null);
      return;
    }
    fs.realpath(name, function (err, path) {
      if (err) {
        callback(null);
        return;
      }
      var unlink;
      var recursive = Boolean(opts.recursive);
      if (opts.track || (opts.track == null && tracking)) {
        if (!trackedDirs[path]) {
          unlink = generateDirUnlinker(recursive, path);
        } else {
          throw new Error("Didn't you delete directories via directory.unlink()?");
        }
      } else {
        unlink = noop;
      }
      callback({path: path, recursive: recursive, unlink: unlink});
    });
  });
}

function generateDir() {
  var args = getArgs(arguments);
  var opts = args[0];
  var callback = args[1];
  var limit = opts.limit || 5;
  var registerCallback = function (dir) {
    if (limit-- >= 0) {
      if (dir) {
        callback && callback(null, dir);
      } else {
        registerDirname(generateName(opts), opts, registerCallback);
      }
    } else {
      var err = new Error('Failed to get a temporary directory within limits.');
      callback && callback(err, null);
    }
  };
  registerDirname(generateName(opts), opts, registerCallback);
}

function registerDirnameSync(name, opts) {
  try {
    fs.mkdirSync(name, opts.mode || SYS_DIR_MODE);
    var path = fs.realpathSync(name);
    var unlink;
    var recursive = Boolean(opts.recursive);
    if (opts.track || (opts.track == null && tracking)) {
      if (!trackedDirs[path]) {
        unlink = generateDirUnlinker(recursive, path);
      } else {
        throw new Error("Didn't you delete directories via directory.unlink()?");
      }
    } else {
      unlink = noop;
    }
    return {path: path, recursive: recursive, unlink: unlink};
  } catch (err) {
    return null;
  }
}

function generateDirSync(opts) {
  opts = opts || {};
  var limit = opts.limit || 5;
  do {
    var dir = registerDirnameSync(generateName(opts), opts);
    if (dir) {
      return dir;
    }
  } while (limit-- > 0);
  throw new Error('Failed to get a temporary directory within limits.');
}

function getArgs(args) {
  var opts, callback;
  if (typeof args[0] === 'function') {
    opts = args[1];
    callback = args[0];
  } else {
    opts = args[0];
    callback = args[1];
  }
  opts = opts || {};
  return [opts, callback];
}

function randomString(length) {
  var buffer;
  try {
    buffer = cs.randomBytes(length);
  } catch (err) {
    buffer = cs.pseudoRandomBytes(length);
  }
  var chars = [];
  for (var i = 0; i < length; i++) {
    chars.push(CHARS[buffer[i]%CHARS.length]);
  }
  return chars.join('');
}

function generateName(opts) {
  opts = opts || {};
  if (opts.name) {
    return ps.join(opts.dir || os.tmpDir(), opts.name);
  }
  if (opts.template) {
    if (TEMPLATE_RE.test(opts.template)) {
      var name = opts.template.replace(TEMPLATE_RE, function (s) {
        return randomString(s.length);
      });
      return ps.join(opts.dir || os.tmpDir(), name);
    } else {
      throw new Error('Invalid template string.');
    }
  }
  var name = [
    opts.prefix || 'tmp-',
    Date.now(),
    '-',
    process.pid,
    '-',
    randomString(12),
    opts.suffix || ''
  ].join('');
  return ps.join(opts.dir || os.tmpDir(), name);
}

module.exports = {
  track: track,
  clear: clear,
  clearSync: clearSync,
  open: generateFile,
  openSync: generateFileSync,
  mkdir: generateDir,
  mkdirSync: generateDirSync,
  name: generateName,
  dir: os.tmpDir.bind(os)
};
<commit_msg>Fix: The result of tempfs.dir() should be resolved.<commit_after>var fs = require('fs');
var os = require('os');
var ps = require('path');
var cs = require('crypto');
var rm = require('rimraf');

var SYS_DIR_MODE = 0700;
var SYS_FILE_MODE = 0600;
var SYS_FILE_FLAGS = 'wx+';
var TEMPLATE_RE = /X+/g;
var CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';

var noop = function (callback) {
  callback && process.nextTick(callback);
};
var tracking = false;
var trackedDirs = {};
var trackedFiles = {};

process.addListener('exit', function (exitcode) {
  tracking && clearSync();
});

function track(on) {
  tracking = (on == null ? true : Boolean(on));
}

function clearSync() {
  for (var k in trackedFiles) {
    trackedFiles[k] && trackedFiles[k]();
  }
  for (var k in trackedDirs) {
    trackedDirs[k] && trackedDirs[k]();
  }
}

function clear(callback) {
  var jobs = [];
  for (var k in trackedFiles) {
    if (trackedFiles[k]) {
      jobs.push(function (next) {
        trackedFiles[k](next);
      });
    }
  }
  for (var k in trackedDirs) {
    if (trackedDirs[k]) {
      jobs.push(function (next) {
        trackedDirs[k](next);
      });
    }
  }
  callback && jobs.push(function (next) { callback(); });
  queue(jobs);
}

function generateFileUnlinker(fd, path) {
  var called = false;
  var unlink = function unlink(callback) {
    if (called) {
      callback && process.nextTick(callback);
      return;
    }
    called = true;
    this.called = true;
    if (callback) {
      fs.unlink(path, function (err) {
        if (trackedFiles[fd] === unlink) {
          delete trackedFiles[fd];
        }
        callback && callback();
      });
    } else {
      try {
        fs.unlinkSync(path);
      } finally {
        if (trackedFiles[fd] === unlink) {
          delete trackedFiles[fd];
        }
      }
    }
  };
  trackedFiles[fd] = unlink;
  return unlink;
}

function generateDirUnlinker(recursive, path) {
  var called = false;
  var unlink = function unlink(callback) {
    if (called) {
      callback && process.nextTick(callback);
      return;
    }
    called = true;
    if (callback) {
      var rmdir = recursive ? rm : fs.rmdir;
      rmdir(path, function (err) {
        if (trackedDirs[path] === unlink) {
          delete trackedDirs[path];
        }
        callback && callback();
      });
    } else {
      var rmdirSync = recursive ? rm.sync.bind(rm) : fs.rmdirSync.bind(fs);
      try {
        rmdirSync(path);
      } finally {
        if (trackedDirs[path] === unlink) {
          delete trackedDirs[path];
        }
      }
    }
  };
  trackedDirs[path] = unlink;
  return unlink;
}

function queue(jobs) {
  var next = function() {
    if (jobs.length && !this.called) {
      this.called = true;
      jobs.shift()(next.bind({}));
    }
  };
  next.call({});
}

function registerFilename(name, opts, callback) {
  fs.open(name, SYS_FILE_FLAGS, opts.mode || SYS_FILE_MODE, function (err, fd) {
    if (err) {
      callback(null);
      return;
    }
    fs.realpath(name, function (err, path) {
      if (err) {
        callback(null);
        return;
      }
      var unlink;
      if (opts.track || (opts.track == null && tracking)) {
        if (!trackedFiles[fd]) {
          unlink = generateFileUnlinker(fd, path);
        } else {
          throw new Error("Didn't you delete files via file.unlink()?");
        }
      } else {
        unlink = noop;
      }
      callback({path: path, fd: fd, unlink: unlink});
    });
  });
}

function generateFile() {
  var args = getArgs(arguments);
  var opts = args[0];
  var callback = args[1];
  var limit = opts.limit || 5;
  var registerCallback = function (file) {
    if (limit-- >= 0) {
      if (file) {
        callback && callback(null, file);
      } else {
        registerFilename(generateName(opts), opts, registerCallback);
      }
    } else {
      var err = new Error('Failed to get a temporary file within limits.');
      callback && callback(err, null);
    }
  };
  registerFilename(generateName(opts), opts, registerCallback);
}

function registerFilenameSync(name, opts) {
  try {
    var fd = fs.openSync(name, SYS_FILE_FLAGS, opts.mode || SYS_FILE_MODE);
    var path = fs.realpathSync(name);
    var unlink;
    if (opts.track || (opts.track == null && tracking)) {
      if (!trackedFiles[fd]) {
        unlink = generateFileUnlinker(fd, path);
        trackedFiles[fd] = unlink;
      } else {
        throw new Error("Didn't you delete files via file.unlink()?");
      }
    } else {
      unlink = noop;
    }
    return {path: path, fd: fd, unlink: unlink};
  } catch (err) {
    return null;
  }
}

function generateFileSync(opts) {
  opts = opts || {};
  var limit = opts.limit || 5;
  do {
    var file = registerFilenameSync(generateName(opts), opts);
    if (file) {
      return file;
    }
  } while (limit-- > 0);
  throw new Error('Failed to get a temporary file within limits.');
}

function registerDirname(name, opts, callback) {
  fs.mkdir(name, opts.mode || SYS_DIR_MODE, function (err) {
    if (err) {
      callback(null);
      return;
    }
    fs.realpath(name, function (err, path) {
      if (err) {
        callback(null);
        return;
      }
      var unlink;
      var recursive = Boolean(opts.recursive);
      if (opts.track || (opts.track == null && tracking)) {
        if (!trackedDirs[path]) {
          unlink = generateDirUnlinker(recursive, path);
        } else {
          throw new Error("Didn't you delete directories via directory.unlink()?");
        }
      } else {
        unlink = noop;
      }
      callback({path: path, recursive: recursive, unlink: unlink});
    });
  });
}

function generateDir() {
  var args = getArgs(arguments);
  var opts = args[0];
  var callback = args[1];
  var limit = opts.limit || 5;
  var registerCallback = function (dir) {
    if (limit-- >= 0) {
      if (dir) {
        callback && callback(null, dir);
      } else {
        registerDirname(generateName(opts), opts, registerCallback);
      }
    } else {
      var err = new Error('Failed to get a temporary directory within limits.');
      callback && callback(err, null);
    }
  };
  registerDirname(generateName(opts), opts, registerCallback);
}

function registerDirnameSync(name, opts) {
  try {
    fs.mkdirSync(name, opts.mode || SYS_DIR_MODE);
    var path = fs.realpathSync(name);
    var unlink;
    var recursive = Boolean(opts.recursive);
    if (opts.track || (opts.track == null && tracking)) {
      if (!trackedDirs[path]) {
        unlink = generateDirUnlinker(recursive, path);
      } else {
        throw new Error("Didn't you delete directories via directory.unlink()?");
      }
    } else {
      unlink = noop;
    }
    return {path: path, recursive: recursive, unlink: unlink};
  } catch (err) {
    return null;
  }
}

function generateDirSync(opts) {
  opts = opts || {};
  var limit = opts.limit || 5;
  do {
    var dir = registerDirnameSync(generateName(opts), opts);
    if (dir) {
      return dir;
    }
  } while (limit-- > 0);
  throw new Error('Failed to get a temporary directory within limits.');
}

function getArgs(args) {
  var opts, callback;
  if (typeof args[0] === 'function') {
    opts = args[1];
    callback = args[0];
  } else {
    opts = args[0];
    callback = args[1];
  }
  opts = opts || {};
  return [opts, callback];
}

function randomString(length) {
  var buffer;
  try {
    buffer = cs.randomBytes(length);
  } catch (err) {
    buffer = cs.pseudoRandomBytes(length);
  }
  var chars = [];
  for (var i = 0; i < length; i++) {
    chars.push(CHARS[buffer[i]%CHARS.length]);
  }
  return chars.join('');
}

function generateName(opts) {
  opts = opts || {};
  if (opts.name) {
    return ps.join(opts.dir || os.tmpDir(), opts.name);
  }
  if (opts.template) {
    if (TEMPLATE_RE.test(opts.template)) {
      var name = opts.template.replace(TEMPLATE_RE, function (s) {
        return randomString(s.length);
      });
      return ps.join(opts.dir || os.tmpDir(), name);
    } else {
      throw new Error('Invalid template string.');
    }
  }
  var name = [
    opts.prefix || 'tmp-',
    Date.now(),
    '-',
    process.pid,
    '-',
    randomString(12),
    opts.suffix || ''
  ].join('');
  return ps.join(opts.dir || os.tmpDir(), name);
}

module.exports = {
  track: track,
  clear: clear,
  clearSync: clearSync,
  open: generateFile,
  openSync: generateFileSync,
  mkdir: generateDir,
  mkdirSync: generateDirSync,
  name: generateName,
  dir: function () { return ps.resolve(os.tmpDir()); }
};
<|endoftext|>


<commit_before>require('./config/config');
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const cors = require('cors');

const router = express.Router();
const port = process.env.PORT || 3000;

const mongoose = require('./db/mongoose');
const userRoutes = require('./middleware/userRoutes')(router);

const app = express();

app.use(cors({origin: 'http://localhost:4200'}));
app.use(bodyParser.json());
app.use(express.static(__dirname + '/Client/dist'));
app.use('/user', userRoutes);
app.use(bodyParser.urlencoded({ extended: false }));

app.get('/', (request, response) => {
    response.send('Hello World!');
});

app.listen(port, () => {
    console.log(`Server is up on port ${port}`);
});

module.exports = {app};<commit_msg>change in API msg<commit_after>require('./config/config');
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const cors = require('cors');

const router = express.Router();
const port = process.env.PORT || 3000;

const mongoose = require('./db/mongoose');
const userRoutes = require('./middleware/userRoutes')(router);

const app = express();

app.use(cors({origin: 'http://localhost:4200'}));
app.use(bodyParser.json());
app.use(express.static(__dirname + '/Client/dist'));
app.use('/user', userRoutes);
app.use(bodyParser.urlencoded({ extended: false }));

app.get('/', (request, response) => {
    response.send('API service');
});

app.listen(port, () => {
    console.log(`Server is up on port ${port}`);
});

module.exports = {app};<|endoftext|>


<commit_before>/**
 *      lgtv2 - Simple Node.js module to remote control LG WebOS smart TVs
 *
 *      MIT (c) 2015 Sebastian Raff <hq@ccu.io> (https://github.com/hobbyquaker)
 *      this is a fork of https://github.com/msloth/lgtv.js, heavily modified and rewritten to suite my needs.
 *
 */

var fs = require('fs'); // for storing client key
var WebSocketClient = require('websocket').client; // for communication with TV
var EventEmitter = require('events').EventEmitter;
var util =  require('util');

var SpecializedSocket = function (ws) {
    this.send = function(type, payload) {
        payload = payload || {};
        // the message should be key:value pairs, one per line,
        // with an extra blank line to terminate.
        var message =
            Object.keys(payload)
                .reduce(function(acc, k) {
                    return acc.concat([k + ':' + payload[k]]);
                }, ['type:' + type])
                .join('\n') + '\n\n';

        ws.send(message);
    };

    this.close = function() {
        ws.close();
    };
};

var LGTV = function (config) {
    if (!(this instanceof LGTV)) return new LGTV(config);
    var that = this;

    config = config || {};
    config.url = config.url || 'ws://lgwebostv:3000';
    config.timeout = config.timeout || 15000;
    config.reconnect = typeof config.reconnect === 'undefined' ? 5000 : config.reconnect;
    if (config.clientKey === undefined) {
        config.keyFile = (config.keyFile ? config.keyFile : './lgtv-') + config.url.replace(/[a-z]+:\/\/([0-9a-zA-Z-_.]+):[0-9]+/, '$1');
        try {
            that.clientKey = fs.readFileSync(config.keyFile).toString();
        } catch (e) {
            //console.error(config.keyFile, e);
        }
    } else {
        that.clientKey = config.clientKey;
    }

    that.saveKey = config.saveKey || function (key, cb) {
        //console.log('saveKey', config.address, key);
        that.clientKey = key;
        fs.writeFile(config.keyFile, key, cb);
    };

    var client = new WebSocketClient();
    var connection = {};
    var isPaired = false;
    var autoReconnect = config.reconnect;

    var specializedSockets = {};

    var callbacks = {};
    var cidCount = 0;
    var cidPrefix = ('0000000' + (Math.floor(Math.random() * 0xFFFFFFFF).toString(16))).slice(-8);

    function getCid() {
        return cidPrefix + ('000' + (cidCount++).toString(16)).slice(-4);
    }

    var pairing = require('./pairing.json');

    client.on('connectFailed', function (error) {
        //console.log('connect failed', error);
        that.emit('error', error);

        if (config.reconnect) {
            setTimeout(function () {
                if (autoReconnect) that.connect(config.url);
            }, config.reconnect);
        }
    });

    client.on('connect', function (conn) {
        //console.log('client connect', connection);
        connection = conn;

        connection.on('error', function (error) {
            //console.log('connection error', error);
            that.emit('error', error);
        });

        connection.on('close', function (e) {
            //console.log('connection close', arguments);
            connection = {};
            delete connection;
            for (var i in callbacks) {
                delete callbacks[i];
            }
            that.emit('close', e);
            if (config.reconnect) {
                setTimeout(function () {
                    if (autoReconnect) that.connect(config.url);
                }, config.reconnect);
            }

        });

        connection.on('message', function (message) {
            //console.log('connection message', message);
            if (message.type === 'utf8') {
                try {
                    message = JSON.parse(message.utf8Data);
                    //console.log('<--', message);

                    if (callbacks[message.id]) {
                        callbacks[message.id](null, message.payload);
                    }

                } catch (e) {
                    //console.log('<  ', message.utf8Data);
                }

            } else {
                //console.log('<  ', message.toString());
            }
        });

        isPaired = false;

        that.register();

    });

    this.register = function () {

        pairing['client-key'] = that.clientKey || undefined;

        that.send('register', undefined, pairing, function (err, res) {

            if (!err && res) {
                if (!res["client-key"]) {
                    that.emit('prompt');
                } else {
                    that.emit('connect');
                    that.saveKey(res["client-key"]);
                    isPaired = true;
                }
            } else {
                that.emit('error', err);
                //console.log(err, res);
            }

        });
    };

    this.request = function (uri, payload, cb) {
        this.send('request', uri, payload, cb);
    };

    this.subscribe = function (uri, payload, cb) {
        this.send('subscribe', uri, payload, cb);
    };

    this.send = function (type, uri, /* optional */ payload, /* optional */ cb) {
        if (typeof payload === 'function') {
            cb = payload;
            payload = {};
        }

        //console.log(type, connection);

        if (!connection.connected) {
            if (typeof cb === 'function') cb(new Error('not connected'));
            return;
        }

        var cid = getCid();

        var json = JSON.stringify({
            id: cid,
            type: type,
            uri: uri,
            payload: payload
        });

        //console.log('-->', json);

        if (typeof cb === 'function') {

            switch (type)  {
                case 'request':
                    callbacks[cid] = function (err, res) {
                        // remove callback reference
                        delete callbacks[cid];
                        cb(err, res);

                    };

                    // set callback timeout
                    setTimeout(function () {
                        if (callbacks[cid]) cb(new Error('timeout'));
                        // remove callback reference
                        delete callbacks[cid];
                    }, config.timeout);
                    break;

                case 'subscribe':
                    callbacks[cid] = cb;
                    break;

                case 'register':
                    callbacks[cid] = cb;
                    break;
                default:
                    throw new Error('unknown type');
            }
        }
        connection.send(json);
    };

    this.getSocket = function (url, cb) {
        if (specializedSockets[url]) {
            cb(null, specializedSockets[url]);
            return;
        }

        that.request(url, function (err, data) {
            if (err) {
                cb(err);
                return;
            }

            var special = new WebSocketClient();
            special
                .on('connect', function (conn) {
                    conn
                        .on('error', function (error) {
                            that.emit('error', error);
                        })
                        .on('close', function() {
                            delete specializedSockets[url];
                        });

                    specializedSockets[url] = new SpecializedSocket(conn);
                    cb(null, specializedSockets[url]);
                })
                .on('connectFailed', function(error) {
                    that.emit('error', error);
                });

            special.connect(data.socketPath);
        });
    };

    /**
     *      Connect to TV using a websocket url (eg "ws://192.168.0.100:3000")
     *
     */
    this.connect = function (host) {
        autoReconnect = config.reconnect;

        if (connection.connected && !isPaired) {
            that.register();
        } else if (!connection.connected) {
            that.emit('connecting', host);
            connection = {};
            client.connect(host);
        }
    };

    this.disconnect = function () {
        connection.close();
        autoReconnect = false;

        Object.keys(specializedSockets).forEach(
            function (k) {
                specializedSockets[k].close();
            }
        );
    };

    setTimeout(function () {
        that.connect(config.url);
    }, 0);
};

util.inherits(LGTV, EventEmitter);

module.exports = LGTV;
<commit_msg>Status getter<commit_after>/**
 *      lgtv2 - Simple Node.js module to remote control LG WebOS smart TVs
 *
 *      MIT (c) 2015 Sebastian Raff <hq@ccu.io> (https://github.com/hobbyquaker)
 *      this is a fork of https://github.com/msloth/lgtv.js, heavily modified and rewritten to suite my needs.
 *
 */

var fs = require('fs'); // for storing client key
var WebSocketClient = require('websocket').client; // for communication with TV
var EventEmitter = require('events').EventEmitter;
var util =  require('util');

var SpecializedSocket = function (ws) {
    this.send = function(type, payload) {
        payload = payload || {};
        // the message should be key:value pairs, one per line,
        // with an extra blank line to terminate.
        var message =
            Object.keys(payload)
                .reduce(function(acc, k) {
                    return acc.concat([k + ':' + payload[k]]);
                }, ['type:' + type])
                .join('\n') + '\n\n';

        ws.send(message);
    };

    this.close = function() {
        ws.close();
    };
};

var LGTV = function (config) {
    if (!(this instanceof LGTV)) return new LGTV(config);
    var that = this;

    config = config || {};
    config.url = config.url || 'ws://lgwebostv:3000';
    config.timeout = config.timeout || 15000;
    config.reconnect = typeof config.reconnect === 'undefined' ? 5000 : config.reconnect;
    if (config.clientKey === undefined) {
        config.keyFile = (config.keyFile ? config.keyFile : './lgtv-') + config.url.replace(/[a-z]+:\/\/([0-9a-zA-Z-_.]+):[0-9]+/, '$1');
        try {
            that.clientKey = fs.readFileSync(config.keyFile).toString();
        } catch (e) {
            //console.error(config.keyFile, e);
        }
    } else {
        that.clientKey = config.clientKey;
    }

    that.saveKey = config.saveKey || function (key, cb) {
        //console.log('saveKey', config.address, key);
        that.clientKey = key;
        fs.writeFile(config.keyFile, key, cb);
    };

    var client = new WebSocketClient();
    var connection = {};
    var isPaired = false;
    var autoReconnect = config.reconnect;

    var specializedSockets = {};

    var callbacks = {};
    var cidCount = 0;
    var cidPrefix = ('0000000' + (Math.floor(Math.random() * 0xFFFFFFFF).toString(16))).slice(-8);

    function getCid() {
        return cidPrefix + ('000' + (cidCount++).toString(16)).slice(-4);
    }

    var pairing = require('./pairing.json');

    client.on('connectFailed', function (error) {
        //console.log('connect failed', error);
        that.emit('error', error);

        if (config.reconnect) {
            setTimeout(function () {
                if (autoReconnect) that.connect(config.url);
            }, config.reconnect);
        }
    });

    client.on('connect', function (conn) {
        //console.log('client connect', connection);
        connection = conn;

        connection.on('error', function (error) {
            //console.log('connection error', error);
            that.emit('error', error);
        });

        connection.on('close', function (e) {
            //console.log('connection close', arguments);
            connection = {};
            delete connection;
            for (var i in callbacks) {
                delete callbacks[i];
            }
            that.emit('close', e);
            if (config.reconnect) {
                setTimeout(function () {
                    if (autoReconnect) that.connect(config.url);
                }, config.reconnect);
            }

        });

        connection.on('message', function (message) {
            //console.log('connection message', message);
            if (message.type === 'utf8') {
                try {
                    message = JSON.parse(message.utf8Data);
                    //console.log('<--', message);

                    if (callbacks[message.id]) {
                        callbacks[message.id](null, message.payload);
                    }

                } catch (e) {
                    //console.log('<  ', message.utf8Data);
                }

            } else {
                //console.log('<  ', message.toString());
            }
        });

        isPaired = false;

        that.connection = connection;

        that.register();

    });

    this.register = function () {

        pairing['client-key'] = that.clientKey || undefined;

        that.send('register', undefined, pairing, function (err, res) {

            if (!err && res) {
                if (!res["client-key"]) {
                    that.emit('prompt');
                } else {
                    that.emit('connect');
                    that.saveKey(res["client-key"]);
                    isPaired = true;
                }
            } else {
                that.emit('error', err);
                //console.log(err, res);
            }

        });
    };

    this.request = function (uri, payload, cb) {
        this.send('request', uri, payload, cb);
    };

    this.subscribe = function (uri, payload, cb) {
        this.send('subscribe', uri, payload, cb);
    };

    this.send = function (type, uri, /* optional */ payload, /* optional */ cb) {
        if (typeof payload === 'function') {
            cb = payload;
            payload = {};
        }

        //console.log(type, connection);

        if (!connection.connected) {
            if (typeof cb === 'function') cb(new Error('not connected'));
            return;
        }

        var cid = getCid();

        var json = JSON.stringify({
            id: cid,
            type: type,
            uri: uri,
            payload: payload
        });

        //console.log('-->', json);

        if (typeof cb === 'function') {

            switch (type)  {
                case 'request':
                    callbacks[cid] = function (err, res) {
                        // remove callback reference
                        delete callbacks[cid];
                        cb(err, res);

                    };

                    // set callback timeout
                    setTimeout(function () {
                        if (callbacks[cid]) cb(new Error('timeout'));
                        // remove callback reference
                        delete callbacks[cid];
                    }, config.timeout);
                    break;

                case 'subscribe':
                    callbacks[cid] = cb;
                    break;

                case 'register':
                    callbacks[cid] = cb;
                    break;
                default:
                    throw new Error('unknown type');
            }
        }
        connection.send(json);
    };

    this.getSocket = function (url, cb) {
        if (specializedSockets[url]) {
            cb(null, specializedSockets[url]);
            return;
        }

        that.request(url, function (err, data) {
            if (err) {
                cb(err);
                return;
            }

            var special = new WebSocketClient();
            special
                .on('connect', function (conn) {
                    conn
                        .on('error', function (error) {
                            that.emit('error', error);
                        })
                        .on('close', function() {
                            delete specializedSockets[url];
                        });

                    specializedSockets[url] = new SpecializedSocket(conn);
                    cb(null, specializedSockets[url]);
                })
                .on('connectFailed', function(error) {
                    that.emit('error', error);
                });

            special.connect(data.socketPath);
        });
    };

    /**
     *      Connect to TV using a websocket url (eg "ws://192.168.0.100:3000")
     *
     */
    this.connect = function (host) {
        autoReconnect = config.reconnect;

        if (connection.connected && !isPaired) {
            that.register();
        } else if (!connection.connected) {
            that.emit('connecting', host);
            connection = {};
            client.connect(host);
        }
    };

    this.disconnect = function () {
        connection.close();
        autoReconnect = false;

        Object.keys(specializedSockets).forEach(
            function (k) {
                specializedSockets[k].close();
            }
        );
    };

    setTimeout(function () {
        that.connect(config.url);
    }, 0);
};

util.inherits(LGTV, EventEmitter);

module.exports = LGTV;
<|endoftext|>


<commit_before>var assert = require('assert');
var tzdata = require('./lib/tzdata.js');
exports.tzdata = tzdata;

var _Date = Date;
exports._Date = _Date;

var timezone;

var weekDays = ['Sun', 'Mon','Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'Jun', 'Jul', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec'];

var HOUR = 60 * 60 * 1000;

var date_iso_8601_regex=/^\d\d\d\d(-\d\d(-\d\d(T\d\d\:\d\d\:\d\d(\.\d\d\d)?(Z|[+-]\d\d\:?\d\d))?)?)?$/;
var date_with_offset=/^\d\d\d\d-\d\d-\d\d \d\d\:\d\d\:\d\d(\.\d\d\d)? (Z|(\-|\+|)\d\d\:\d\d)$/;
var date_rfc_2822_regex=/^\d\d-\w\w\w-\d\d\d\d \d\d\:\d\d\:\d\d (\+|-)\d\d\d\d$/;
var local_date_regex=/^\d\d\d\d-\d\d-\d\d[T ]\d\d\:\d\d\:\d\d(\.\d\d\d)?$/;

function MockDate(param) {
  if (arguments.length === 0) {
    this.d = new _Date();
  } else if (arguments.length === 1) {
    if (param instanceof MockDate) {
      this.d = new _Date(param.d);
    } else if (typeof param === 'string') {
      if (param.match(date_iso_8601_regex) || param.match(date_with_offset) || param.match(date_rfc_2822_regex) || param === '') {
        this.d = new _Date(param);
      } else if (param.match(local_date_regex)) {
        this.d = new _Date();
        this.fromLocal(new _Date(param.replace(' ', 'T') + 'Z'));
      } else {
        assert.ok(false, 'Unhandled date format passed to MockDate constructor: ' + param);
      }
    } else if (typeof param === 'number') {
      this.d = new _Date(param);
    } else if (typeof param === 'undefined') {
      this.d = new _Date();
    } else {
      assert.ok(false, 'Unhandled type passed to MockDate constructor: ' + typeof param);
    }
  } else {
    this.d = new _Date();
    this.fromLocal(new _Date(_Date.UTC.apply(null, arguments)));
  }
}

MockDate.prototype.calcTZO = function (ts) {
  var data = tzdata[timezone];
  assert.ok(data, 'Unsupported timezone: ' + timezone);
  ts = (ts || this.d.getTime()) / 1000;
  for (var ii = 2; ii < data.transitions.length; ii+=2) {
    if (data.transitions[ii] > ts) {
      return -data.transitions[ii-1];
    }
  }
  assert.ok(false, ts);
};

function passthrough(fn) {
  MockDate.prototype[fn] = function () {
    var real_date;
    if (this instanceof MockDate) {
      real_date = this.d;
    } else if (this instanceof _Date) {
      // console.log calls our prototype to format regular Date objects!
      // This should only be hit while debugging MockDate itself though, as
      // there should be no _Date objects in user code when using MockDate.
      real_date = this;
    } else {
      assert(false, 'Unexpected object type');
    }
    return real_date[fn].apply(real_date, arguments);
  };
}
function localgetter(fn) {
  MockDate.prototype[fn] = function () {
    var d = new _Date(this.d.getTime() - this.calcTZO() * HOUR);
    return d['getUTC' + fn.slice(3)]();
  };
}
MockDate.prototype.fromLocal = function(d) {
  // From a Date object in the fake-timezone where the returned UTC values are
  //   meant to be interpreted as local values.
  this.d.setTime(d.getTime() + this.calcTZO(d.getTime() + this.calcTZO(d.getTime()) * HOUR) * HOUR);
};
function localsetter(fn) {
  MockDate.prototype[fn] = function () {
    var d = new _Date(this.d.getTime() - this.calcTZO() * HOUR);
    d['setUTC' + fn.slice(3)].apply(d, arguments);
    this.fromLocal(d);
    return this.getTime();
  };
}
[
  'getUTCDate',
  'getUTCDay',
  'getUTCFullYear',
  'getUTCHours',
  'getUTCMilliseconds',
  'getUTCMinutes',
  'getUTCMonth',
  'getUTCSeconds',
  'getTime',
  'setTime',
  'setUTCDate',
  'setUTCFullYear',
  'setUTCHours',
  'setUTCMilliseconds',
  'setUTCMinutes',
  'setUTCMonth',
  'setUTCSeconds',
  'toGMTString',
  'toISOString',
  'toJSON',
  'toUTCString',
  'valueOf',
].forEach(passthrough);
[
  'getDate',
  'getDay',
  'getFullYear',
  'getHours',
  'getMilliseconds',
  'getMinutes',
  'getMonth',
  'getSeconds',
].forEach(localgetter);
[
  'setDate',
  'setFullYear',
  'setHours',
  'setMilliseconds',
  'setMinutes',
  'setMonth',
  'setSeconds',
].forEach(localsetter);

MockDate.prototype.getYear = function () {
  return this.getFullYear() - 1900;
};

MockDate.prototype.setYear = function (yr) {
  if (yr < 1900) {
    return this.setFullYear(1900 + yr);
  }
  return this.setFullYear(yr);
};

MockDate.parse = function (dateString) {
  return new MockDate(dateString).getTime();
}

MockDate.prototype.getTimezoneOffset = function () {
  return this.calcTZO() * 60;
};

MockDate.prototype.toString = MockDate.prototype.toLocaleString = function () {
  if (this instanceof _Date) {
    // someone, like util.inspect, calling Date.prototype.toString.call(foo)
    return _Date.prototype.toString.call(this);
  }
  return 'Mockday ' + this.d.toISOString() + ' GMT-0' + this.calcTZO() + '00 (MockDate)';
};

MockDate.now = _Date.now;

MockDate.UTC = _Date.UTC;

MockDate.prototype.toDateString = function () {
  return `${ weekDays[this.getDay()] } ${ months[this.getMonth()] } ${ this.getDate().toString().padStart(2, '0') } ${ this.getFullYear() }`;
};

// TODO:
// 'toDateString',
// 'toLocaleDateString',
// 'toLocaleTimeString',
// 'toTimeString',

function register(new_timezone, glob = global) {
  timezone = new_timezone || 'US/Pacific';
  glob.Date = MockDate;
}
exports.register = register;

function unregister(glob = global) {
  glob.Date = _Date;
}
exports.unregister = unregister;
<commit_msg>Update local date regex to accept more formats<commit_after>var assert = require('assert');
var tzdata = require('./lib/tzdata.js');
exports.tzdata = tzdata;

var _Date = Date;
exports._Date = _Date;

var timezone;

var weekDays = ['Sun', 'Mon','Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'Jun', 'Jul', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec'];

var HOUR = 60 * 60 * 1000;

var date_iso_8601_regex=/^\d\d\d\d(-\d\d(-\d\d(T\d\d\:\d\d\:\d\d(\.\d\d\d)?(Z|[+-]\d\d\:?\d\d))?)?)?$/;
var date_with_offset=/^\d\d\d\d-\d\d-\d\d \d\d\:\d\d\:\d\d(\.\d\d\d)? (Z|(\-|\+|)\d\d\:\d\d)$/;
var date_rfc_2822_regex=/^\d\d-\w\w\w-\d\d\d\d \d\d\:\d\d\:\d\d (\+|-)\d\d\d\d$/;
var local_date_regex=/^\d\d\d\d-\d\d-\d\d[T ]\d\d\:\d\d(\:\d\d(\.\d\d\d)?)?$/;

function MockDate(param) {
  if (arguments.length === 0) {
    this.d = new _Date();
  } else if (arguments.length === 1) {
    if (param instanceof MockDate) {
      this.d = new _Date(param.d);
    } else if (typeof param === 'string') {
      if (param.match(date_iso_8601_regex) || param.match(date_with_offset) || param.match(date_rfc_2822_regex) || param === '') {
        this.d = new _Date(param);
      } else if (param.match(local_date_regex)) {
        this.d = new _Date();
        this.fromLocal(new _Date(param.replace(' ', 'T') + 'Z'));
      } else {
        assert.ok(false, 'Unhandled date format passed to MockDate constructor: ' + param);
      }
    } else if (typeof param === 'number') {
      this.d = new _Date(param);
    } else if (typeof param === 'undefined') {
      this.d = new _Date();
    } else {
      assert.ok(false, 'Unhandled type passed to MockDate constructor: ' + typeof param);
    }
  } else {
    this.d = new _Date();
    this.fromLocal(new _Date(_Date.UTC.apply(null, arguments)));
  }
}

MockDate.prototype.calcTZO = function (ts) {
  var data = tzdata[timezone];
  assert.ok(data, 'Unsupported timezone: ' + timezone);
  ts = (ts || this.d.getTime()) / 1000;
  for (var ii = 2; ii < data.transitions.length; ii+=2) {
    if (data.transitions[ii] > ts) {
      return -data.transitions[ii-1];
    }
  }
  assert.ok(false, ts);
};

function passthrough(fn) {
  MockDate.prototype[fn] = function () {
    var real_date;
    if (this instanceof MockDate) {
      real_date = this.d;
    } else if (this instanceof _Date) {
      // console.log calls our prototype to format regular Date objects!
      // This should only be hit while debugging MockDate itself though, as
      // there should be no _Date objects in user code when using MockDate.
      real_date = this;
    } else {
      assert(false, 'Unexpected object type');
    }
    return real_date[fn].apply(real_date, arguments);
  };
}
function localgetter(fn) {
  MockDate.prototype[fn] = function () {
    var d = new _Date(this.d.getTime() - this.calcTZO() * HOUR);
    return d['getUTC' + fn.slice(3)]();
  };
}
MockDate.prototype.fromLocal = function(d) {
  // From a Date object in the fake-timezone where the returned UTC values are
  //   meant to be interpreted as local values.
  this.d.setTime(d.getTime() + this.calcTZO(d.getTime() + this.calcTZO(d.getTime()) * HOUR) * HOUR);
};
function localsetter(fn) {
  MockDate.prototype[fn] = function () {
    var d = new _Date(this.d.getTime() - this.calcTZO() * HOUR);
    d['setUTC' + fn.slice(3)].apply(d, arguments);
    this.fromLocal(d);
    return this.getTime();
  };
}
[
  'getUTCDate',
  'getUTCDay',
  'getUTCFullYear',
  'getUTCHours',
  'getUTCMilliseconds',
  'getUTCMinutes',
  'getUTCMonth',
  'getUTCSeconds',
  'getTime',
  'setTime',
  'setUTCDate',
  'setUTCFullYear',
  'setUTCHours',
  'setUTCMilliseconds',
  'setUTCMinutes',
  'setUTCMonth',
  'setUTCSeconds',
  'toGMTString',
  'toISOString',
  'toJSON',
  'toUTCString',
  'valueOf',
].forEach(passthrough);
[
  'getDate',
  'getDay',
  'getFullYear',
  'getHours',
  'getMilliseconds',
  'getMinutes',
  'getMonth',
  'getSeconds',
].forEach(localgetter);
[
  'setDate',
  'setFullYear',
  'setHours',
  'setMilliseconds',
  'setMinutes',
  'setMonth',
  'setSeconds',
].forEach(localsetter);

MockDate.prototype.getYear = function () {
  return this.getFullYear() - 1900;
};

MockDate.prototype.setYear = function (yr) {
  if (yr < 1900) {
    return this.setFullYear(1900 + yr);
  }
  return this.setFullYear(yr);
};

MockDate.parse = function (dateString) {
  return new MockDate(dateString).getTime();
}

MockDate.prototype.getTimezoneOffset = function () {
  return this.calcTZO() * 60;
};

MockDate.prototype.toString = MockDate.prototype.toLocaleString = function () {
  if (this instanceof _Date) {
    // someone, like util.inspect, calling Date.prototype.toString.call(foo)
    return _Date.prototype.toString.call(this);
  }
  return 'Mockday ' + this.d.toISOString() + ' GMT-0' + this.calcTZO() + '00 (MockDate)';
};

MockDate.now = _Date.now;

MockDate.UTC = _Date.UTC;

MockDate.prototype.toDateString = function () {
  return `${ weekDays[this.getDay()] } ${ months[this.getMonth()] } ${ this.getDate().toString().padStart(2, '0') } ${ this.getFullYear() }`;
};

// TODO:
// 'toDateString',
// 'toLocaleDateString',
// 'toLocaleTimeString',
// 'toTimeString',

function register(new_timezone, glob = global) {
  timezone = new_timezone || 'US/Pacific';
  glob.Date = MockDate;
}
exports.register = register;

function unregister(glob = global) {
  glob.Date = _Date;
}
exports.unregister = unregister;
<|endoftext|>


<commit_before>// buildstrap demo server.
var http = require('http'),
    consolidate = require('consolidate'),
    express = require('express'),
    cookieParser = require('cookie-parser'),
    swig = require('swig'),
    passport = require('passport'),
    BeatsMusicStrategy = require('passport-beatsmusic').Strategy,
    api = require('./lib/api'),
    beats = require('./lib/beats'),
    host = process.env.HOST || '127.0.0.1',
    port = Number(process.env.PORT || 3000),
    beatsClientId = process.env.BEATS_CLIENTID,
    beatsSecret = process.env.BEATS_SECRET,
    app = express(),
    server = http.createServer(app),
    io = require('socket.io').listen(server);

passport.use(new BeatsMusicStrategy({
  clientID: beatsClientId,
  clientSecret: beatsSecret,
  callbackURL: 'http://' + host + (port > 80 ? ':' + port : '') + '/auth/beatsmusic/callback'
}, function(accessToken, refreshToken, profile, done) {
  done(null, {
    accessToken: accessToken,
    refreshToken: refreshToken,
    profile: profile
  })
}));

passport.serializeUser(function(user, done) {
  done(null, user);
});

passport.deserializeUser(function(user, done) {
  done(null, user);
});

app.locals({
  templateMap: {
    'home': 'desktop/home.html',
    'signup': 'desktop/signup.html',
    'walkup': 'desktop/walkup.html',
    'rooms': 'desktop/rooms.html',
    'create': 'desktop/create.html'
  }
});

app.use(cookieParser());
app.use('/css', express.static(__dirname + '/build/css'));
app.use('/js', express.static(__dirname + '/build/js'));
app.use('/img', express.static(__dirname + '/src/img'));
app.use('/fonts', express.static(__dirname + '/src/fonts'));
app.use(express.favicon(__dirname + '/src/img/favicon.png'));

app.use(express.cookieParser());
app.use(express.session({ secret: 'secret' }));
app.use(passport.initialize());
app.use(passport.session());

app.engine('html', consolidate.swig);
app.set('view engine', 'html');
app.set('views', __dirname + '/build/html');
swig.setDefaults({ cache: false });

app.get('/user', function(req, res) {
  console.log(':: user ::', req.user)
  res.end(JSON.stringify(req.user));
})

app.get('/login', passport.authenticate('beatsmusic'));
// app.get('/auth/beatsmusic', passport.authenticate('beatsmusic'));

app.get('/auth/beatsmusic/callback', passport.authenticate('beatsmusic', {
  failureRedirect: '/login/failed'
}), function(req, res) {
  console.log('ON CALLBACK')
  // Successful authentication, redirect home.
  res.redirect('/');
});

app.get('/ajax/:action', function (req, res) {
  require('./controllers/ajax').call(app, req, res);
});

app.get('/test/:video', function (req, res) {
  require('./controllers/test').call(app, req, res);
});

app.get('/walkup', function (req, res) {
  require('./controllers/walkup').call(app, req, res);
});

app.get('/:route?', function (req, res) {
  require('./controllers/static').call(app, req, res);
});

server.listen(port);

console.log('Running walkup server on port ' + port);

io.sockets.on('connection', function (socket) {
  socket.emit('news', { hello: 'world' });
  socket.on('my other event', function (data) {
    console.log(data);
  });
});
<commit_msg>changing domain name<commit_after>// buildstrap demo server.
var http = require('http'),
    consolidate = require('consolidate'),
    express = require('express'),
    cookieParser = require('cookie-parser'),
    swig = require('swig'),
    passport = require('passport'),
    BeatsMusicStrategy = require('passport-beatsmusic').Strategy,
    api = require('./lib/api'),
    beats = require('./lib/beats'),
    host = process.env.HOST || 'www.spotilocal.com',
    port = Number(process.env.PORT || 3000),
    beatsClientId = process.env.BEATS_CLIENTID,
    beatsSecret = process.env.BEATS_SECRET,
    app = express(),
    server = http.createServer(app),
    io = require('socket.io').listen(server);

passport.use(new BeatsMusicStrategy({
  clientID: beatsClientId,
  clientSecret: beatsSecret,
  callbackURL: 'http://' + host + (port > 80 ? ':' + port : '') + '/auth/beatsmusic/callback'
}, function(accessToken, refreshToken, profile, done) {
  done(null, {
    accessToken: accessToken,
    refreshToken: refreshToken,
    profile: profile
  })
}));

passport.serializeUser(function(user, done) {
  done(null, user);
});

passport.deserializeUser(function(user, done) {
  done(null, user);
});

app.locals({
  templateMap: {
    'home': 'desktop/home.html',
    'signup': 'desktop/signup.html',
    'walkup': 'desktop/walkup.html',
    'rooms': 'desktop/rooms.html',
    'create': 'desktop/create.html'
  }
});

app.use(cookieParser());
app.use('/css', express.static(__dirname + '/build/css'));
app.use('/js', express.static(__dirname + '/build/js'));
app.use('/img', express.static(__dirname + '/src/img'));
app.use('/fonts', express.static(__dirname + '/src/fonts'));
app.use(express.favicon(__dirname + '/src/img/favicon.png'));

app.use(express.cookieParser());
app.use(express.session({ secret: 'secret' }));
app.use(passport.initialize());
app.use(passport.session());

app.engine('html', consolidate.swig);
app.set('view engine', 'html');
app.set('views', __dirname + '/build/html');
swig.setDefaults({ cache: false });

app.get('/user', function(req, res) {
  console.log(':: user ::', req.user)
  res.end(JSON.stringify(req.user));
})

app.get('/login', passport.authenticate('beatsmusic'));
// app.get('/auth/beatsmusic', passport.authenticate('beatsmusic'));

app.get('/auth/beatsmusic/callback', passport.authenticate('beatsmusic', {
  failureRedirect: '/login/failed'
}), function(req, res) {
  console.log('ON CALLBACK')
  // Successful authentication, redirect home.
  res.redirect('/');
});

app.get('/ajax/:action', function (req, res) {
  require('./controllers/ajax').call(app, req, res);
});

app.get('/test/:video', function (req, res) {
  require('./controllers/test').call(app, req, res);
});

app.get('/walkup', function (req, res) {
  require('./controllers/walkup').call(app, req, res);
});

app.get('/:route?', function (req, res) {
  require('./controllers/static').call(app, req, res);
});

server.listen(port);

console.log('Running walkup server on port ' + port);

io.sockets.on('connection', function (socket) {
  socket.emit('news', { hello: 'world' });
  socket.on('my other event', function (data) {
    console.log(data);
  });
});
<|endoftext|>


<commit_before>module.exports = Synopsis;

var assert = require('assert');
var async = require('async');

var EventEmitter = require('events').EventEmitter;

var inherits = require('util').inherits;

var noop = function() {};

inherits(Synopsis, EventEmitter);

function Synopsis(options) {
  if (!(this instanceof Synopsis)) {
    return new Synopsis(options);
  }

  var self = this;

  EventEmitter.call(this);

  assert(typeof options === 'object');

  var granularity = options.granularity || 5;

  var count = 0;

  var deltaCache = this.deltaCache = {};
  var differ = options.differ;
  var patcher = options.patcher;

  var store = options.store || (function() {
    var cache = [];
    return {
      get: function(key, cb) {
        return cb(null, cache[key]);
      },
      set: function(key, value, cb) {
        cache[key] = value;
        cb();
      }
    };
  })();

  function sum(index, cb) {
    if (typeof cb === 'undefined') {
      cb = index;
      index = count;
    }

    if (typeof index === 'undefined') {
      index = count;
    }

    if (index === 0) {
      return cb(null, options.start);
    }

    delta(0, index, function(err, d) {
      if (err) return cb(err);

      cb(null, patcher(options.start, d));
    });
  }

  function patch(delta, cb) {
    cb = cb || noop;

    sum(function(err, s) {
      try {
        patcher(s, delta);

        store.set(++ count + '-1', delta, function(err) {
          if (err) return cb(err);

          // TODO: make these two set operations atomic
          store.set('count', count, function(err) {
            if (err) return cb(err);

            updateAggregates(function(err) {
              if (err) return cb(err);

              cb();
            });
          });
        });
      } catch(e) {
        //invalid patch
        return cb(new Error('Invalid Patch'));
      }
    });
  }

  function updateAggregates(cb) {
    var scale = granularity;

    async.whilst(function() {
      return scale <= count && count % scale === 0;
    }, function(next) {
      async.parallel({
        before: function(cb) {
          return sum(count - scale, cb);
        },
        after: function(cb) {
          return sum(count, cb);
        }
      }, function(err, sums) {
        store.set(count + '-' + scale, differ(sums.before, sums.after), function(err) {
          scale *= granularity;
          next();
        });
      });
    }, function(err) {
      cb();
    });
  }

  function collectDeltas(idx1, idx2, cb) {
    var result = [];

    if (idx2 > count) return cb(new Error('index out of range: ' + idx2));
    if (idx1 > idx2) return cb(new Error('delta in incorrect order'));

    if (idx1 === idx2) return cb(null, []);

    var idx = idx2;

    async.whilst(function() {
      return idx > idx1;
    }, function(next) {
      if (idx === 0) {
        idx --;
        return next();
      } else if (idx % granularity !== 0) {
        store.get(idx -- + '-1', function(err, delta) {
          result.push(delta);
          return next();
        });
        return;
      }

      var deltaSize = idx2 - idx1;
      var deltaScale = Math.pow(granularity, Math.floor(Math.log(deltaSize)/Math.log(granularity)));

      var cached;

      async.doWhilst(function(next) {
        if (idx % deltaScale === 0) {
          store.get(idx + '-' + deltaScale, function(err, c) {
            if (c) {
              cached = c;
            } else {
              deltaScale /= granularity;
            }
            next();
          });
        } else {
          deltaScale /= granularity;
          next();
        }
      }, function() {
        return !cached && deltaScale > 1;
      }, function(err) {
        if (err) return next(err);
        if (cached) {
          result.push(cached);
          idx -= deltaScale;
          next();
        } else {
          store.get(idx -- + '-1', function(err, delta) {
            result.push(delta);
            next();
          });
        }
      });
    }, function(err) {
      cb(err, result.reverse());
    });
  }

  function delta(idx1, idx2, cb) {
    if (typeof cb === 'undefined') {
      cb = idx2;
      idx2 = count;
    }

    collectDeltas(idx1, idx2, function(err, deltas) {
      if (err) return cb(err);

      sum(idx1, function(err, start) {
        if (err) return cb(err);

        var result = start;

        deltas.forEach(function(delta) {
          result = patcher(result, delta);
        });

        cb(null, differ(start, result));
      });
    });
  }

  function rollup(from, cb) {
    var c = count;
    var patch = delta(from, c, function(err, delta) {
      cb(null, {
        patch: delta,
        end: c
      });
    });
  }

  store.get('count', function(err, c) {
    count = c || 0;
    self.emit('ready');
  });

  this.sum = sum;
  this.delta = delta;
  this.patch = patch;
  this.collectDeltas = collectDeltas;
  this.rollup = rollup;
}
<commit_msg>adding guard against adding invalid patches<commit_after>module.exports = Synopsis;

var assert = require('assert');
var async = require('async');

var EventEmitter = require('events').EventEmitter;

var inherits = require('util').inherits;

var noop = function() {};

inherits(Synopsis, EventEmitter);

function Synopsis(options) {
  if (!(this instanceof Synopsis)) {
    return new Synopsis(options);
  }

  var self = this;

  EventEmitter.call(this);

  assert(typeof options === 'object');

  var granularity = options.granularity || 5;

  var count = 0;

  var deltaCache = this.deltaCache = {};
  var differ = options.differ;
  var patcher = options.patcher;

  var store = options.store || (function() {
    var cache = [];
    return {
      get: function(key, cb) {
        return cb(null, cache[key]);
      },
      set: function(key, value, cb) {
        cache[key] = value;
        cb();
      }
    };
  })();

  function sum(index, cb) {
    if (typeof cb === 'undefined') {
      cb = index;
      index = count;
    }

    if (typeof index === 'undefined') {
      index = count;
    }

    if (index === 0) {
      return cb(null, options.start);
    }

    delta(0, index, function(err, d) {
      if (err) return cb(err);

      cb(null, patcher(options.start, d));
    });
  }

  function patch(delta, cb) {
    cb = cb || noop;

    testNewPatch(delta, function(err) {
      if (err) return cb(err);

      // TODO: make these two set operations atomic
      store.set(++ count + '-1', delta, function(err) {
        if (err) return cb(err);

        store.set('count', count, function(err) {
          if (err) return cb(err);

          updateAggregates(cb);
        });
      });
    });
  }

  function testNewPatch(patch, cb) {
    sum(function(err, s) {
      if (err) return cb(err);
      try {
        patcher(s, delta);
        cb();
      } catch(e) {
        return cb(new Error('Invalid Patch'));
      }
    });
  }

  function updateAggregates(cb) {
    var scale = granularity;

    async.whilst(function() {
      return scale <= count && count % scale === 0;
    }, function(next) {
      async.parallel({
        before: function(cb) {
          return sum(count - scale, cb);
        },
        after: function(cb) {
          return sum(count, cb);
        }
      }, function(err, sums) {
        store.set(count + '-' + scale, differ(sums.before, sums.after), function(err) {
          scale *= granularity;
          next();
        });
      });
    }, function(err) {
      cb();
    });
  }

  function collectDeltas(idx1, idx2, cb) {
    var result = [];

    if (idx2 > count) return cb(new Error('index out of range: ' + idx2));
    if (idx1 > idx2) return cb(new Error('delta in incorrect order'));

    if (idx1 === idx2) return cb(null, []);

    var idx = idx2;

    async.whilst(function() {
      return idx > idx1;
    }, function(next) {
      if (idx === 0) {
        idx --;
        return next();
      } else if (idx % granularity !== 0) {
        store.get(idx -- + '-1', function(err, delta) {
          result.push(delta);
          return next();
        });
        return;
      }

      var deltaSize = idx2 - idx1;
      var deltaScale = Math.pow(granularity, Math.floor(Math.log(deltaSize)/Math.log(granularity)));

      var cached;

      async.doWhilst(function(next) {
        if (idx % deltaScale === 0) {
          store.get(idx + '-' + deltaScale, function(err, c) {
            if (c) {
              cached = c;
            } else {
              deltaScale /= granularity;
            }
            next();
          });
        } else {
          deltaScale /= granularity;
          next();
        }
      }, function() {
        return !cached && deltaScale > 1;
      }, function(err) {
        if (err) return next(err);
        if (cached) {
          result.push(cached);
          idx -= deltaScale;
          next();
        } else {
          store.get(idx -- + '-1', function(err, delta) {
            result.push(delta);
            next();
          });
        }
      });
    }, function(err) {
      cb(err, result.reverse());
    });
  }

  function delta(idx1, idx2, cb) {
    if (typeof cb === 'undefined') {
      cb = idx2;
      idx2 = count;
    }

    collectDeltas(idx1, idx2, function(err, deltas) {
      if (err) return cb(err);

      sum(idx1, function(err, start) {
        if (err) return cb(err);

        var result = start;

        deltas.forEach(function(delta) {
          result = patcher(result, delta);
        });

        cb(null, differ(start, result));
      });
    });
  }

  function rollup(from, cb) {
    var c = count;
    var patch = delta(from, c, function(err, delta) {
      cb(null, {
        patch: delta,
        end: c
      });
    });
  }

  store.get('count', function(err, c) {
    count = c || 0;
    self.emit('ready');
  });

  this.sum = sum;
  this.delta = delta;
  this.patch = patch;
  this.collectDeltas = collectDeltas;
  this.rollup = rollup;
}
<|endoftext|>