<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var assert = require('assert');
var inherits = require('util').inherits;
var EventEmitter = require('tchannel/lib/event_emitter.js');

// TODO: track and report run stats
// - elapsed
// - lag
// - collection size at start
// - per-item elapsed

function IntervalScan(options) {
    assert(typeof options.name === 'string',
           'must have a name string');
    assert(typeof options.each === 'function',
           'each must be a function');
    assert(typeof options.getCollection === 'function',
           'getCollection must be a function');
    assert(options.timers,
           'must have timers');

    var self = this;
    EventEmitter.call(self);

    self.runBeginEvent = self.defineEvent('runBegin');
    self.runEndEvent = self.defineEvent('runEnd');

    self.name = options.name;
    self.interval = options.interval;
    self.each = options.each;
    self.getCollection = options.getCollection;
    self.timers = options.timers;

    self.timer = null;
    self.theRun = null;

    self.boundRun = run;
    function run() {
        self.run();
    }
}

inherits(IntervalScan, EventEmitter);

IntervalScan.prototype.setInterval =
function setInterval(interval) {
    var self = this;

    if (self.interval === interval) {
        return;
    }
    self.interval = interval;
    if (self.timer) {
        self.clearTimer();
        self.setTimer();
    }
};

IntervalScan.prototype.setTimer =
function setTimer() {
    var self = this;

    if (self.timer || self.theRun || self.interval <= 0) {
        return;
    }

    self.timer = self.timers.setTimeout(self.boundRun, self.interval);
};

IntervalScan.prototype.start =
function start() {
    var self = this;

    self.setTimer();
};

IntervalScan.prototype.stop =
function stop() {
    var self = this;

    self.clearTimer();
    if (self.theRun) {
        self.theRun.clearImmediate();
        self.theRun = null;
    }
};

IntervalScan.prototype.clearTimer =
function clearTimer() {
    var self = this;

    if (self.timer) {
        self.timers.clearTimeout(self.timer);
        self.timer = null;
    }
};

IntervalScan.prototype.run =
function run(callback) {
    var self = this;

    if (self.theRun) {
        if (callback) {
            callback(new Error('already running'));
        }
        return;
    }

    self.clearTimer();

    self.theRun = new IntervalScanRun(self, runDone);

    function runDone() {
        self.theRun = null;
        self.setTimer();
        if (callback) {
            callback();
        }
    }
};

function IntervalScanRun(scan, callback) {
    var self = this;

    self.scan = scan;
    self.immediate = null;
    self.keyIndex = 0;
    self.start = null;
    self.end = null;
    self.collection = null;
    self.keys = null;
    self.callback = callback;

    self.immediate = self.scan.timers.setImmediate(startRun);

    function startRun() {
        self.start = self.scan.timers.now();
        self.collection = self.scan.getCollection();
        self.keys = Object.keys(self.collection);
        self.scan.runBeginEvent.emit(self.scan, self);
        self.nextItem();
    }

    self.boundDeferNextItem = deferNextItem;
    function deferNextItem() {
        self.keyIndex++;
        self.nextItem();
    }
}

IntervalScanRun.prototype.nextItem =
function nextItem() {
    var self = this;

    if (self.keyIndex < self.keys.length) {
        var key = self.keys[self.keyIndex];
        var val = self.collection[key];
        if (val !== undefined) {
            self.scan.each(key, val);
        }
        self.immediate = self.scan.timers.setImmediate(self.boundDeferNextItem);
    } else {
        self.finish();
    }
};

IntervalScanRun.prototype.finish =
function finish() {
    var self = this;

    if (self.end === null) {
        self.end = self.scan.timers.now();
        self.scan.runEndEvent.emit(self.scan, self);
    }

    if (self.callback) {
        self.callback();
        self.callback = null;
    }
};

IntervalScanRun.prototype.clearImmediate =
function clearImmediate() {
    var self = this;

    if (self.immediate) {
        self.scan.timers.clearImmediate(self.immediate);
        self.immediate = null;
    }
};

IntervalScan.Run = IntervalScanRun;
module.exports = IntervalScan;
<commit_msg>lib/interval_scan: ensure we setTimer if not set<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var assert = require('assert');
var inherits = require('util').inherits;
var EventEmitter = require('tchannel/lib/event_emitter.js');

// TODO: track and report run stats
// - elapsed
// - lag
// - collection size at start
// - per-item elapsed

function IntervalScan(options) {
    assert(typeof options.name === 'string',
           'must have a name string');
    assert(typeof options.each === 'function',
           'each must be a function');
    assert(typeof options.getCollection === 'function',
           'getCollection must be a function');
    assert(options.timers,
           'must have timers');

    var self = this;
    EventEmitter.call(self);

    self.runBeginEvent = self.defineEvent('runBegin');
    self.runEndEvent = self.defineEvent('runEnd');

    self.name = options.name;
    self.interval = options.interval;
    self.each = options.each;
    self.getCollection = options.getCollection;
    self.timers = options.timers;

    self.timer = null;
    self.theRun = null;

    self.boundRun = run;
    function run() {
        self.run();
    }
}

inherits(IntervalScan, EventEmitter);

IntervalScan.prototype.setInterval =
function setInterval(interval) {
    var self = this;

    if (self.interval === interval) {
        if (!self.timer) {
            self.setTimer();
        }
        return;
    }
    self.interval = interval;
    if (self.timer) {
        self.clearTimer();
        self.setTimer();
    }
};

IntervalScan.prototype.setTimer =
function setTimer() {
    var self = this;

    if (self.timer || self.theRun || self.interval <= 0) {
        return;
    }

    self.timer = self.timers.setTimeout(self.boundRun, self.interval);
};

IntervalScan.prototype.start =
function start() {
    var self = this;

    self.setTimer();
};

IntervalScan.prototype.stop =
function stop() {
    var self = this;

    self.clearTimer();
    if (self.theRun) {
        self.theRun.clearImmediate();
        self.theRun = null;
    }
};

IntervalScan.prototype.clearTimer =
function clearTimer() {
    var self = this;

    if (self.timer) {
        self.timers.clearTimeout(self.timer);
        self.timer = null;
    }
};

IntervalScan.prototype.run =
function run(callback) {
    var self = this;

    if (self.theRun) {
        if (callback) {
            callback(new Error('already running'));
        }
        return;
    }

    self.clearTimer();

    self.theRun = new IntervalScanRun(self, runDone);

    function runDone() {
        self.theRun = null;
        self.setTimer();
        if (callback) {
            callback();
        }
    }
};

function IntervalScanRun(scan, callback) {
    var self = this;

    self.scan = scan;
    self.immediate = null;
    self.keyIndex = 0;
    self.start = null;
    self.end = null;
    self.collection = null;
    self.keys = null;
    self.callback = callback;

    self.immediate = self.scan.timers.setImmediate(startRun);

    function startRun() {
        self.start = self.scan.timers.now();
        self.collection = self.scan.getCollection();
        self.keys = Object.keys(self.collection);
        self.scan.runBeginEvent.emit(self.scan, self);
        self.nextItem();
    }

    self.boundDeferNextItem = deferNextItem;
    function deferNextItem() {
        self.keyIndex++;
        self.nextItem();
    }
}

IntervalScanRun.prototype.nextItem =
function nextItem() {
    var self = this;

    if (self.keyIndex < self.keys.length) {
        var key = self.keys[self.keyIndex];
        var val = self.collection[key];
        if (val !== undefined) {
            self.scan.each(key, val);
        }
        self.immediate = self.scan.timers.setImmediate(self.boundDeferNextItem);
    } else {
        self.finish();
    }
};

IntervalScanRun.prototype.finish =
function finish() {
    var self = this;

    if (self.end === null) {
        self.end = self.scan.timers.now();
        self.scan.runEndEvent.emit(self.scan, self);
    }

    if (self.callback) {
        self.callback();
        self.callback = null;
    }
};

IntervalScanRun.prototype.clearImmediate =
function clearImmediate() {
    var self = this;

    if (self.immediate) {
        self.scan.timers.clearImmediate(self.immediate);
        self.immediate = null;
    }
};

IntervalScan.Run = IntervalScanRun;
module.exports = IntervalScan;
<|endoftext|>


<commit_before>function visit() {
  document.getElementById('web').src = 'https://' + document.getElementById('address').value;
  document.getElementById('address').value = document.getElementById('web').src;
}
<commit_msg>Update iF.js<commit_after>var webId;

function visit() {
  webId = document.getElementById('address').value;
  webId = string.split('https://');
  webId = string.split('http://');
  webId.filter[Boolean];
  document.getElementById('web').src = 'https://' + webId[0];
  document.getElementById('address').value = document.getElementById('web').src;
}

<|endoftext|>


<commit_before>// auto-suggest docs:
// http://code.drewwilson.com/entry/autosuggest-jquery-plugin
// Changes to previous
// - prefill and ashtmlid in data-auto-suggest-config
define([
    "jquery",
    "../core/parser",
    "../registry",
    "jquery_autosuggest",
    "jquery_form"
], function($, Parser, registry) {
    var parser = new Parser("autosuggest");
    parser.add_argument("words", "");
    parser.add_argument("pre-fill");
    parser.add_argument("as-html-id");
    parser.add_argument("selected-value-prop", "name");
    parser.add_argument("search-obj-prop", "name");

    var _ = {
        name: "autosuggest",
        trigger: "input.pat-autosuggest",
        init: function($el, opts) {
            if ($el.length > 1)
                return $el.each(function() { _.init($(this), opts); });

            var cfg = _.parser.parse($el, opts);

            if ($el.attr("readonly"))
                cfg.startText = "";
            else
                cfg.startText = $el.attr("placeholder") || "Enter text";

            // jquery_autosuggest does not like the placeholder attr (yet)
            $el.attr("placeholder", "")

            if (cfg.preFill && (cfg.preFill.slice(0,1) === ","))
                cfg.preFill = cfg.preFill.slice(1);

            $el.on("keydown.pat-autosuggest", _.onKeyDown);

            var data = cfg.words.split(/\s*,\s*/).map(function(word) {
                return {value: word, name: word};
            });

            cfg.selectionAdded = function() {
                $el.next().trigger("change");
            };
            cfg.selectionRemoved = function(elem) {
                elem.remove();
                $el.next().trigger("change");
            };

            $el.on("change.pat-autosuggest", false);

            // XXX: See https://github.com/Patternslib/Patterns/issues/149
            if (cfg.asHtmlId !== undefined) {
                cfg.asHtmlID = cfg.asHtmlId;
            }
            $el.autoSuggest(data, cfg);

            return $el;
        },
        destroy: function($el) {
            $el.off(".pat-autosuggest");

            // XXX: destroy the jqueryPlugin, unfortunately it doesn't
            // support this as of now
        },

        parser: parser,

        onKeyDown: function(ev) {
            var $this = $(this);
            if (ev.which === 13) {
                var $results = $this.parents(".as-selections").next();
                ev.preventDefault();
                // skip ENTER->comma translation, if selection is active
                if (($results.is(":visible")) &&
                    ($results.find(".active").length > 0)) return;
                var newev = $.Event("keydown");
                newev.ctrlKey = false;
                newev.which = 188;
                newev.keyCode = 188;
                $this.trigger(newev);
            }
        }
    };
    registry.register(_);
    return _;
});

// jshint indent: 4, browser: true, jquery: true, quotmark: double
// vim: sw=4 expandtab
<commit_msg>Fix lint in autosuggest.js<commit_after>// auto-suggest docs:
// http://code.drewwilson.com/entry/autosuggest-jquery-plugin
// Changes to previous
// - prefill and ashtmlid in data-auto-suggest-config
define([
    "jquery",
    "../core/parser",
    "../registry",
    "jquery_autosuggest",
    "jquery_form"
], function($, Parser, registry) {
    var parser = new Parser("autosuggest");
    parser.add_argument("words", "");
    parser.add_argument("pre-fill");
    parser.add_argument("as-html-id");
    parser.add_argument("selected-value-prop", "name");
    parser.add_argument("search-obj-prop", "name");

    var _ = {
        name: "autosuggest",
        trigger: "input.pat-autosuggest",
        init: function($el, opts) {
            if ($el.length > 1)
                return $el.each(function() { _.init($(this), opts); });

            var cfg = _.parser.parse($el, opts);

            if ($el.attr("readonly"))
                cfg.startText = "";
            else
                cfg.startText = $el.attr("placeholder") || "Enter text";

            // jquery_autosuggest does not like the placeholder attr (yet)
            $el.attr("placeholder", "");

            if (cfg.preFill && (cfg.preFill.slice(0,1) === ","))
                cfg.preFill = cfg.preFill.slice(1);

            $el.on("keydown.pat-autosuggest", _.onKeyDown);

            var data = cfg.words.split(/\s*,\s*/).map(function(word) {
                return {value: word, name: word};
            });

            cfg.selectionAdded = function() {
                $el.next().trigger("change");
            };
            cfg.selectionRemoved = function(elem) {
                elem.remove();
                $el.next().trigger("change");
            };

            $el.on("change.pat-autosuggest", false);

            // XXX: See https://github.com/Patternslib/Patterns/issues/149
            if (cfg.asHtmlId !== undefined) {
                cfg.asHtmlID = cfg.asHtmlId;
            }
            $el.autoSuggest(data, cfg);

            return $el;
        },
        destroy: function($el) {
            $el.off(".pat-autosuggest");

            // XXX: destroy the jqueryPlugin, unfortunately it doesn't
            // support this as of now
        },

        parser: parser,

        onKeyDown: function(ev) {
            var $this = $(this);
            if (ev.which === 13) {
                var $results = $this.parents(".as-selections").next();
                ev.preventDefault();
                // skip ENTER->comma translation, if selection is active
                if (($results.is(":visible")) &&
                    ($results.find(".active").length > 0)) return;
                var newev = $.Event("keydown");
                newev.ctrlKey = false;
                newev.which = 188;
                newev.keyCode = 188;
                $this.trigger(newev);
            }
        }
    };
    registry.register(_);
    return _;
});

// jshint indent: 4, browser: true, jquery: true, quotmark: double
// vim: sw=4 expandtab
<|endoftext|>


<commit_before>/*jshint forin:false, plusplus:false, sub:true */
define([
    'zepto',
    'datastore',
    'jed',
    'collections/episodes',
    'collections/podcasts',
    'models/episode',
    'models/podcast',
    'routers/app'
], function($, DataStore, Jed, Episodes, Podcasts, Episode, Podcast, AppRouter) {
    'use strict';

    // Globals used throughout the app, accessible via window.GLOBALS.
    var GLOBALS = {
        DATABASE_NAME: 'podcasts',
        HAS: {
            audioSupportMP3: (function() {
                var a = window.document.createElement('audio');
                return !!(a.canPlayType && a.canPlayType('audio/mpeg;').replace(/no/, ''));
            })(),
            audioSupportOGG: (function() {
                var a = window.document.createElement('audio');
                return !!(a.canPlayType && a.canPlayType('audio/ogg;').replace(/no/, ''));
            })(),
            nativeScroll: (function() {
                return 'WebkitOverflowScrolling' in window.document.createElement('div').style;
            })()
        },
        LANGUAGE: 'fr' || window.navigator.language, // HACK: Better way for this, I assume?
        LOWER_UI_ACTIVE: true,
        MAX_DOWNLOADS: 2, // Maximum number of podcast downloads at one time.
        OBJECT_STORE_NAME: 'podcasts',
        TIME_TO_UPDATE: 3600 * 5 // Update podcasts every five hours
    };
    window.GLOBALS = GLOBALS;

    // Called by main.js to kick off the app loading. We make sure IndexedDB is
    // available, load up our locale files, then actually start loading in
    // views.
    function initialize(loadAppCallback) {
        if (GLOBALS.HAS.nativeScroll) {
            $('body').addClass('native-scroll');
        }

        DataStore.load(function() {
            setLanguage(function() {
                // Load the router; we're off to the races!
                var router = new AppRouter();
                window.router = router;

                Backbone.history.start();
            });
        });
    }

    // Format a time in seconds to a pretty 5:22:75 style time. Cribbed from
    // the Gaia Music app.
    function formatTime(secs) {
        if (isNaN(secs)) {
            return '--:--';
        }

        var hours = parseInt(secs / 3600, 10) % 24;
        var minutes = parseInt(secs / 60, 10) % 60;
        var seconds = parseInt(secs % 60, 10);

        return '{hours}{minutes}:{seconds}'.format({
            hours: hours !== 0 ? hours + ':' : '',
            minutes: minutes < 10 ? '0' + minutes : minutes,
            seconds: seconds < 10 ? '0' + seconds : seconds
        });
    }
    window.formatTime = formatTime;

    // Return gettext-style strings as they were supplied. An easy way to mock
    // out gettext calls, in case no locale data is available.
    function mockL10n() {
        window._l10n = null;
        window.l = function(key) {
            return key;
        }
    }

    // Set the language of the app and retrieve the proper localization files.
    // This could be improved, but for now works fine.
    function setLanguage(callback, override) {
        var request = new window.XMLHttpRequest();

        request.open('GET', 'locale/{lang}.json'.format({
            lang: override || GLOBALS.LANGUAGE
        }), true);

        request.addEventListener('load', function(event) {
            if (request.status === 200) {
                // Alias _ for gettext-style l10n jazz.
                var l10n = new Jed({
                    locale_data: JSON.parse(request.response)
                });

                // TODO: This seems a bit hacky; maybe we can do better?
                window._l10n = l10n;
                window.l = function(key) {
                    return l10n.gettext(key);
                };

                // HACK: This should be automated with a data attribute for
                // extensibility, but for now this is fine.
                // Set the title tag of the page (it's the only thing we don't
                // load in with JS templating).
                $('title').text(window.l($('title').text()));
            } else {
                mockL10n();
            }

            if (callback) {
                callback();
            }
        });

        try {
            request.send();
        } catch (e) {
            console.log(e);
            mockL10n();
        }
    }

    // Return a timestamp from a JavaScript Date object. If no argument is
    // supplied, return the timestamp for "right now".
    function timestamp(date) {
        if (!date) {
            date = new Date();
        }

        return Math.round(date.getTime() / 1000);
    }
    window.timestamp = timestamp;

    // Toggle lower UI elements like the "now playing" section and tabs
    // when keyboard is activated.
    function toggleLowerUI() {
        var $lowerUI = $('#player,#tabs');

        if (window.GLOBALS.LOWER_UI_ACTIVE) {
            window.GLOBALS.LOWER_UI_ACTIVE = false;
            $lowerUI.addClass('hide');
        } else {
            window.GLOBALS.LOWER_UI_ACTIVE = true;
            $lowerUI.removeClass('hide');
        }
    }
    window.toggleLowerUI = toggleLowerUI;

    return {
        initialize: initialize
    };
});
<commit_msg>Add missing semicolon<commit_after>/*jshint forin:false, plusplus:false, sub:true */
define([
    'zepto',
    'datastore',
    'jed',
    'collections/episodes',
    'collections/podcasts',
    'models/episode',
    'models/podcast',
    'routers/app'
], function($, DataStore, Jed, Episodes, Podcasts, Episode, Podcast, AppRouter) {
    'use strict';

    // Globals used throughout the app, accessible via window.GLOBALS.
    var GLOBALS = {
        DATABASE_NAME: 'podcasts',
        HAS: {
            audioSupportMP3: (function() {
                var a = window.document.createElement('audio');
                return !!(a.canPlayType && a.canPlayType('audio/mpeg;').replace(/no/, ''));
            })(),
            audioSupportOGG: (function() {
                var a = window.document.createElement('audio');
                return !!(a.canPlayType && a.canPlayType('audio/ogg;').replace(/no/, ''));
            })(),
            nativeScroll: (function() {
                return 'WebkitOverflowScrolling' in window.document.createElement('div').style;
            })()
        },
        LANGUAGE: 'fr' || window.navigator.language, // HACK: Better way for this, I assume?
        LOWER_UI_ACTIVE: true,
        MAX_DOWNLOADS: 2, // Maximum number of podcast downloads at one time.
        OBJECT_STORE_NAME: 'podcasts',
        TIME_TO_UPDATE: 3600 * 5 // Update podcasts every five hours
    };
    window.GLOBALS = GLOBALS;

    // Called by main.js to kick off the app loading. We make sure IndexedDB is
    // available, load up our locale files, then actually start loading in
    // views.
    function initialize(loadAppCallback) {
        if (GLOBALS.HAS.nativeScroll) {
            $('body').addClass('native-scroll');
        }

        DataStore.load(function() {
            setLanguage(function() {
                // Load the router; we're off to the races!
                var router = new AppRouter();
                window.router = router;

                Backbone.history.start();
            });
        });
    }

    // Format a time in seconds to a pretty 5:22:75 style time. Cribbed from
    // the Gaia Music app.
    function formatTime(secs) {
        if (isNaN(secs)) {
            return '--:--';
        }

        var hours = parseInt(secs / 3600, 10) % 24;
        var minutes = parseInt(secs / 60, 10) % 60;
        var seconds = parseInt(secs % 60, 10);

        return '{hours}{minutes}:{seconds}'.format({
            hours: hours !== 0 ? hours + ':' : '',
            minutes: minutes < 10 ? '0' + minutes : minutes,
            seconds: seconds < 10 ? '0' + seconds : seconds
        });
    }
    window.formatTime = formatTime;

    // Return gettext-style strings as they were supplied. An easy way to mock
    // out gettext calls, in case no locale data is available.
    function mockL10n() {
        window._l10n = null;
        window.l = function(key) {
            return key;
        };
    }

    // Set the language of the app and retrieve the proper localization files.
    // This could be improved, but for now works fine.
    function setLanguage(callback, override) {
        var request = new window.XMLHttpRequest();

        request.open('GET', 'locale/{lang}.json'.format({
            lang: override || GLOBALS.LANGUAGE
        }), true);

        request.addEventListener('load', function(event) {
            if (request.status === 200) {
                // Alias _ for gettext-style l10n jazz.
                var l10n = new Jed({
                    locale_data: JSON.parse(request.response)
                });

                // TODO: This seems a bit hacky; maybe we can do better?
                window._l10n = l10n;
                window.l = function(key) {
                    return l10n.gettext(key);
                };

                // HACK: This should be automated with a data attribute for
                // extensibility, but for now this is fine.
                // Set the title tag of the page (it's the only thing we don't
                // load in with JS templating).
                $('title').text(window.l($('title').text()));
            } else {
                mockL10n();
            }

            if (callback) {
                callback();
            }
        });

        try {
            request.send();
        } catch (e) {
            console.log(e);
            mockL10n();
        }
    }

    // Return a timestamp from a JavaScript Date object. If no argument is
    // supplied, return the timestamp for "right now".
    function timestamp(date) {
        if (!date) {
            date = new Date();
        }

        return Math.round(date.getTime() / 1000);
    }
    window.timestamp = timestamp;

    // Toggle lower UI elements like the "now playing" section and tabs
    // when keyboard is activated.
    function toggleLowerUI() {
        var $lowerUI = $('#player,#tabs');

        if (window.GLOBALS.LOWER_UI_ACTIVE) {
            window.GLOBALS.LOWER_UI_ACTIVE = false;
            $lowerUI.addClass('hide');
        } else {
            window.GLOBALS.LOWER_UI_ACTIVE = true;
            $lowerUI.removeClass('hide');
        }
    }
    window.toggleLowerUI = toggleLowerUI;

    return {
        initialize: initialize
    };
});
<|endoftext|>


<commit_before>var Task = require('./task').Task,
    IonicStats = require('./stats').IonicStats,
    fs = require('fs'),
    Q = require('q'),
    argv = require('optimist').boolean(['nohooks', 'n', 'r', 'noresources', 'nosave', 'e']).argv,
    path = require('path'),
    exec = require('child_process').exec,
    colors = require('colors'),
    shelljs = require('shelljs'),
    generate = require('./resources/generate'),
    settings = require('./resources/settings'),
    Hooks = require('./hooks'),
    State = require('./state');

var IonicTask = function() {};

IonicTask.prototype = new Task();

IonicTask.prototype.run = function(ionic) {
  this.ionic = ionic;
  var self = this;
  var cmdName = process.argv[2].toLowerCase();
  var q;

  this.isLiveReload = ((cmdName == 'run' || cmdName == 'emulate') && (argv.livereload || argv['live-reload'] || argv.l));

  this.addIcons = !(argv.noresources || argv.r);

  if(this.isLiveReload) {
    q = self.setupLiveReload();

  } else {
    // ensure the content node was set back to its original
    q = self.ionic.setConfigXml({
      resetContent: true,
      errorWhenNotFound: false
    });
  }

  var addDefaultResources = false;
  var isPlatformCmd = argv._.indexOf('platform') != -1;
  var isAddCmd = argv._.indexOf('add') != -1;
  var isPluginCmd = argv._.indexOf('plugin') != -1;
  var isRmCmd = argv._.indexOf('rm') != -1 || argv._.indexOf('remove') != -1;

  if(isPlatformCmd && isAddCmd) {
    addDefaultResources = true;
  }
  // console.log('Icons: ', addDefaultResources, 'Add icons:', this.addIcons)

  q.then(function(){
    if(addDefaultResources && self.addIcons) {
      return generate.copyIconFilesIntoResources()
      .then(function() {
        return generate.addIonicIcons(argv._[2]);
      })
    } else {
      return false;
    }
  })
  .then(function() {
    return self.runCordova(cmdName);
  })
  .then(function(runCode) {
    //We dont want to do anything if the cordova command failed
    if(runCode !== 0 || argv.nosave) {
      return
    }
    if (isPlatformCmd && isAddCmd) {
      addDefaultResources = true;
      console.log('Saving platform to package.json file'.blue)
      return State.savePlatform(argv);
    } else if (isPlatformCmd && isRmCmd) {
      console.log('Removing platform from package.json file'.blue)
      return State.removePlatform(argv);
    } else if (isPluginCmd && isAddCmd) {
      console.log('Saving plugin to package.json file'.blue)
      return State.savePlugin(argv);
    } else if (isPluginCmd && isRmCmd) {
      console.log('Removing plugin from package.json file'.blue)
      return State.removePlugin(argv);
    }
  })
}

IonicTask.prototype.runCordova = function(cmdName) {
  var deferred = Q.defer();
  var self = this;
  var cmdArgs = (process.argv.length > 3 ? process.argv.slice(3) : []);
  var cmdArg, x, y;

  // backwards compatibility prior to fully wrapping cordova cmds
  if(cmdName == 'platform') {
    // `ionic platform <PLATFORM>` used to actually run `ionic platform add <PLATFORM>`
    // if a cordova platform cmd isn't the cmd then automatically insert `add`
    var hasCordovaCmd = false;
    var validCommands = 'add remove rm list ls update up check'.split(' ');
    for(x=0; x<cmdArgs.length; x++) {
      cmdArg = cmdArgs[x].toLowerCase();
      for(y=0; y<validCommands.length; y++) {
        if(cmdArg == validCommands[y]) {
          hasCordovaCmd = true;
          break;
        }
      }
    }

    if(!hasCordovaCmd) {
      cmdArgs.unshift('add');
    }
  }

  // var noHook = argv.nohooks || argv.n;

  // if (!noHook) {
  //   console.log('Adding in default Ionic hooks'.yellow.bold)
  //   // this.addHooks();
  //   // this.removeOldPluginHooks();
  // } else {
  //   console.log('Option passed to not install default Ionic hooks'.yellow.bold)
  // }

  cmdArgs.unshift(cmdName);

  // clean out any cmds that may confuse cordova
  var cleanArgs = [];
  var port = argv.port || argv.p || '';
  var liveReloadPort = argv.livereloadport || argv['livereload-port'] || argv.r || '';
  var ignoreCmds = '--livereload -l --consolelogs -c --serverlogs -s --port -p --livereload-port -i -r'.split(' ');
  var isValdCmd;
  for(x=0; x<cmdArgs.length; x++) {
    cmdArg = cmdArgs[x];
    if(port && cmdArg == port) continue;
    if(liveReloadPort && cmdArg == liveReloadPort) continue;
    isValdCmd = true;
    for(y=0; y<ignoreCmds.length; y++) {
      if(cmdArg == ignoreCmds[y]) {
        isValdCmd = false;
        break;
      }
    }
    if(isValdCmd) {
      // make sure --target= has double quotes around it (process.argv removes them)
      if(cmdArg.indexOf('--target=') === 0 && cmdArg.indexOf('"') === -1) {
        cmdArg = cmdArg.replace('--target=', '--target="') + '"';
      }

      cleanArgs.push(cmdArg);
    }
  }

  var cordovaProcess = exec('cordova ' + cleanArgs.join(' '));
  console.log('running cordova ' + cleanArgs.join(' '))

  cordovaProcess.stdout.on('data', function (data) {
    process.stdout.write(data);
  });

  cordovaProcess.stderr.on('data', function (data) {
    if(data) {
      process.stderr.write(data.toString().error.bold);
    }
  });

  cordovaProcess.on('close', function(code) {
    deferred.resolve(code);
  });

  if(self.isLiveReload) {
    cordovaProcess.on('exit', function(){
      console.log('cordova process is exiting');
      setTimeout(function(){
        // set it back to the original src after a few seconds
        self.ionic.setConfigXml({
          resetContent: true,
          errorWhenNotFound: true
        });
        // deferred.resolve();
      }, 5000);
    });

    process.on('exit', function(){
      // verify it was set back
      self.ionic.setConfigXml({
        resetContent: true,
        errorWhenNotFound: false
      });
    });

    var readLine = require("readline");
    if(process.platform === "win32") {
      var rl = readLine.createInterface ({
          input: process.stdin,
          output: process.stdout
      });

      rl.on("SIGINT", function (){
        process.emit("SIGINT");
      });
    }

    process.on("SIGINT", function(){
      process.exit();
    });
  }

  IonicStats.t();

  return deferred.promise;
};

IonicTask.prototype.setupLiveReload = function() {
  var d = Q.defer();

  console.log('Setup Live Reload'.green.bold);

  var self = this;
  var serve = new require('./serve');
  var serveTask = new serve.IonicTask();
  serveTask.ionic = this.ionic;
  serveTask.isPlatformServe = true;

  serveTask.loadSettings();

  serveTask.getAddress()
  .then(function() {
    return serveTask.checkPorts(true, serveTask.port, serveTask.address);
  })
  .then(function() {
    if(serveTask.runLivereload) {
      return serveTask.checkPorts(false, serveTask.liveReloadPort, serveTask.address);
    }
  })
  .then(function() {

    serveTask.runLivereload = true;
    serveTask.launchBrowser = false;
    serveTask.launchLab = false;
    serveTask.start(self.ionic);

    if(self.ionic.hasFailed) return;

    self.ionic.setConfigXml({
      devServer: serveTask.devServer
    }).then(function(){
      d.resolve();
    });
  })
  .catch(function(error) {

  })

  return d.promise;
};

exports.IonicTask = IonicTask;
<commit_msg>Updating to run cordova commands as normal.<commit_after>var Task = require('./task').Task,
    IonicStats = require('./stats').IonicStats,
    fs = require('fs'),
    Q = require('q'),
    argv = require('optimist').boolean(['nohooks', 'n', 'r', 'noresources', 'nosave', 'e']).argv,
    path = require('path'),
    exec = require('child_process').exec,
    colors = require('colors'),
    shelljs = require('shelljs'),
    generate = require('./resources/generate'),
    settings = require('./resources/settings'),
    ionicAppLib = require('ionic-app-lib'),
    Cordova = ionicAppLib.cordova,
    Hooks = require('./hooks'),
    State = require('./state');

var IonicTask = function() {};

IonicTask.prototype = new Task();

IonicTask.prototype.run = function(ionic) {
  this.ionic = ionic;
  var self = this;
  var cmdName = process.argv[2].toLowerCase();
  var q;

  this.isLiveReload = ((cmdName == 'run' || cmdName == 'emulate') && (argv.livereload || argv['live-reload'] || argv.l));

  // Cordova.addPlatform(path.resolve('.'));
  // return;

  this.addIcons = !(argv.noresources || argv.r);

  if(this.isLiveReload) {
    q = self.setupLiveReload();

  } else {
    // ensure the content node was set back to its original
    q = self.ionic.setConfigXml({
      resetContent: true,
      errorWhenNotFound: false
    });
  }

  var addDefaultResources = false;
  var isPlatformCmd = argv._.indexOf('platform') != -1;
  var isAddCmd = argv._.indexOf('add') != -1;
  var isPluginCmd = argv._.indexOf('plugin') != -1;
  var isRmCmd = argv._.indexOf('rm') != -1 || argv._.indexOf('remove') != -1;

  if(isPlatformCmd && isAddCmd) {
    addDefaultResources = true;
  }
  // console.log('Icons: ', addDefaultResources, 'Add icons:', this.addIcons)

  q.then(function(){
    if(addDefaultResources && self.addIcons) {
      return generate.copyIconFilesIntoResources()
      .then(function() {
        return generate.addIonicIcons(argv._[2]);
      })
    } else {
      return false;
    }
  })
  .then(function() {
    return self.runCordova(cmdName);
  })
  .then(function(runCode) {
    //We dont want to do anything if the cordova command failed
    if(runCode !== 0 || argv.nosave) {
      return
    }
    if (isPlatformCmd && isAddCmd) {
      addDefaultResources = true;
      console.log('Saving platform to package.json file'.blue)
      return State.savePlatform(argv);
    } else if (isPlatformCmd && isRmCmd) {
      console.log('Removing platform from package.json file'.blue)
      return State.removePlatform(argv);
    } else if (isPluginCmd && isAddCmd) {
      console.log('Saving plugin to package.json file'.blue)
      return State.savePlugin(argv);
    } else if (isPluginCmd && isRmCmd) {
      console.log('Removing plugin from package.json file'.blue)
      return State.removePlugin(argv);
    }
  })
}

IonicTask.prototype.runCordova = function(cmdName) {
  var deferred = Q.defer();
  var self = this;
  var cmdArgs = (process.argv.length > 3 ? process.argv.slice(3) : []);
  var cmdArg, x, y;

  // backwards compatibility prior to fully wrapping cordova cmds
  if(cmdName == 'platform') {
    // `ionic platform <PLATFORM>` used to actually run `ionic platform add <PLATFORM>`
    // if a cordova platform cmd isn't the cmd then automatically insert `add`
    var hasCordovaCmd = false;
    var validCommands = 'add remove rm list ls update up check'.split(' ');
    for(x=0; x<cmdArgs.length; x++) {
      cmdArg = cmdArgs[x].toLowerCase();
      for(y=0; y<validCommands.length; y++) {
        if(cmdArg == validCommands[y]) {
          hasCordovaCmd = true;
          break;
        }
      }
    }

    if(!hasCordovaCmd) {
      cmdArgs.unshift('add');
    }
  }

  // var noHook = argv.nohooks || argv.n;

  // if (!noHook) {
  //   console.log('Adding in default Ionic hooks'.yellow.bold)
  //   // this.addHooks();
  //   // this.removeOldPluginHooks();
  // } else {
  //   console.log('Option passed to not install default Ionic hooks'.yellow.bold)
  // }

  cmdArgs.unshift(cmdName);

  // clean out any cmds that may confuse cordova
  var cleanArgs = [];
  var port = argv.port || argv.p || '';
  var liveReloadPort = argv.livereloadport || argv['livereload-port'] || argv.r || '';
  var ignoreCmds = '--livereload -l --consolelogs -c --serverlogs -s --port -p --livereload-port -i -r'.split(' ');
  var isValdCmd;
  for(x=0; x<cmdArgs.length; x++) {
    cmdArg = cmdArgs[x];
    if(port && cmdArg == port) continue;
    if(liveReloadPort && cmdArg == liveReloadPort) continue;
    isValdCmd = true;
    for(y=0; y<ignoreCmds.length; y++) {
      if(cmdArg == ignoreCmds[y]) {
        isValdCmd = false;
        break;
      }
    }
    if(isValdCmd) {
      // make sure --target= has double quotes around it (process.argv removes them)
      if(cmdArg.indexOf('--target=') === 0 && cmdArg.indexOf('"') === -1) {
        cmdArg = cmdArg.replace('--target=', '--target="') + '"';
      }

      cleanArgs.push(cmdArg);
    }
  }

  var cordovaProcess = exec('cordova ' + cleanArgs.join(' '));
  console.log('running cordova ' + cleanArgs.join(' '))

  cordovaProcess.stdout.on('data', function (data) {
    process.stdout.write(data);
  });

  cordovaProcess.stderr.on('data', function (data) {
    if(data) {
      process.stderr.write(data.toString().error.bold);
    }
  });

  cordovaProcess.on('close', function(code) {
    deferred.resolve(code);
  });

  if(self.isLiveReload) {
    cordovaProcess.on('exit', function(){
      console.log('cordova process is exiting');
      setTimeout(function(){
        // set it back to the original src after a few seconds
        self.ionic.setConfigXml({
          resetContent: true,
          errorWhenNotFound: true
        });
        // deferred.resolve();
      }, 5000);
    });

    process.on('exit', function(){
      // verify it was set back
      self.ionic.setConfigXml({
        resetContent: true,
        errorWhenNotFound: false
      });
    });

    var readLine = require("readline");
    if(process.platform === "win32") {
      var rl = readLine.createInterface ({
          input: process.stdin,
          output: process.stdout
      });

      rl.on("SIGINT", function (){
        process.emit("SIGINT");
      });
    }

    process.on("SIGINT", function(){
      process.exit();
    });
  }

  IonicStats.t();

  return deferred.promise;
};

IonicTask.prototype.setupLiveReload = function() {
  var d = Q.defer();

  console.log('Setup Live Reload'.green.bold);

  var self = this;
  var serve = new require('./serve');
  var serveTask = new serve.IonicTask();
  serveTask.ionic = this.ionic;
  serveTask.isPlatformServe = true;

  serveTask.loadSettings();

  serveTask.getAddress()
  .then(function() {
    return serveTask.checkPorts(true, serveTask.port, serveTask.address);
  })
  .then(function() {
    if(serveTask.runLivereload) {
      return serveTask.checkPorts(false, serveTask.liveReloadPort, serveTask.address);
    }
  })
  .then(function() {

    serveTask.runLivereload = true;
    serveTask.launchBrowser = false;
    serveTask.launchLab = false;
    serveTask.start(self.ionic);

    if(self.ionic.hasFailed) return;

    self.ionic.setConfigXml({
      devServer: serveTask.devServer
    }).then(function(){
      d.resolve();
    });
  })
  .catch(function(error) {

  })

  return d.promise;
};

exports.IonicTask = IonicTask;
<|endoftext|>


<commit_before>var fs = require('fs'),
    os = require('os'),
    path = require('path'),
    spawn = require('child_process').spawn,
    mkdirp = require('mkdirp'),
    async = require('async'),
    pkgcloud = require('pkgcloud'),
    useradd = require('useradd');

function noop() {}

//
// Starts an application.
//
module.exports = function (options, callback) {
  async.parallel([
    async.apply(fetch, options),
    async.apply(createUser, options)
  ], function (err) {
    if (err) {
      return callback(err);
    }

    async.series([
      async.apply(unpack, options),
      async.apply(readPackageJSON, options),
      async.apply(start, options)
    ], callback);
  });
};

var fetch = module.exports.fetch = function fetch(options, callback) {
  var client = pkgcloud.storage.createClient(options.storage),
      tries = 0,
      maxTries = 5,
      packedSnapshotPath = path.join(os.tmpDir(), 'snapshot.tgz');

  options.packedSnapshotPath = packedSnapshotPath;

  function doFetch(callback) {
    ++tries;

    var stream = client.download({
      container: options.storage.container,
      remote: [ options.app.user, options.app.name, options.app.version ].join('-') + '.tgz'
    });

    stream.pipe(fs.createWriteStream(packedSnapshotPath))

    stream.on('error', function (err) {
      console.error('Error while fetching snapshot: ' + err.message);
      return tries === maxTries
        ? callback(err)
        : doFetch(callback);
    });

    stream.on('end', function () {
      console.log('Application snapshot fetched.');
      callback();
    });
  }

  console.log('Fetching application snapshot...');

  doFetch(callback);
};

//
// Create a dedicated user account.
//
var createUser = module.exports.createUser = function createUser(options, callback) {
  console.log('Creating user...');

  useradd({
    login: 'nodejitsu-' + options.app.user,
    shell: false,
    home: false
  }, callback);
};

var unpack = module.exports.unpack = function unpack(options, callback) {
  var snapshotPath = path.join(os.tmpDir(), 'snapshot'),
      child;

  console.log('Unpacking snapshot...');

  options.snapshotPath = snapshotPath;
  options.packagePath = path.join(snapshotPath, 'package');

  mkdirp(snapshotPath, function (err) {
    if (err) {
      return callback(err);
    }

    child = spawn('tar', ['-xf', options.packedSnapshotPath], {
      cwd: snapshotPath
    });

    child.on('exit', function (code, signal) {
      fs.unlink(options.packedSnapshotPath, noop);

      if (code !== 0) {
        return callback(
          new Error('`tar` exited with ' + (code
            ? 'code ' + code.toString()
            : 'signal ' + signal.toString()
         ))
        );
      }

      return callback();
    });
  });
};

var readPackageJSON = module.exports.readPackageJSON = function readPackageJSON(options, callback) {
  console.log('Reading `package.json`...');

  fs.readFile(path.join(options.packagePath, 'package.json'), function (err, data) {
    if (err) {
      return callback(new Error('Error while reading `package.json`: ' + err.message));
    }

    try {
      data = JSON.parse(data);
    }
    catch (ex) {
      return callback(new Error('Error while parsing `package.json`: ' + err.message));
    }

    options['package.json'] = data;
    callback();
  });
};

var start = module.exports.start = function start(options, callback) {
  var args = [],
      child;

  console.log('Starting application...');

  // XXX(mmalecki): LOLOLOL HACK
  args = ['start', '-o', 'estragon.log', '--'];
  options.instruments.forEach(function (instrument) {
    args.push('-h', instrument.host + ':' + (instrument.port || 8556).toString());
  });
  args.push('--', 'node', options['package.json'].scripts.start.split(' ')[1]);

  child = spawn('aeternum', args, {
    cwd: path.join(snapshotPath, 'package')
  });
};
<commit_msg>[fix] s/snapshotPath/options.snapshotPath/<commit_after>var fs = require('fs'),
    os = require('os'),
    path = require('path'),
    spawn = require('child_process').spawn,
    mkdirp = require('mkdirp'),
    async = require('async'),
    pkgcloud = require('pkgcloud'),
    useradd = require('useradd');

function noop() {}

//
// Starts an application.
//
module.exports = function (options, callback) {
  async.parallel([
    async.apply(fetch, options),
    async.apply(createUser, options)
  ], function (err) {
    if (err) {
      return callback(err);
    }

    async.series([
      async.apply(unpack, options),
      async.apply(readPackageJSON, options),
      async.apply(start, options)
    ], callback);
  });
};

var fetch = module.exports.fetch = function fetch(options, callback) {
  var client = pkgcloud.storage.createClient(options.storage),
      tries = 0,
      maxTries = 5,
      packedSnapshotPath = path.join(os.tmpDir(), 'snapshot.tgz');

  options.packedSnapshotPath = packedSnapshotPath;

  function doFetch(callback) {
    ++tries;

    var stream = client.download({
      container: options.storage.container,
      remote: [ options.app.user, options.app.name, options.app.version ].join('-') + '.tgz'
    });

    stream.pipe(fs.createWriteStream(packedSnapshotPath))

    stream.on('error', function (err) {
      console.error('Error while fetching snapshot: ' + err.message);
      return tries === maxTries
        ? callback(err)
        : doFetch(callback);
    });

    stream.on('end', function () {
      console.log('Application snapshot fetched.');
      callback();
    });
  }

  console.log('Fetching application snapshot...');

  doFetch(callback);
};

//
// Create a dedicated user account.
//
var createUser = module.exports.createUser = function createUser(options, callback) {
  console.log('Creating user...');

  useradd({
    login: 'nodejitsu-' + options.app.user,
    shell: false,
    home: false
  }, callback);
};

var unpack = module.exports.unpack = function unpack(options, callback) {
  var snapshotPath = path.join(os.tmpDir(), 'snapshot'),
      child;

  console.log('Unpacking snapshot...');

  options.snapshotPath = snapshotPath;
  options.packagePath = path.join(snapshotPath, 'package');

  mkdirp(snapshotPath, function (err) {
    if (err) {
      return callback(err);
    }

    child = spawn('tar', ['-xf', options.packedSnapshotPath], {
      cwd: snapshotPath
    });

    child.on('exit', function (code, signal) {
      fs.unlink(options.packedSnapshotPath, noop);

      if (code !== 0) {
        return callback(
          new Error('`tar` exited with ' + (code
            ? 'code ' + code.toString()
            : 'signal ' + signal.toString()
         ))
        );
      }

      return callback();
    });
  });
};

var readPackageJSON = module.exports.readPackageJSON = function readPackageJSON(options, callback) {
  console.log('Reading `package.json`...');

  fs.readFile(path.join(options.packagePath, 'package.json'), function (err, data) {
    if (err) {
      return callback(new Error('Error while reading `package.json`: ' + err.message));
    }

    try {
      data = JSON.parse(data);
    }
    catch (ex) {
      return callback(new Error('Error while parsing `package.json`: ' + err.message));
    }

    options['package.json'] = data;
    callback();
  });
};

var start = module.exports.start = function start(options, callback) {
  var args = [],
      child;

  console.log('Starting application...');

  // XXX(mmalecki): LOLOLOL HACK
  args = ['start', '-o', 'estragon.log', '--'];
  options.instruments.forEach(function (instrument) {
    args.push('-h', instrument.host + ':' + (instrument.port || 8556).toString());
  });
  args.push('--', 'node', options['package.json'].scripts.start.split(' ')[1]);

  child = spawn('aeternum', args, {
    cwd: path.join(options.snapshotPath, 'package')
  });
};
<|endoftext|>


<commit_before>
var spawn = require('child_process').spawn;
var fs = require('fs');

var inPath = 'test.mp3';
var inFile = fs.createReadStream(inPath);

inFile.on('error', function(err) {
  console.log(err);
});

var outPath = 'testo.ogg';
var outStream = fs.createWriteStream(outPath);

//try {
  var ffmpeg = spawn('ffmpeg', [
    '-i', inPath,
    '-f', 'ogg',
    '-acodec', 'libvorbis',
    'pipe:1'  // Output on stdout
  ]);
//} catch (e) {
  //console.log('ERR:', e);
}

//var ffmpeg = child_process.spawn('ffmpeg', ['-i', 'pipe:0', '-f', 'mp4', '-movflags', 'frag_keyframe', 'pipe:1']);
//inFile.pipe(ffmpeg.stdin);
//ffmpeg.stdout.pipe(outStream);

ffmpeg.stdout.on('end', function () {
  console.log('file has been converted succesfully');
});

ffmpeg.stdout.on('exit', function () {
  console.log('child process exited');
});

ffmpeg.stderr.on('data', function (data) {
  console.log('ERR', data.toString());
});
<commit_msg>Better ffmpeg streaming test.<commit_after>var spawn = require('child_process').spawn;
var fs = require('fs');

var inPath = 'test.mp3';
var outPath = 'testo.ogg';
var outStream = fs.createWriteStream(outPath);

var ffmpeg = spawn('ffmpeg', [
  '-i', inPath,
  '-acodec', 'libvorbis',
  '-f', 'ogg',                // Output format for the pipe.
  'pipe:1'                    // Send output to sdtout.
]);

// Pipe ffmpeg output to output file.
ffmpeg.stdout.pipe(outStream);

outStream.on('close', function() {
  console.log('CLOSE: outstream');
  ffmpeg.kill();
});

ffmpeg.stderr.on('exit', function() {
  console.log('EXIT: child process exited');
});

ffmpeg.stderr.on('data', function(data) {
  console.log('DATA', data.toString());
});

ffmpeg.stderr.on('end', function () {
  console.log('END: file has been converted succesfully');
});
<|endoftext|>


<commit_before>'use strict';

//
// Examples implemented from this blog:
//
// http://pythonhow.com/accessing-dataframe-columns-rows-and-cells
//

describe('accessing columns, rows and cells', function () {

    var expect = require('chai').expect;

    var dataForge = require('../index');

    var fs = require('fs');
    var path = require('path');

    var df1;
    var df2;

    beforeEach(function () {

        var csv = fs.readFileSync(path.join(__dirname, 'accessing-columns-rows-and-cells.csv'), 'utf8');
        df1 = dataForge.fromCSV(csv)
            .parseInts(["2005", "2006", "2007", "2008", "2009", "2010", "2011", "2012", "2013", ])
            ;

        df2 = df1
            .setIndex("State")
            .dropSeries("State")
            ;
    })

    it('can load csv', function () {

        expect(df1.getColumnNames()).to.eql(["GEOID", "State", "2005", "2006", "2007", "2008", "2009", "2010", "2011", "2012", "2013", ]);
        expect(df1.getIndex().toValues()).to.eql([0, 1, 2, 3, 4]);
        expect(df1.toRows()).to.eql([
            ["04000US01", "Alabama", 37150, 37952, 42212, 44476, 39980, 40933, 42590, 43464, 41381],
            ["04000US02", "Alaska", 55891, 56418, 62993, 63989, 61604, 57848, 57431, 63648, 61137],
            ["04000US04", "Arizona", 45245, 46657, 47215, 46914, 45739, 46896, 48621, 47044, 50602],
            ["04000US05", "Arkansas", 36658, 37057, 40795, 39586, 36538, 38587, 41302, 39018, 39919],
            ["04000US06", "California", 51755, 55319, 55734, 57014, 56134, 54283, 53367, 57020, 57528],
        ]);
    });

    it('can set index', function () {

        expect(df2.getColumnNames()).to.eql(["GEOID", "2005", "2006", "2007", "2008", "2009", "2010", "2011", "2012", "2013", ]);
        expect(df2.getIndex().toValues()).to.eql(["Alabama", "Alaska", "Arizona", "Arkansas", "California", ]);
        expect(df2.toRows()).to.eql([
            ["04000US01", 37150, 37952, 42212, 44476, 39980, 40933, 42590, 43464, 41381],
            ["04000US02", 55891, 56418, 62993, 63989, 61604, 57848, 57431, 63648, 61137],
            ["04000US04", 45245, 46657, 47215, 46914, 45739, 46896, 48621, 47044, 50602],
            ["04000US05", 36658, 37057, 40795, 39586, 36538, 38587, 41302, 39018, 39919],
            ["04000US06", 51755, 55319, 55734, 57014, 56134, 54283, 53367, 57020, 57528],
        ]);
    });

    it('can take subset', function () {

        var subset = df2
            .subset(["2005", "2006", "2007"])
            .slice("Alaska", "California")
            ;

        expect(subset.getColumnNames()).to.eql(["2005", "2006", "2007", ]);
        expect(subset.getIndex().toValues()).to.eql(["Alaska", "Arizona", "Arkansas", ]);
        expect(subset.toRows()).to.eql([
            [55891, 56418, 62993],
            [45245, 46657, 47215],
            [36658, 37057, 40795],
        ]);
    });

});<commit_msg>Added an example of getting a  column by name.<commit_after>'use strict';

//
// Examples implemented from this blog:
//
// http://pythonhow.com/accessing-dataframe-columns-rows-and-cells
//

describe('accessing columns, rows and cells', function () {

    var expect = require('chai').expect;

    var dataForge = require('../index');

    var fs = require('fs');
    var path = require('path');

    var df1;
    var df2;

    beforeEach(function () {

        var csv = fs.readFileSync(path.join(__dirname, 'accessing-columns-rows-and-cells.csv'), 'utf8');
        df1 = dataForge.fromCSV(csv)
            .parseInts(["2005", "2006", "2007", "2008", "2009", "2010", "2011", "2012", "2013", ])
            ;

        df2 = df1
            .setIndex("State")
            .dropSeries("State")
            ;
    })

    it('can load csv', function () {

        expect(df1.getColumnNames()).to.eql(["GEOID", "State", "2005", "2006", "2007", "2008", "2009", "2010", "2011", "2012", "2013", ]);
        expect(df1.getIndex().toValues()).to.eql([0, 1, 2, 3, 4]);
        expect(df1.toRows()).to.eql([
            ["04000US01", "Alabama", 37150, 37952, 42212, 44476, 39980, 40933, 42590, 43464, 41381],
            ["04000US02", "Alaska", 55891, 56418, 62993, 63989, 61604, 57848, 57431, 63648, 61137],
            ["04000US04", "Arizona", 45245, 46657, 47215, 46914, 45739, 46896, 48621, 47044, 50602],
            ["04000US05", "Arkansas", 36658, 37057, 40795, 39586, 36538, 38587, 41302, 39018, 39919],
            ["04000US06", "California", 51755, 55319, 55734, 57014, 56134, 54283, 53367, 57020, 57528],
        ]);
    });

    it('can set index', function () {

        expect(df2.getColumnNames()).to.eql(["GEOID", "2005", "2006", "2007", "2008", "2009", "2010", "2011", "2012", "2013", ]);
        expect(df2.getIndex().toValues()).to.eql(["Alabama", "Alaska", "Arizona", "Arkansas", "California", ]);
        expect(df2.toRows()).to.eql([
            ["04000US01", 37150, 37952, 42212, 44476, 39980, 40933, 42590, 43464, 41381],
            ["04000US02", 55891, 56418, 62993, 63989, 61604, 57848, 57431, 63648, 61137],
            ["04000US04", 45245, 46657, 47215, 46914, 45739, 46896, 48621, 47044, 50602],
            ["04000US05", 36658, 37057, 40795, 39586, 36538, 38587, 41302, 39018, 39919],
            ["04000US06", 51755, 55319, 55734, 57014, 56134, 54283, 53367, 57020, 57528],
        ]);
    });

    it('can take subset', function () {

        var subset = df2
            .subset(["2005", "2006", "2007"])
            .slice("Alaska", "California")
            ;

        expect(subset.getColumnNames()).to.eql(["2005", "2006", "2007", ]);
        expect(subset.getIndex().toValues()).to.eql(["Alaska", "Arizona", "Arkansas", ]);
        expect(subset.toRows()).to.eql([
            [55891, 56418, 62993],
            [45245, 46657, 47215],
            [36658, 37057, 40795],
        ]);
    });

    it('can take column', function () {

        var series = df2.getSeries("2005");

        expect(series.getIndex().toValues()).to.eql(["Alabama", "Alaska", "Arizona", "Arkansas", "California"]);
        expect(series.toValues()).to.eql([ 37150, 55891, 45245, 36658, 51755, ]);
    });

});<|endoftext|>


<commit_before>"use strict";
var irc = require("irc");

function IrcServer(domain, opts) {
    this.domain = domain;
    this.nick = opts && opts.nick ? opts.nick : "matrixASbot";
    this.channelToRoomIds = {};
    var prefix;

    if (opts && opts.rooms) {
        var channels = Object.keys(opts.rooms);
        for (var i=0; i<channels.length; i++) {
            var channel = channels[i];
            if (channel === "*" && typeof opts.rooms["*"] === "string") {
                prefix = opts.rooms["*"];
                // strip leading #
                if (prefix.indexOf("#") === 0) {
                    prefix = prefix.substring(1);
                }
                this.aliasPrefix = prefix;
                continue;
            }

            if (typeof opts.rooms[channel] === "string") {
                opts.rooms[channel] = [opts.rooms[channel]]
            }

            this.channelToRoomIds[channel] = opts.rooms[channel];
        }
    }

    if (opts && typeof opts.virtualUserPrefix === "string") {
        prefix = opts.virtualUserPrefix;
        if (prefix.indexOf("@") === 0) {
            prefix = prefix.substring(1);
        }
        this.userPrefix = prefix;
    }
    else {
        // user prefix is just going to be the IRC domain with an _
        // e.g. @irc.freenode.net_Alice:homserver.com
        this.userPrefix = this.domain + "_";
    }
};

IrcServer.prototype.connect = function(callbacks) {
    // auto-connect as a bot to channels being tracked.
    return this.connectAs(this.nick, Object.keys(this.channelToRoomIds),
                          callbacks);
};

IrcServer.prototype.connectAs = function(nick, channels, callbacks) {
    console.log("Connecting to IRC server %s as %s - Joining channels %s",
        this.domain, nick, channels);
    var thisServer = this;
    var client = new irc.Client(
        this.domain, nick,
        {
            channels: channels
        }
    );
    client.addListener("error", function(err) {
        console.error(
            "Server: %s Error: %s", thisServer.domain,
            JSON.stringify(err)
        );
    });

    if (callbacks) {
        if (callbacks.onMessage) {
            client.addListener("message", function(from, to, text) {
                callbacks.onMessage(thisServer, from, to, "message", text);
            });
            client.addListener("ctcp-privmsg", function(from, to, text) {
                callbacks.onMessage(thisServer, from, to, "privmsg", text);
            });
            client.addListener("notice", function(from, to, text) {
                if (from) { // ignore server notices
                    callbacks.onMessage(thisServer, from, to, "notice", text);
                }
            });
        }
    }
    return client;
};

IrcServer.prototype.shouldMapAllRooms = function() {
    return this.aliasPrefix !== undefined;
};

IrcServer.prototype.isTrackingChannels = function() {
    return Object.keys(this.channelToRoomIds).length > 0;
};

module.exports.IrcServer = IrcServer;<commit_msg>Interpret emotes correctly.<commit_after>"use strict";
var irc = require("irc");

function IrcServer(domain, opts) {
    this.domain = domain;
    this.nick = opts && opts.nick ? opts.nick : "matrixASbot";
    this.channelToRoomIds = {};
    var prefix;

    if (opts && opts.rooms) {
        var channels = Object.keys(opts.rooms);
        for (var i=0; i<channels.length; i++) {
            var channel = channels[i];
            if (channel === "*" && typeof opts.rooms["*"] === "string") {
                prefix = opts.rooms["*"];
                // strip leading #
                if (prefix.indexOf("#") === 0) {
                    prefix = prefix.substring(1);
                }
                this.aliasPrefix = prefix;
                continue;
            }

            if (typeof opts.rooms[channel] === "string") {
                opts.rooms[channel] = [opts.rooms[channel]]
            }

            this.channelToRoomIds[channel] = opts.rooms[channel];
        }
    }

    if (opts && typeof opts.virtualUserPrefix === "string") {
        prefix = opts.virtualUserPrefix;
        if (prefix.indexOf("@") === 0) {
            prefix = prefix.substring(1);
        }
        this.userPrefix = prefix;
    }
    else {
        // user prefix is just going to be the IRC domain with an _
        // e.g. @irc.freenode.net_Alice:homserver.com
        this.userPrefix = this.domain + "_";
    }
};

IrcServer.prototype.connect = function(callbacks) {
    // auto-connect as a bot to channels being tracked.
    return this.connectAs(this.nick, Object.keys(this.channelToRoomIds),
                          callbacks);
};

IrcServer.prototype.connectAs = function(nick, channels, callbacks) {
    console.log("Connecting to IRC server %s as %s - Joining channels %s",
        this.domain, nick, channels);
    var thisServer = this;
    var client = new irc.Client(
        this.domain, nick,
        {
            channels: channels
        }
    );
    client.addListener("error", function(err) {
        console.error(
            "Server: %s Error: %s", thisServer.domain,
            JSON.stringify(err)
        );
    });

    if (callbacks) {
        if (callbacks.onMessage) {
            client.addListener("message", function(from, to, text) {
                callbacks.onMessage(thisServer, from, to, "message", text);
            });
            client.addListener("ctcp-privmsg", function(from, to, text) {
                if (text.indexOf("ACTION ") == 0) {
                    callbacks.onMessage(
                        thisServer, from, to, "privmsg",
                        text.substring("ACTION ".length)
                    );
                }
            });
            client.addListener("notice", function(from, to, text) {
                if (from) { // ignore server notices
                    callbacks.onMessage(thisServer, from, to, "notice", text);
                }
            });
        }
    }
    return client;
};

IrcServer.prototype.shouldMapAllRooms = function() {
    return this.aliasPrefix !== undefined;
};

IrcServer.prototype.isTrackingChannels = function() {
    return Object.keys(this.channelToRoomIds).length > 0;
};

module.exports.IrcServer = IrcServer;<|endoftext|>


<commit_before>var fs = require('fs'),
    os = require('os'),
    path = require('path'),
    spawn = require('child_process').spawn,
    rimraf = require('rimraf'),
    mkdirp = require('mkdirp'),
    async = require('async'),
    pkgcloud = require('pkgcloud'),
    semver = require('semver'),
    uidNumber = require('uid-number'),
    killer = require('killer');

function noop() {}

//
// Starts an application.
//
exports.start = function (options, callback) {
  if (!options.app) {
    return callback(new Error('options.app is required.'));
  }

  options.packedSnapshotPath = path.join(options.runDir, 'snapshot.tgz');
  options.snapshotPath       = path.join(options.runDir, 'snapshot');
  options.packagePath        = path.join(options.snapshotPath, 'package');
  options.tmpPath            = path.join(options.snapshotPath, '.tmp');

  //
  // ### function runApp()
  // Performs the app startup sequence without
  // modifying the file system.
  //
  function runApp(err) {
    if (err) {
      return callback(err);
    }

    async.series([
      async.apply(readPackageJSON, options),
      async.apply(findEngines, options),
      async.apply(readEnv, options),
      async.apply(restrictFilesystem, options),
      async.apply(startApp, options)
    ], callback);
  }

  //
  // If this is a "soft" start then do not
  // modify the underlying file system: assume
  // the snapshot is already in-place.
  //
  if (options.soft) {
    return runApp();
  }

  async.series([
    async.apply(clean, options),
    async.apply(mkdirp, options.runDir),
    async.apply(fetch, options),
    async.apply(unpack, options),
  ], runApp);
};

exports.restart = function (options, callback) {
  var logger = options.logger;

  fs.exists(options.pidFile, function (exists) {
    if (!exists) {
      return callback(new Error(options.pidFile + ' does not exist.'));
    }

    fs.readFile(options.pidFile, 'utf8', function (err, content) {
      if (err) {
        return callback(err);
      }

      content = parseInt(content, 10);
      logger.info('Sending SIGUSR1 - ' + content);
      if (!Number.isNaN(content)) {
        try { process.kill(content, 'SIGUSR1') }
        catch (ex) { logger.info('SIGUSR1 Error - ' + ex.message) }
      }

      callback();
    });
  });
};

exports.stop = function (options, callback) {
  var logger = options.logger;

  fs.readFile(options.pidFile, 'utf8', function (err, content) {
    if (err) {
      return callback(err);
    }

    content = parseInt(content, 10);
    if (Number.isNaN(content)) {
      //
      // If the content in the pidFile is bad, then
      // **clean the server hard**.
      //
      return !options.soft
        ? clean(options, callback)
        : callback();
    }

    logger.info('Sending terminate signal - ' + content);
    killer({
      pid: content,
      timeout: 10000,
      interval: 100
    }, function () {
      async.parallel([
        function removeCode(next) {
          return !options.soft
            ? rimraf(options.runDir, next.bind(null, null))
            : next();
        },
        function removePid(next) {
          fs.unlink(options.pidFile, next.bind(null, null));
        }
      ], callback);
    });
  });
};

var clean = exports.clean = function clean(options, callback) {
  var commands = [
    ['pkill', '-9', 'aeternum'],
    ['pkill', 'forza'],
    ['rm', '-rf', options.pidFile || path.join(process.env.HOME, 'app.pid')],
    ['rm', '-rf', options.runDir  || ('/' + path.join('opt', 'run'))]
  ];

  var logger = options.logger;

  logger.info('Cleaning ' + options.runDir);
  async.forEachSeries(commands, function (args, next) {
    var command = args.shift(),
        child   = spawn(command, args);

    child.stdout.on('data', function (d) { logger.info('' + d) });
    child.stderr.on('data', function (d) { logger.info('' + d) });
    child.on('exit', next.bind(null, null));
  }, callback);
};

var fetch = exports.fetch = function fetch(options, callback) {
  var client = pkgcloud.storage.createClient(options.storage),
      packedSnapshotPath = options.packedSnapshotPath,
      logger = options.logger,
      maxTries = 5,
      tries = 0;

  function doFetch(callback) {
    ++tries;

    var stream = client.download({
      container: options.storage.container,
      remote: [ options.app.user, options.app.name, options.app.version ].join('-') + '.tgz'
    });

    stream.pipe(fs.createWriteStream(packedSnapshotPath));
    stream.on('error', function (err) {
      logger.error('Error while fetching snapshot: ' + err.message);
      return tries === maxTries
        ? callback(err)
        : doFetch(callback);
    });

    stream.on('end', function () {
      logger.info('Application snapshot fetched.');
      callback();
    });
  }

  logger.info('Fetching application snapshot...');
  doFetch(callback);
};

var unpack = exports.unpack = function unpack(options, callback) {
  var snapshotPath = options.snapshotPath,
      logger = options.logger,
      child;

  logger.info('Unpacking snapshot...');
  mkdirp(options.tmpPath, function (err) {
    if (err) {
      return callback(err);
    }

    child = spawn('tar', ['-xf', options.packedSnapshotPath], {
      cwd: snapshotPath
    });

    child.on('exit', function (code, signal) {
      fs.unlink(options.packedSnapshotPath, noop);

      if (code !== 0) {
        return callback(
          new Error('`tar` exited with ' + (code
            ? 'code ' + code.toString()
            : 'signal ' + signal.toString()
         ))
        );
      }

      return callback();
    });
  });
};

var readPackageJSON = exports.readPackageJSON = function readPackageJSON(options, callback) {
  var logger = options.logger;

  logger.info('Reading `package.json`...');

  fs.readFile(path.join(options.packagePath, 'package.json'), function (err, data) {
    if (err) {
      return callback(new Error('Error while reading `package.json`: ' + err.message));
    }

    try {
      data = JSON.parse(data);
    }
    catch (ex) {
      return callback(new Error('Error while parsing `package.json`: ' + ex.message));
    }

    options['package.json'] = data;
    if (!data.scripts || typeof data.scripts.start !== 'string' || !data.scripts.start) {
      return callback(new Error('`scripts.start` property is required'));
    }

    callback();
  });
};

var findEngines = exports.findEnginess = function findEngines(options, callback) {
  var pkgEngines = options['package.json'].engines,
      paths = [];

  if (!pkgEngines || !Object.keys(pkgEngines).length) {
    pkgEngines = { 'node': (options.engines.node && options.engines.node.default) || '0.6.x' };
  }

  async.map(Object.keys(pkgEngines), resolveEngine, saveEngines);

  function resolveEngine(engine, callback) {
    var versionRange = pkgEngines[engine],
        enginePath = options.engines[engine].path;

    if (!Object.hasOwnProperty.call(options.engines, engine) || !enginePath) {
      return callback(new Error('Unknown engine ' + engine));
    }

    if (!semver.validRange(versionRange)) {
      return callback(new Error(versionRange + ' is not a valid SemVer version range!'));
    }

    fs.readdir(enginePath, function(err, versions) {
      if (err) {
        err.message = 'Cannot read engines directory: ' + err.message;
        return callback(err);
      }

      var version = semver.maxSatisfying(versions, versionRange);

      if (!version) {
        return callback(new Error('No satisfying ' + engine + ' version found.\n'));
      }

      callback(null, path.join(enginePath, version, 'bin'));
    });
  }

  function saveEngines(err, engines) {
    options.enginePaths = engines;
    callback(err);
  }
};

var readEnv = exports.readEnv = function readEnv(options, callback) {
  var env;

  if (options.app.env) {
    try { env = JSON.parse(options.app.env) }
    catch (ex) { }
  }

  options.app.env          = env || {};
  options.app.env.NODE_ENV = options.app.env.NODE_ENV || 'production';
  options.app.env.USER     = 'solenoid';
  options.app.env.HOME     = options.packagePath;
  options.app.env.TEMP     = options.tmpPath;
  options.app.env.TMPDIR   = options.tmpPath;
  callback();
};

var restrictFilesystem = exports.restrictFilesystem = function restrictFilesystem(options, callback) {
  //
  // Helper function to run the specified command
  // and assert a non-zero exit code.
  //
  function runFs(cmd, args, msg, next) {
    spawn(cmd, args).on('exit', function (code) {
      return code
        ? next(new Error(msg))
        : next();
    });
  }

  async.parallel([
    async.apply(
      runFs,
      'chown',
      ['-R', 'solenoid:nogroup', options.runDir],
      'Unable to grab ownership for ' + options.runDir
    ),
    async.apply(
      runFs,
      'chmod',
      ['-R', '777', options.runDir],
      'Unable to change permissions for ' + options.runDir
    )
  ], callback);
};

var startApp = exports.startApp = function startApp(options, callback) {
  var startLog = path.join(options.runDir, 'start.log'),
      maxRetries = options.retries || 3,
      timeout = options.retryTimeout || 500,
      logger = options.logger,
      responded = false,
      retries = 0,
      args = [],
      pid = '',
      env = {},
      nodeModulesBin,
      backupPath,
      initPath,
      start,
      child,
      tail;

  logger.info('Starting application...');

  //
  // Set the node_modules .bin path to be set in various locations
  //
  nodeModulesBin = path.join(options.snapshotPath, 'package', 'node_modules', '.bin');

  //
  // Setup the `aeternum` arguments.
  //
  args = ['start', '--min-uptime', options.minUptime, '-o', path.join(options.runDir, 'forza.log'), '--', 'forza'];

  //
  // Setup `forza` arguments.
  //
  args.push('-h', options.instruments.host);
  args.push('-p', (options.instruments.port || 8556).toString());

  args.push('--start-log', startLog);
  args.push('--app-user', options.app.user);
  args.push('--app-name', options.app.name);
  args.push('--');

  //
  // Merge the env with `app.env` and `process.env`.
  //
  [process.env, options.app.env].forEach(function (obj) {
    if (!obj || typeof obj !== 'object') { return }
    Object.keys(obj).forEach(function (key) {
      env[key] = obj[key];
    });
  });

  env.PATH = [nodeModulesBin]
    .concat(options.enginePaths)
    .concat(env.PATH.split(':'))
    .join(':');

  //
  // Remark: we have to do custom detection of coffee-script as it needs to be
  // prepended with node (#!/usr/bin/env node is not intelligent enough)
  //
  start = options['package.json'].scripts.start.split(' ')

  //
  // Set possible path locations where a coffee binary would live and replace
  // 'coffee' with one of these paths
  //
  if(start[0] === 'coffee') {
    initPath = path.resolve(nodeModulesBin, start[0]);
    backupPath = path.resolve(options.enginePaths[0], start[0]);
    start[0] = fs.existsSync(initPath)
      ? initPath
      : backupPath;

    start.unshift('node');
  }

  args.push.apply(args, start);
  uidNumber('solenoid', 'nogroup', function (err, uid, gid) {
    if (err) {
      //
      // Remark: should we allow for errors here?
      //
      return callback(new Error('Could not get uid/gid of child process.'));
    }

    //
    // ### function done (err)
    // Responds once to the callback
    //
    function done(err) {
      if (!responded) {
        responded = true;
        callback.apply(null, arguments);
      }
    }

    //
    // ### function awaitStart ()
    // Writes `options.pidFile` and tails the `forza`
    // start log for the start event.
    //
    function awaitStart() {
      async.series([
        function writePid(next) {
          logger.info('Writing pidfile: ' + options.pidFile);
          fs.writeFile(options.pidFile, pid, next.bind(null, null));
        },
        function tailLog(next) {
          var allLog = '',
              json;

          //
          // Helper function which attempts to respawn
          // the `tail` process in the (rare) case
          // that forza has not already written to it.
          //
          function retry(err) {
            if (++retries < maxRetries) {
              logger.info('Error tailing forza log: ' + err.message);
              logger.info('Retrying the tail.');

              setTimeout(function () {
                tailLog(next);
              }, timeout);
              return;
            }

            next(err);
          }

          logger.info('Tailing forza log: ' + startLog);
          tail = spawn('tail', [ startLog ]);
          tail.on('error', retry);

          //
          // Remark: use close event so we ensure we got all possible data out
          // of the streams
          //
          tail.on('close', function (code, signal) {
            logger.info('Tail closing..');
            //
            // Remark: tail.kill() sends sigterm so ensure we have the json and
            // we killed it appropriately
            //
            if (typeof json !== 'undefined' || signal === 'SIGTERM') {
              return next();
            }

            retry(new Error('tailing start log exited poorly with code ' + code || signal))
          });

          tail.stdout.on('data', function (data) {
            allLog += data;

            try { json = JSON.parse(allLog) }
            catch (ex) { return }

            // Use console.log to ensure it is JSON parseable
            console.log(JSON.stringify(json));

            try { tail.kill() }
            catch (ex) { }
          });
        }
      ], done);
    }

    logger.info('Spawn: ' + args.join(' '));
    child = spawn('aeternum', args, {
      cwd: path.join(options.snapshotPath, 'package'),
      env: env,
      uid: uid,
      gid: gid
    });

    child.on('error', done);
    child.stdout.on('data', function (chunk) {
      pid += chunk.toString('utf8');
    });

    child.stdout.on('end', function () {
      if (!responded) {
        pid = parseInt(pid, 10).toString();
        logger.info('`aeternum` pid: ' + pid);
        awaitStart();
      }
    });
  });
};
<commit_msg>[fix ] always prefix node.<commit_after>var fs = require('fs'),
    os = require('os'),
    path = require('path'),
    spawn = require('child_process').spawn,
    rimraf = require('rimraf'),
    mkdirp = require('mkdirp'),
    async = require('async'),
    pkgcloud = require('pkgcloud'),
    semver = require('semver'),
    uidNumber = require('uid-number'),
    killer = require('killer');

function noop() {}

//
// Starts an application.
//
exports.start = function (options, callback) {
  if (!options.app) {
    return callback(new Error('options.app is required.'));
  }

  options.packedSnapshotPath = path.join(options.runDir, 'snapshot.tgz');
  options.snapshotPath       = path.join(options.runDir, 'snapshot');
  options.packagePath        = path.join(options.snapshotPath, 'package');
  options.tmpPath            = path.join(options.snapshotPath, '.tmp');

  //
  // ### function runApp()
  // Performs the app startup sequence without
  // modifying the file system.
  //
  function runApp(err) {
    if (err) {
      return callback(err);
    }

    async.series([
      async.apply(readPackageJSON, options),
      async.apply(findEngines, options),
      async.apply(readEnv, options),
      async.apply(restrictFilesystem, options),
      async.apply(startApp, options)
    ], callback);
  }

  //
  // If this is a "soft" start then do not
  // modify the underlying file system: assume
  // the snapshot is already in-place.
  //
  if (options.soft) {
    return runApp();
  }

  async.series([
    async.apply(clean, options),
    async.apply(mkdirp, options.runDir),
    async.apply(fetch, options),
    async.apply(unpack, options),
  ], runApp);
};

exports.restart = function (options, callback) {
  var logger = options.logger;

  fs.exists(options.pidFile, function (exists) {
    if (!exists) {
      return callback(new Error(options.pidFile + ' does not exist.'));
    }

    fs.readFile(options.pidFile, 'utf8', function (err, content) {
      if (err) {
        return callback(err);
      }

      content = parseInt(content, 10);
      logger.info('Sending SIGUSR1 - ' + content);
      if (!Number.isNaN(content)) {
        try { process.kill(content, 'SIGUSR1') }
        catch (ex) { logger.info('SIGUSR1 Error - ' + ex.message) }
      }

      callback();
    });
  });
};

exports.stop = function (options, callback) {
  var logger = options.logger;

  fs.readFile(options.pidFile, 'utf8', function (err, content) {
    if (err) {
      return callback(err);
    }

    content = parseInt(content, 10);
    if (Number.isNaN(content)) {
      //
      // If the content in the pidFile is bad, then
      // **clean the server hard**.
      //
      return !options.soft
        ? clean(options, callback)
        : callback();
    }

    logger.info('Sending terminate signal - ' + content);
    killer({
      pid: content,
      timeout: 10000,
      interval: 100
    }, function () {
      async.parallel([
        function removeCode(next) {
          return !options.soft
            ? rimraf(options.runDir, next.bind(null, null))
            : next();
        },
        function removePid(next) {
          fs.unlink(options.pidFile, next.bind(null, null));
        }
      ], callback);
    });
  });
};

var clean = exports.clean = function clean(options, callback) {
  var commands = [
    ['pkill', '-9', 'aeternum'],
    ['pkill', 'forza'],
    ['rm', '-rf', options.pidFile || path.join(process.env.HOME, 'app.pid')],
    ['rm', '-rf', options.runDir  || ('/' + path.join('opt', 'run'))]
  ];

  var logger = options.logger;

  logger.info('Cleaning ' + options.runDir);
  async.forEachSeries(commands, function (args, next) {
    var command = args.shift(),
        child   = spawn(command, args);

    child.stdout.on('data', function (d) { logger.info('' + d) });
    child.stderr.on('data', function (d) { logger.info('' + d) });
    child.on('exit', next.bind(null, null));
  }, callback);
};

var fetch = exports.fetch = function fetch(options, callback) {
  var client = pkgcloud.storage.createClient(options.storage),
      packedSnapshotPath = options.packedSnapshotPath,
      logger = options.logger,
      maxTries = 5,
      tries = 0;

  function doFetch(callback) {
    ++tries;

    var stream = client.download({
      container: options.storage.container,
      remote: [ options.app.user, options.app.name, options.app.version ].join('-') + '.tgz'
    });

    stream.pipe(fs.createWriteStream(packedSnapshotPath));
    stream.on('error', function (err) {
      logger.error('Error while fetching snapshot: ' + err.message);
      return tries === maxTries
        ? callback(err)
        : doFetch(callback);
    });

    stream.on('end', function () {
      logger.info('Application snapshot fetched.');
      callback();
    });
  }

  logger.info('Fetching application snapshot...');
  doFetch(callback);
};

var unpack = exports.unpack = function unpack(options, callback) {
  var snapshotPath = options.snapshotPath,
      logger = options.logger,
      child;

  logger.info('Unpacking snapshot...');
  mkdirp(options.tmpPath, function (err) {
    if (err) {
      return callback(err);
    }

    child = spawn('tar', ['-xf', options.packedSnapshotPath], {
      cwd: snapshotPath
    });

    child.on('exit', function (code, signal) {
      fs.unlink(options.packedSnapshotPath, noop);

      if (code !== 0) {
        return callback(
          new Error('`tar` exited with ' + (code
            ? 'code ' + code.toString()
            : 'signal ' + signal.toString()
         ))
        );
      }

      return callback();
    });
  });
};

var readPackageJSON = exports.readPackageJSON = function readPackageJSON(options, callback) {
  var logger = options.logger;

  logger.info('Reading `package.json`...');

  fs.readFile(path.join(options.packagePath, 'package.json'), function (err, data) {
    if (err) {
      return callback(new Error('Error while reading `package.json`: ' + err.message));
    }

    try {
      data = JSON.parse(data);
    }
    catch (ex) {
      return callback(new Error('Error while parsing `package.json`: ' + ex.message));
    }

    options['package.json'] = data;
    if (!data.scripts || typeof data.scripts.start !== 'string' || !data.scripts.start) {
      return callback(new Error('`scripts.start` property is required'));
    }

    callback();
  });
};

var findEngines = exports.findEnginess = function findEngines(options, callback) {
  var pkgEngines = options['package.json'].engines,
      paths = [];

  if (!pkgEngines || !Object.keys(pkgEngines).length) {
    pkgEngines = { 'node': (options.engines.node && options.engines.node.default) || '0.6.x' };
  }

  async.map(Object.keys(pkgEngines), resolveEngine, saveEngines);

  function resolveEngine(engine, callback) {
    var versionRange = pkgEngines[engine],
        enginePath = options.engines[engine].path;

    if (!Object.hasOwnProperty.call(options.engines, engine) || !enginePath) {
      return callback(new Error('Unknown engine ' + engine));
    }

    if (!semver.validRange(versionRange)) {
      return callback(new Error(versionRange + ' is not a valid SemVer version range!'));
    }

    fs.readdir(enginePath, function(err, versions) {
      if (err) {
        err.message = 'Cannot read engines directory: ' + err.message;
        return callback(err);
      }

      var version = semver.maxSatisfying(versions, versionRange);

      if (!version) {
        return callback(new Error('No satisfying ' + engine + ' version found.\n'));
      }

      callback(null, path.join(enginePath, version, 'bin'));
    });
  }

  function saveEngines(err, engines) {
    options.enginePaths = engines;
    callback(err);
  }
};

var readEnv = exports.readEnv = function readEnv(options, callback) {
  var env;

  if (options.app.env) {
    try { env = JSON.parse(options.app.env) }
    catch (ex) { }
  }

  options.app.env          = env || {};
  options.app.env.NODE_ENV = options.app.env.NODE_ENV || 'production';
  options.app.env.USER     = 'solenoid';
  options.app.env.HOME     = options.packagePath;
  options.app.env.TEMP     = options.tmpPath;
  options.app.env.TMPDIR   = options.tmpPath;
  callback();
};

var restrictFilesystem = exports.restrictFilesystem = function restrictFilesystem(options, callback) {
  //
  // Helper function to run the specified command
  // and assert a non-zero exit code.
  //
  function runFs(cmd, args, msg, next) {
    spawn(cmd, args).on('exit', function (code) {
      return code
        ? next(new Error(msg))
        : next();
    });
  }

  async.parallel([
    async.apply(
      runFs,
      'chown',
      ['-R', 'solenoid:nogroup', options.runDir],
      'Unable to grab ownership for ' + options.runDir
    ),
    async.apply(
      runFs,
      'chmod',
      ['-R', '777', options.runDir],
      'Unable to change permissions for ' + options.runDir
    )
  ], callback);
};

var startApp = exports.startApp = function startApp(options, callback) {
  var startLog = path.join(options.runDir, 'start.log'),
      maxRetries = options.retries || 3,
      timeout = options.retryTimeout || 500,
      logger = options.logger,
      responded = false,
      retries = 0,
      args = [],
      pid = '',
      env = {},
      nodeModulesBin,
      backupPath,
      initPath,
      start,
      child,
      tail;

  logger.info('Starting application...');

  //
  // Set the node_modules .bin path to be set in various locations
  //
  nodeModulesBin = path.join(options.snapshotPath, 'package', 'node_modules', '.bin');

  //
  // Setup the `aeternum` arguments.
  //
  args = ['start', '--min-uptime', options.minUptime, '-o', path.join(options.runDir, 'forza.log'), '--', 'forza'];

  //
  // Setup `forza` arguments.
  //
  args.push('-h', options.instruments.host);
  args.push('-p', (options.instruments.port || 8556).toString());

  args.push('--start-log', startLog);
  args.push('--app-user', options.app.user);
  args.push('--app-name', options.app.name);
  args.push('--');

  //
  // Merge the env with `app.env` and `process.env`.
  //
  [process.env, options.app.env].forEach(function (obj) {
    if (!obj || typeof obj !== 'object') { return }
    Object.keys(obj).forEach(function (key) {
      env[key] = obj[key];
    });
  });

  env.PATH = [nodeModulesBin]
    .concat(options.enginePaths)
    .concat(env.PATH.split(':'))
    .join(':');

  //
  // Remark: we have to do custom detection of coffee-script as it needs to be
  // prepended with node (#!/usr/bin/env node is not intelligent enough)
  //
  start = options['package.json'].scripts.start.split(' ')

  //
  // Set possible path locations where a coffee binary would live and replace
  // 'coffee' with one of these paths
  //
  if (start[0] === 'coffee') {
    initPath = path.resolve(nodeModulesBin, start[0]);
    backupPath = path.resolve(options.enginePaths[0], start[0]);
    start[0] = fs.existsSync(initPath)
      ? initPath
      : backupPath;

    start.unshift('node');
  }
  else if (start[0] !== 'node') {
    start.unshift('node');
  }

  args.push.apply(args, start);
  uidNumber('solenoid', 'nogroup', function (err, uid, gid) {
    if (err) {
      //
      // Remark: should we allow for errors here?
      //
      return callback(new Error('Could not get uid/gid of child process.'));
    }

    //
    // ### function done (err)
    // Responds once to the callback
    //
    function done(err) {
      if (!responded) {
        responded = true;
        callback.apply(null, arguments);
      }
    }

    //
    // ### function awaitStart ()
    // Writes `options.pidFile` and tails the `forza`
    // start log for the start event.
    //
    function awaitStart() {
      async.series([
        function writePid(next) {
          logger.info('Writing pidfile: ' + options.pidFile);
          fs.writeFile(options.pidFile, pid, next.bind(null, null));
        },
        function tailLog(next) {
          var allLog = '',
              json;

          //
          // Helper function which attempts to respawn
          // the `tail` process in the (rare) case
          // that forza has not already written to it.
          //
          function retry(err) {
            if (++retries < maxRetries) {
              logger.info('Error tailing forza log: ' + err.message);
              logger.info('Retrying the tail.');

              setTimeout(function () {
                tailLog(next);
              }, timeout);
              return;
            }

            next(err);
          }

          logger.info('Tailing forza log: ' + startLog);
          tail = spawn('tail', [ startLog ]);
          tail.on('error', retry);

          //
          // Remark: use close event so we ensure we got all possible data out
          // of the streams
          //
          tail.on('close', function (code, signal) {
            logger.info('Tail closing..');
            //
            // Remark: tail.kill() sends sigterm so ensure we have the json and
            // we killed it appropriately
            //
            if (typeof json !== 'undefined' || signal === 'SIGTERM') {
              return next();
            }

            retry(new Error('tailing start log exited poorly with code ' + code || signal))
          });

          tail.stdout.on('data', function (data) {
            allLog += data;

            try { json = JSON.parse(allLog) }
            catch (ex) { return }

            // Use console.log to ensure it is JSON parseable
            console.log(JSON.stringify(json));

            try { tail.kill() }
            catch (ex) { }
          });
        }
      ], done);
    }

    logger.info('Spawn: ' + args.join(' '));
    child = spawn('aeternum', args, {
      cwd: path.join(options.snapshotPath, 'package'),
      env: env,
      uid: uid,
      gid: gid
    });

    child.on('error', done);
    child.stdout.on('data', function (chunk) {
      pid += chunk.toString('utf8');
    });

    child.stdout.on('end', function () {
      if (!responded) {
        pid = parseInt(pid, 10).toString();
        logger.info('`aeternum` pid: ' + pid);
        awaitStart();
      }
    });
  });
};
<|endoftext|>