<commit_before>'use babel';
/* @flow */

import child_process from 'child_process';
import log4js from 'log4js';
import fs from 'fs';
import path from 'path';

const logger = log4js.getLogger('installer');
logger.setLevel('ERROR');

export var config = {
	lovePath: {
		title: 'Path to Love Executable',
		description: `This should be the full path to the LOVE executable.
On OSX, this is likely \`/Applications/love.app/Contents/MacOS/love\`.
On Windows, this is likely \`C:\\Program Files (x86)\\LOVE\\love.exe\`
Leave blank to use the executable found in the PATH.`,
		type: 'string',
		default: '',
		order: 1,
	},
	additionalArgs: {
		title: 'Additional Arguments',
		description: `Put any additional arguments to the love executable here. The
executable will be invoked with \`"\${lovePath}" . \${additionalArgs}\`, with the project
directory as the current working directory.`,
		type: 'string',
		default: '',
		order: 2,
	},
	terminalEmulator: {
		title: 'Run In Terminal Emulator',
		description: `When running your Love game, create a terminal emulator
		window, and show the output to that window.`,
		type: 'string',
		default: 'None',
		enum: ['None', 'iTerm'],
		order: 3,
	}
}

export function activate () {
	require('atom-package-deps').install('love-ide');
}

function run() {
	// Find all the directories that have a main.lua in them.
	var dirs = atom.project.getDirectories().filter(dir =>
		dir.getFile('main.lua').existsSync());

	// No directories were found.
	if(dirs.length == 0) {
		atom.notifications.addError("None of the project directories have a main.lua");
		return;
	}

	// Prioritize the directory of the currently active editor.
	const activeEditor = atom.workspace.getActiveTextEditor();
	dirs.sort((a, b) => {
		if (a.contains(activeEditor.getPath())) return -1;
		if (b.contains(activeEditor.getPath())) return 1;
		else return 0;
	});

	var lovePath = atom.config.get('love-ide.lovePath') || 'love';
	var additionalArgs = atom.config.get('love-ide.additionalArgs');
	var terminalEmulator = atom.config.get('love-ide.terminalEmulator');

	switch (terminalEmulator) {
		case 'None':
			child_process.exec(`"${lovePath}" . ${additionalArgs}`, {cwd: dirs[0].getPath()}, (err, stdout, stderr) => {
				if(err) {
					var message = stderr.toString();
					if (err.code == 127) message = "LOVE executable not found. Try setting the PATH in the love-ide settings menu.";
					atom.notifications.addError('Error running LOVE.', {
						detail: message
					});
				}
			});
			break;
		default:
			atom.notifications.addError(`Unsupported terminal emulator ${terminalEmulator}.`);
	}
}

atom.commands.add('atom-text-editor', 'love-ide:run-love', run);

var toolBarSection = null;
export function consumeToolBar(toolBar: ToolBar) {
	logger.trace('Setting up toolbar.');

	toolBarSection = toolBar('love-ide');
	var runButton = toolBarSection.addButton({
		icon: 'play',
		tooltip: 'Run Love App',
		iconset: 'ion',
		callback: 'love-ide:run-love',
	});
}

export function deactivate() {
	if (toolBarSection) {
		toolBarSection.removeItems();
	}
}
<commit_msg>Added option to launch Love game with CMD.exe - Fixes #15<commit_after>'use babel';
/* @flow */

import child_process from 'child_process';
import log4js from 'log4js';
import fs from 'fs';
import path from 'path';

const logger = log4js.getLogger('installer');
logger.setLevel('ERROR');

export var config = {
	lovePath: {
		title: 'Path to Love Executable',
		description: `This should be the full path to the LOVE executable.
On OSX, this is likely \`/Applications/love.app/Contents/MacOS/love\`.
On Windows, this is likely \`C:\\Program Files (x86)\\LOVE\\love.exe\`
Leave blank to use the executable found in the PATH.`,
		type: 'string',
		default: '',
		order: 1,
	},
	additionalArgs: {
		title: 'Additional Arguments',
		description: `Put any additional arguments to the love executable here. The
executable will be invoked with \`"\${lovePath}" . \${additionalArgs}\`, with the project
directory as the current working directory.`,
		type: 'string',
		default: '',
		order: 2,
	},
	terminalEmulator: {
		title: 'Run In Terminal Emulator',
		description: `When running your Love game, create a terminal emulator
		window, and show the output to that window.`,
		type: 'string',
		default: 'None',
		enum: ['None', 'CMD (Windows)'],
		order: 3,
	}
}

export function activate () {
	require('atom-package-deps').install('love-ide');
}

function run() {
	// Find all the directories that have a main.lua in them.
	var dirs = atom.project.getDirectories().filter(dir =>
		dir.getFile('main.lua').existsSync());

	// No directories were found.
	if(dirs.length == 0) {
		atom.notifications.addError("None of the project directories have a main.lua");
		return;
	}

	// Prioritize the directory of the currently active editor.
	const activeEditor = atom.workspace.getActiveTextEditor();
	dirs.sort((a, b) => {
		if (a.contains(activeEditor.getPath())) return -1;
		if (b.contains(activeEditor.getPath())) return 1;
		else return 0;
	});

	var lovePath = atom.config.get('love-ide.lovePath') || 'love';
	var additionalArgs = atom.config.get('love-ide.additionalArgs');
	var terminalEmulator = atom.config.get('love-ide.terminalEmulator');

	var command = `"${lovePath}" . ${additionalArgs}`;
	switch (terminalEmulator) {
		case 'None':
			child_process.exec(command, {cwd: dirs[0].getPath()}, (err, stdout, stderr) => {
				if(err) {
					var message = stderr.toString();
					if (err.code == 127) message = "LOVE executable not found. Try setting the PATH in the love-ide settings menu.";
					atom.notifications.addError('Error running LOVE.', {
						detail: message
					});
				}
			});
			break;
		case 'CMD (Windows)':
			child_process.exec(`start cmd.exe @cmd /c "${command}"`, {cwd: dirs[0].getPath()}, (err, stdout, stderr) => {
				if(err) {
					var message = stderr.toString();
					if (err.code == 127) message = "LOVE executable not found. Try setting the PATH in the love-ide settings menu.";
					atom.notifications.addError('Error running LOVE.', {
						detail: message
					});
				}
			});
			break;
		default:
			atom.notifications.addError(`Unsupported terminal emulator ${terminalEmulator}.`);
	}
}

atom.commands.add('atom-text-editor', 'love-ide:run-love', run);

var toolBarSection = null;
export function consumeToolBar(toolBar: ToolBar) {
	logger.trace('Setting up toolbar.');

	toolBarSection = toolBar('love-ide');
	var runButton = toolBarSection.addButton({
		icon: 'play',
		tooltip: 'Run Love App',
		iconset: 'ion',
		callback: 'love-ide:run-love',
	});
}

export function deactivate() {
	if (toolBarSection) {
		toolBarSection.removeItems();
	}
}
<|endoftext|>


<commit_before>'use strict';

angular.module('registryApp')
    .controller('BuildCtrl', ['$scope', '$routeParams', '$window', '$interval', '$document', '$timeout', 'Build', 'Header', function ($scope, $routeParams, $window, $interval, $document, $timeout, Build, Header) {

        var logIntervalId;
        var scrollTimeoutId;

        Header.setActive('builds');

        $scope.view = {};
        $scope.view.loading = true;
        $scope.view.build = null;
        $scope.view.tab = angular.isUndefined($routeParams.tab) ? 'details': $routeParams.tab;

        /* get the build details */
        Build.getBuild($routeParams.id).then(function(result) {

            $scope.view.build = result;

            /* and if in log tab */
            if ($routeParams.tab === 'log') {

                $scope.view.log = [];
                $scope.view.contentLength = 0;

                /* start log polling if build is running */
                if (result.status === 'running') {

                    console.log('log polling started');

                    $scope.view.loading = false;

                    logIntervalId = $interval(function() {
                        Build.getLog($routeParams.id, $scope.view.contentLength).then(logLoaded);
                    }, 2000);

                } else {
                    /* other than that take the log for the current build */
                    Build.getLog($routeParams.id, 0).then(function(result) {
                        $scope.view.loading = false;
                        $scope.view.log = $scope.view.log.concat(result.content.split('\n'));
                    });
                }
            } else {
                $scope.view.loading = false;
            }
        });

        /**
         * Go back to the previous screen
         */
        $scope.goBack = function () {
            $window.history.back();
        };

        /**
         * Callback when log for the build is loaded
         *
         * @param result
         */
        var logLoaded = function(result) {

            if (result.status !== 'running') {
                $scope.stopLogInterval();
            }

            $scope.view.build.status = result.status;

            console.log('log polling at ', $scope.view.contentLength);

            if (result.contentLength > 0) {
                $scope.view.log = $scope.view.log.concat(result.content.split('\n'));
                $scope.view.contentLength += result.contentLength;

                $scope.stopScrollTimeout();

                var logContainer = $document[0].getElementById('log-content');
                scrollTimeoutId = $timeout(function () {
                    logContainer.scrollTop = logContainer.scrollHeight;
                }, 100);
            }

        };

        /**
         * Stop the log polling
         */
        $scope.stopLogInterval = function() {
            if (angular.isDefined(logIntervalId)) {
                $interval.cancel(logIntervalId);
                logIntervalId = undefined;
                console.log('log polling canceled');
            }
        };

        /**
         * Stop the scroll timeout
         */
        $scope.stopScrollTimeout = function() {
            if (angular.isDefined(scrollTimeoutId)) {
                $timeout.cancel(scrollTimeoutId);
                scrollTimeoutId = undefined;
            }
        };

        $scope.$on('$destroy', function() {
            $scope.stopLogInterval();
            $scope.stopScrollTimeout();
        });

    }]);
<commit_msg>parse as int the content length<commit_after>'use strict';

angular.module('registryApp')
    .controller('BuildCtrl', ['$scope', '$routeParams', '$window', '$interval', '$document', '$timeout', 'Build', 'Header', function ($scope, $routeParams, $window, $interval, $document, $timeout, Build, Header) {

        var logIntervalId;
        var scrollTimeoutId;

        Header.setActive('builds');

        $scope.view = {};
        $scope.view.loading = true;
        $scope.view.build = null;
        $scope.view.tab = angular.isUndefined($routeParams.tab) ? 'details': $routeParams.tab;

        /* get the build details */
        Build.getBuild($routeParams.id).then(function(result) {

            $scope.view.build = result;

            /* and if in log tab */
            if ($routeParams.tab === 'log') {

                $scope.view.log = [];
                $scope.view.contentLength = 0;

                /* start log polling if build is running */
                if (result.status === 'running') {

                    console.log('log polling started');

                    $scope.view.loading = false;

                    logIntervalId = $interval(function() {
                        Build.getLog($routeParams.id, $scope.view.contentLength).then(logLoaded);
                    }, 2000);

                } else {
                    /* other than that take the log for the current build */
                    Build.getLog($routeParams.id, 0).then(function(result) {
                        $scope.view.loading = false;
                        $scope.view.log = $scope.view.log.concat(result.content.split('\n'));
                    });
                }
            } else {
                $scope.view.loading = false;
            }
        });

        /**
         * Go back to the previous screen
         */
        $scope.goBack = function () {
            $window.history.back();
        };

        /**
         * Callback when log for the build is loaded
         *
         * @param result
         */
        var logLoaded = function(result) {

            if (result.status !== 'running') {
                $scope.stopLogInterval();
            }

            $scope.view.build.status = result.status;

            console.log('log polling at ', $scope.view.contentLength);

            if (result.contentLength > 0) {
                $scope.view.log = $scope.view.log.concat(result.content.split('\n'));
                $scope.view.contentLength += parseInt(result.contentLength, 10);

                $scope.stopScrollTimeout();

                var logContainer = $document[0].getElementById('log-content');
                scrollTimeoutId = $timeout(function () {
                    logContainer.scrollTop = logContainer.scrollHeight;
                }, 100);
            }

        };

        /**
         * Stop the log polling
         */
        $scope.stopLogInterval = function() {
            if (angular.isDefined(logIntervalId)) {
                $interval.cancel(logIntervalId);
                logIntervalId = undefined;
                console.log('log polling canceled');
            }
        };

        /**
         * Stop the scroll timeout
         */
        $scope.stopScrollTimeout = function() {
            if (angular.isDefined(scrollTimeoutId)) {
                $timeout.cancel(scrollTimeoutId);
                scrollTimeoutId = undefined;
            }
        };

        $scope.$on('$destroy', function() {
            $scope.stopLogInterval();
            $scope.stopScrollTimeout();
        });

    }]);
<|endoftext|>


<commit_before>if (typeof window !== 'undefined') {
  var waitSeconds = 100;

  var head = document.getElementsByTagName('head')[0];

  // get all link tags in the page
  var links = document.getElementsByTagName('link');
  var linkHrefs = [];
  for (var i = 0; i < links.length; i++) {
    linkHrefs.push(links[i].href);
  }

  var isWebkit = !!window.navigator.userAgent.match(/AppleWebKit\/([^ ;]*)/);
  var webkitLoadCheck = function(link, callback) {
    setTimeout(function() {
      for (var i = 0; i < document.styleSheets.length; i++) {
        var sheet = document.styleSheets[i];
        if (sheet.href == link.href)
          return callback();
      }
      webkitLoadCheck(link, callback);
    }, 10);
  }

  var noop = function() {}

  var loadCSS = function(url) {
    return new Promise(function(resolve, reject) {
      var timeout = setTimeout(function() {
        reject('Unable to load CSS');
      }, waitSeconds * 1000);
      var _callback = function() {
        clearTimeout(timeout);
        link.onload = noop;
        setTimeout(function() {
          resolve('');
        }, 7);
      }
      var link = document.createElement('link');
      link.type = 'text/css';
      link.rel = 'stylesheet';
      link.href = url;

      if (!isWebkit)
        link.onload = _callback;
      else
        webkitLoadCheck(link, _callback);

      head.appendChild(link);
    });
  }

  exports.fetch = function(load) {
    // dont reload styles loaded in the head
    for (var i = 0; i < linkHrefs.length; i++)
      if (load.address == linkHrefs[i])
        return '';
    return loadCSS(load.address);
  }
}
else {
  exports.fetch = function(load) {
    // individually mark loads as not built for buildCSS false
    if (this.buildCSS === false)
      load.metadata.build = false;
    // setting format = 'defined' means we're managing our own output
    load.metadata.format = 'defined';
    // don't load the CSS at all until build time
    return '';
  }
  exports.bundle = function(loads, opts) {
    var loader = this;
    if (loader.buildCSS === false)
      return '';
    return loader.import('./css-builder', { name: module.id }).then(function(builder) {
      return builder.call(loader, loads, opts);
    });
  }
}
<commit_msg>Propagate CSS load failures.<commit_after>if (typeof window !== 'undefined') {
  var waitSeconds = 100;

  var head = document.getElementsByTagName('head')[0];

  // get all link tags in the page
  var links = document.getElementsByTagName('link');
  var linkHrefs = [];
  for (var i = 0; i < links.length; i++) {
    linkHrefs.push(links[i].href);
  }

  var isWebkit = !!window.navigator.userAgent.match(/AppleWebKit\/([^ ;]*)/);
  var webkitLoadCheck = function(link, callback) {
    setTimeout(function() {
      for (var i = 0; i < document.styleSheets.length; i++) {
        var sheet = document.styleSheets[i];
        if (sheet.href == link.href)
          return callback();
      }
      webkitLoadCheck(link, callback);
    }, 10);
  }

  var noop = function() {}

  var loadCSS = function(url) {
    return new Promise(function(resolve, reject) {
      var timeout = setTimeout(function() {
        reject('Unable to load CSS');
      }, waitSeconds * 1000);
      var _callback = function(error) {
        clearTimeout(timeout);
        link.onload = link.onerror = noop;
        setTimeout(function() {
          if (error)
            reject(error);
          else
            resolve('');
        }, 7);
      }
      var link = document.createElement('link');
      link.type = 'text/css';
      link.rel = 'stylesheet';
      link.href = url;

      if (!isWebkit) {
        link.onload = function() {
          _callback();
        }
        link.onerror = function(event) {
          _callback(event.error);
        }
      } else {
        webkitLoadCheck(link, _callback);
      }

      head.appendChild(link);
    });
  }

  exports.fetch = function(load) {
    // dont reload styles loaded in the head
    for (var i = 0; i < linkHrefs.length; i++)
      if (load.address == linkHrefs[i])
        return '';
    return loadCSS(load.address);
  }
}
else {
  exports.fetch = function(load) {
    // individually mark loads as not built for buildCSS false
    if (this.buildCSS === false)
      load.metadata.build = false;
    // setting format = 'defined' means we're managing our own output
    load.metadata.format = 'defined';
    // don't load the CSS at all until build time
    return '';
  }
  exports.bundle = function(loads, opts) {
    var loader = this;
    if (loader.buildCSS === false)
      return '';
    return loader.import('./css-builder', { name: module.id }).then(function(builder) {
      return builder.call(loader, loads, opts);
    });
  }
}
<|endoftext|>


<commit_before>/* Copyright 2011 Ask Bjørn Hansen, see LICENSE */
"use strict";

var https = require('https');
var querystring = require('querystring');

function setup_response_handler(req, callback) {
    if (typeof callback !== "function") {
        //console.log("missing callback");
        return;
    }
    req.on('response',
        function(res) {
            var response = '';
            res.setEncoding('utf8');
            res.on('data',
                function(chunk) {
                    response += chunk;
            });
            res.on('end',
                function() {
                    var err = null;
                    try {
                        response = JSON.parse(response);
                        if(200 != res.statusCode) {
                            err = new Error(response.error.message);
                            err.name = response.error.type;
                            err.code = response.error.code;
                            err.param = response.error.param;
                            response = null;
                        }
                    }
                    catch(e) {
                        err = new Error("Invalid JSON from stripe.com");
                        response = null;
                    }
                    callback(err, response);
            });
        });
    req.on('error', function(error){
        callback(error);
    });
}

module.exports = function (api_key, options) {
    var defaults = options || {};

    var auth = 'Basic ' + new Buffer(api_key + ":").toString('base64');

    function _request(method, path, data, callback) {

        //console.log("data", typeof data, data);

        // convert first level of deep data structures to foo[bar]=baz syntax
        Object.keys(data).forEach(function(key) {
            if (typeof data[key] === 'object' && data[key] !== null) {
                var o = data[key];
                delete data[key];
                Object.keys(o).forEach(function(k) {
                    var new_key = key + "[" + k + "]";
                    data[new_key] = o[k];
                });
            }
        });

        var request_data = querystring.stringify(data);

        //console.log(method, "request for", path);
        //console.log("http request", request_data);

        var request_options = {
              host: 'api.stripe.com',
              port: '443',
              path: path,
              method: method,
              headers: {
                  'Authorization': auth,
                  'Accept': 'application/json',
                  'Content-Type': 'application/x-www-form-urlencoded',
                  'Content-Length': request_data.length
              }
          };

        var req = https.request(request_options);
        setup_response_handler(req, callback);
        req.write(request_data);
        req.end();
    }

    function post(path, data, callback) {
        _request('POST', path, data, callback);
    }

    function get(path, data, callback) {
        _request('GET', path, data, callback);
    }

    function del(path, data, callback) {
        _request('DELETE', path, data, callback);
    }

    function normalizeArguments() {
        var args = arguments[0];
        if(typeof args[0] == 'object' && typeof args[1] == 'function' && !args[2])
            return { count: args[0].count, offset: args[0].offset, cb: args[1] };
        else
            return { count: args[0], offset: args[1], cb: args[2] };
    }

    return {
        charges: {
            capture: function (charge_id, data, cb) {
                if (typeof data === 'function') {
                    cb = data;
                    data = {};
                }
                post("/v1/charges/" + charge_id + "/capture", data, cb);
            },
            create: function (data, cb) {
                post("/v1/charges", data, cb);
            },
            retrieve: function(charge_id, cb) {
                if(!(charge_id && typeof charge_id === 'string')) {
                    cb("charge_id required");
                }
                get("/v1/charges/" + charge_id, {}, cb);
            },
            refund: function(charge_id, amount, cb) {
                var requestParams = {};
                if(!(charge_id && typeof charge_id === 'string')) {
                    cb("charge_id required");
                }
                if (typeof amount === 'function') {
                    cb = amount;
                    amount = null;
                }
                if (amount) {
                    requestParams.amount = amount;
                }
                post("/v1/charges/" + charge_id + "/refund", requestParams, cb);
            },
            list: function(data, cb) {
                get("/v1/charges", data, cb);
            },
        },
        customers: {
            create: function (data, cb) {
                post("/v1/customers", data, cb);
            },
            retrieve: function(customer_id, cb) {
                if (!(customer_id && typeof customer_id === 'string')) {
                    return cb("customer_id required");
                }
                get("/v1/customers/" + customer_id, {}, cb);
            },
            update: function(customer_id, data, cb) {
                post("/v1/customers/" + customer_id, data, cb);
            },
            del: function(customer_id, cb) {
                del("/v1/customers/" + customer_id, {}, cb);
            },
            list: function(count, offset, cb) {
                var nArgs = normalizeArguments(arguments);
                get("/v1/customers", { count: nArgs.count, offset: nArgs.offset }, nArgs.cb);
            },
            update_subscription: function(customer_id, data, cb) {
                post("/v1/customers/" + customer_id + '/subscription', data, cb);
            },
            cancel_subscription: function(customer_id, at_period_end, cb) {
                del("/v1/customers/" + customer_id + '/subscription', { at_period_end: at_period_end }, cb);
            }
        },
        plans: {
            create: function (data, cb) {
                post("/v1/plans", data, cb);
            },
            retrieve: function(plan_id, cb) {
                if (!(plan_id && typeof plan_id === 'string')) {
                    return cb("plan_id required");
                }
                get("/v1/plans/" + plan_id, {}, cb);
            },
            del: function(plan_id, cb) {
                del("/v1/plans/" + plan_id, {}, cb);
            },
            list: function(count, offset, cb) {
                var nArgs = normalizeArguments(arguments);
                get("/v1/plans", { count: nArgs.count, offset: nArgs.offset }, nArgs.cb);
            },
            update: function (plan_id, data, cb) {
                post("/v1/plans/" + plan_id, data, cb);
            }
        },
        invoices: {
            retrieve: function(invoice_id, cb) {
                get("/v1/invoices/" + invoice_id, {}, cb);
            },
            list: function(data, cb) {
                get("/v1/invoices", data, cb);
            },
            upcoming: function(customer_id, cb) {
                get("/v1/invoices/upcoming", { customer: customer_id }, cb);
            },
        },
        invoice_items: {
            create: function(data, cb) {
                post("/v1/invoiceitems", data, cb);
            },
            retrieve: function(invoice_item_id, cb) {
                if (!(invoice_item_id && typeof invoice_item_id === 'string')) {
                    return cb("invoice_item_id required");
                }
                get("/v1/invoiceitems/" + invoice_item_id, {}, cb);
            },
            update: function(invoice_item_id, data, cb) {
                post("/v1/invoiceitems/" + invoice_item_id, data, cb);
            },
            del: function(invoice_item_id, cb) {
                del("/v1/invoiceitems/" + invoice_item_id, {}, cb);
            },
            list: function(customer_id, count, offset, cb) {
                var nArgs = normalizeArguments({count: count, offset: offset }, cb);
                get("/v1/invoiceitems", { customer: customer_id, count: count, offset: offset}, cb );
            }
        },
        coupons: {
            create: function (data, cb) {
                post("/v1/coupons", data, cb);
            },
            retrieve: function(coupon_id, cb) {
                if (!(coupon_id && typeof coupon_id === 'string')) {
                    cb("coupon_id required");
                }
                get("/v1/coupons/" + coupon_id, {}, cb);
            },
            del: function(coupon_id, cb) {
                del("/v1/coupons/" + coupon_id, {}, cb);
            },
            list: function(count, offset, cb) {
                var nArgs = normalizeArguments(arguments);
                get("/v1/coupons", { count: nArgs.count, offset: nArgs.offset}, nArgs.cb );
            }
        },
        token: {
            create: function (data, cb) {
                post("/v1/tokens", data, cb)
            },
            retrieve: function (token_id, cb) {
                get("/v1/tokens/" + token_id, {}, cb)
            }
        },
        account: {
            retrieve: function (cb) {
                get("/v1/account", {}, cb)
            }
        },
        events: {
            retrieve: function (token_id, cb) {
                get("/v1/events/" + token_id, {}, cb)
            },
            list: function (cb) {
                get("/v1/events/", {}, cb)
            }
        },
    };
}
<commit_msg>add invoice create and invoice pay.<commit_after>/* Copyright 2011 Ask Bjørn Hansen, see LICENSE */
"use strict";

var https = require('https');
var querystring = require('querystring');

function setup_response_handler(req, callback) {
    if (typeof callback !== "function") {
        //console.log("missing callback");
        return;
    }
    req.on('response',
        function(res) {
            var response = '';
            res.setEncoding('utf8');
            res.on('data',
                function(chunk) {
                    response += chunk;
            });
            res.on('end',
                function() {
                    var err = null;
                    try {
                        response = JSON.parse(response);
                        if(200 != res.statusCode) {
                            err = new Error(response.error.message);
                            err.name = response.error.type;
                            err.code = response.error.code;
                            err.param = response.error.param;
                            response = null;
                        }
                    }
                    catch(e) {
                        err = new Error("Invalid JSON from stripe.com");
                        response = null;
                    }
                    callback(err, response);
            });
        });
    req.on('error', function(error){
        callback(error);
    });
}

module.exports = function (api_key, options) {
    var defaults = options || {};

    var auth = 'Basic ' + new Buffer(api_key + ":").toString('base64');

    function _request(method, path, data, callback) {

        //console.log("data", typeof data, data);

        // convert first level of deep data structures to foo[bar]=baz syntax
        Object.keys(data).forEach(function(key) {
            if (typeof data[key] === 'object' && data[key] !== null) {
                var o = data[key];
                delete data[key];
                Object.keys(o).forEach(function(k) {
                    var new_key = key + "[" + k + "]";
                    data[new_key] = o[k];
                });
            }
        });

        var request_data = querystring.stringify(data);

        //console.log(method, "request for", path);
        //console.log("http request", request_data);

        var request_options = {
              host: 'api.stripe.com',
              port: '443',
              path: path,
              method: method,
              headers: {
                  'Authorization': auth,
                  'Accept': 'application/json',
                  'Content-Type': 'application/x-www-form-urlencoded',
                  'Content-Length': request_data.length
              }
          };

        var req = https.request(request_options);
        setup_response_handler(req, callback);
        req.write(request_data);
        req.end();
    }

    function post(path, data, callback) {
        _request('POST', path, data, callback);
    }

    function get(path, data, callback) {
        _request('GET', path, data, callback);
    }

    function del(path, data, callback) {
        _request('DELETE', path, data, callback);
    }

    function normalizeArguments() {
        var args = arguments[0];
        if(typeof args[0] == 'object' && typeof args[1] == 'function' && !args[2])
            return { count: args[0].count, offset: args[0].offset, cb: args[1] };
        else
            return { count: args[0], offset: args[1], cb: args[2] };
    }

    return {
        charges: {
            capture: function (charge_id, data, cb) {
                if (typeof data === 'function') {
                    cb = data;
                    data = {};
                }
                post("/v1/charges/" + charge_id + "/capture", data, cb);
            },
            create: function (data, cb) {
                post("/v1/charges", data, cb);
            },
            retrieve: function(charge_id, cb) {
                if(!(charge_id && typeof charge_id === 'string')) {
                    cb("charge_id required");
                }
                get("/v1/charges/" + charge_id, {}, cb);
            },
            refund: function(charge_id, amount, cb) {
                var requestParams = {};
                if(!(charge_id && typeof charge_id === 'string')) {
                    cb("charge_id required");
                }
                if (typeof amount === 'function') {
                    cb = amount;
                    amount = null;
                }
                if (amount) {
                    requestParams.amount = amount;
                }
                post("/v1/charges/" + charge_id + "/refund", requestParams, cb);
            },
            list: function(data, cb) {
                get("/v1/charges", data, cb);
            },
        },
        customers: {
            create: function (data, cb) {
                post("/v1/customers", data, cb);
            },
            retrieve: function(customer_id, cb) {
                if (!(customer_id && typeof customer_id === 'string')) {
                    return cb("customer_id required");
                }
                get("/v1/customers/" + customer_id, {}, cb);
            },
            update: function(customer_id, data, cb) {
                post("/v1/customers/" + customer_id, data, cb);
            },
            del: function(customer_id, cb) {
                del("/v1/customers/" + customer_id, {}, cb);
            },
            list: function(count, offset, cb) {
                var nArgs = normalizeArguments(arguments);
                get("/v1/customers", { count: nArgs.count, offset: nArgs.offset }, nArgs.cb);
            },
            update_subscription: function(customer_id, data, cb) {
                post("/v1/customers/" + customer_id + '/subscription', data, cb);
            },
            cancel_subscription: function(customer_id, at_period_end, cb) {
                del("/v1/customers/" + customer_id + '/subscription', { at_period_end: at_period_end }, cb);
            }
        },
        plans: {
            create: function (data, cb) {
                post("/v1/plans", data, cb);
            },
            retrieve: function(plan_id, cb) {
                if (!(plan_id && typeof plan_id === 'string')) {
                    return cb("plan_id required");
                }
                get("/v1/plans/" + plan_id, {}, cb);
            },
            del: function(plan_id, cb) {
                del("/v1/plans/" + plan_id, {}, cb);
            },
            list: function(count, offset, cb) {
                var nArgs = normalizeArguments(arguments);
                get("/v1/plans", { count: nArgs.count, offset: nArgs.offset }, nArgs.cb);
            },
            update: function (plan_id, data, cb) {
                post("/v1/plans/" + plan_id, data, cb);
            }
        },
        invoices: {
            retrieve: function(invoice_id, cb) {
                get("/v1/invoices/" + invoice_id, {}, cb);
            },
            list: function(data, cb) {
                get("/v1/invoices", data, cb);
            },
            upcoming: function(customer_id, cb) {
                get("/v1/invoices/upcoming", { customer: customer_id }, cb);
            },
            create: function(customer_id, cb) {
                post("/v1/invoices", { customer: customer_id }, cb);
            },
            pay: function(invoice_id, cb) {
                post("/v1/invoices/"+invoice_id+"/pay", {}, cb);
            }
        },
        invoice_items: {
            create: function(data, cb) {
                post("/v1/invoiceitems", data, cb);
            },
            retrieve: function(invoice_item_id, cb) {
                if (!(invoice_item_id && typeof invoice_item_id === 'string')) {
                    return cb("invoice_item_id required");
                }
                get("/v1/invoiceitems/" + invoice_item_id, {}, cb);
            },
            update: function(invoice_item_id, data, cb) {
                post("/v1/invoiceitems/" + invoice_item_id, data, cb);
            },
            del: function(invoice_item_id, cb) {
                del("/v1/invoiceitems/" + invoice_item_id, {}, cb);
            },
            list: function(customer_id, count, offset, cb) {
                var nArgs = normalizeArguments({count: count, offset: offset }, cb);
                get("/v1/invoiceitems", { customer: customer_id, count: count, offset: offset}, cb );
            }
        },
        coupons: {
            create: function (data, cb) {
                post("/v1/coupons", data, cb);
            },
            retrieve: function(coupon_id, cb) {
                if (!(coupon_id && typeof coupon_id === 'string')) {
                    cb("coupon_id required");
                }
                get("/v1/coupons/" + coupon_id, {}, cb);
            },
            del: function(coupon_id, cb) {
                del("/v1/coupons/" + coupon_id, {}, cb);
            },
            list: function(count, offset, cb) {
                var nArgs = normalizeArguments(arguments);
                get("/v1/coupons", { count: nArgs.count, offset: nArgs.offset}, nArgs.cb );
            }
        },
        token: {
            create: function (data, cb) {
                post("/v1/tokens", data, cb)
            },
            retrieve: function (token_id, cb) {
                get("/v1/tokens/" + token_id, {}, cb)
            }
        },
        account: {
            retrieve: function (cb) {
                get("/v1/account", {}, cb)
            }
        },
        events: {
            retrieve: function (token_id, cb) {
                get("/v1/events/" + token_id, {}, cb)
            },
            list: function (cb) {
                get("/v1/events/", {}, cb)
            }
        },
    };
}
<|endoftext|>


<commit_before>var SelectorSolver = require("./selector-solver")

module.exports = {

	config: {
		solveTagsOnly: {
			type: "boolean",
			default: true,
			title: "Solve Tags",
			description: "Solve even if the selector is only the tag with no id and/or class. Enabling this will basically override html-language package, so you could disable that package."
		},

		activeForFileTypes: {
			type: "array",
			default: ["htm", "html", "kit", "shtml", "tmpl", "tpl", "xhtml"],
			title: "File extensions",
			description: "Active for these file extensions",
			items: {
				type: "string"
			}
		},

		closeSelfclosingTags: {
			type: "boolean",
			default: false,
			title: "Close self-closing tags",
			description: "Add a backslash before the end of self-closing tags"
		},

		expandBlockTags: {
			type: "boolean",
			default: false,
			title: "Expand block tags to multiple lines",
			description: "Put end tag on a new line"
		},

		blockTags: {
			type: "array",
			default: ["address", "article", "aside", "audio", "blockquote", "canvas",
			          "dd", "div", "dl", "fieldset", "figcaption", "figure", "footer",
			          "form", "header", "hgroup", "hr", "main", "nav", "noscript",
								"ol", "output", "p", "pre", "section", "table", "tfoot", "ul",
								"video"],
			title: "Block-level elements",
			description: "HTML tags that will be expanded to multiple lines."
		}
	},

	activate: function(state) {
		new SelectorSolver();
	}
};
<commit_msg>Use tabs instead of spaces<commit_after>var SelectorSolver = require("./selector-solver")

module.exports = {

	config: {
		solveTagsOnly: {
			type: "boolean",
			default: true,
			title: "Solve Tags",
			description: "Solve even if the selector is only the tag with no id and/or class. Enabling this will basically override html-language package, so you could disable that package."
		},

		activeForFileTypes: {
			type: "array",
			default: ["htm", "html", "kit", "shtml", "tmpl", "tpl", "xhtml"],
			title: "File extensions",
			description: "Active for these file extensions",
			items: {
				type: "string"
			}
		},

		closeSelfclosingTags: {
			type: "boolean",
			default: false,
			title: "Close self-closing tags",
			description: "Add a backslash before the end of self-closing tags"
		},

		expandBlockTags: {
			type: "boolean",
			default: false,
			title: "Expand block tags to multiple lines",
			description: "Put end tag on a new line"
		},

		blockTags: {
			type: "array",
			default: ["address", "article", "aside", "audio", "blockquote", "canvas",
								"dd", "div", "dl", "fieldset", "figcaption", "figure", "footer",
								"form", "header", "hgroup", "hr", "main", "nav", "noscript",
								"ol", "output", "p", "pre", "section", "table", "tfoot", "ul",
								"video"],
			title: "Block-level elements",
			description: "HTML tags that will be expanded to multiple lines."
		}
	},

	activate: function(state) {
		new SelectorSolver();
	}
};
<|endoftext|>


<commit_before>/**
 * Main entry-point for the amon agent. This agent is meant to run in all
 * zones. It gets config info (checks to run) from its amon-relay in the
 * global zone and emits alarm (to the relay) when a check fails.
 */

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

var log = require('restify').log;

var common = require('amon-common');
var plugins = require('amon-plugins');
var Config = common.Config;

var Notification = require('./lib/notify');

//---- globals

var gChecks = {};
var gConfig;  // Set to an `amon-common.Config` below.
var relaySocket;  // Socket on which to talk to amon-relay.

var opts = {
  'debug': Boolean,
  'config-repository': String,
  'config-file': String,
  'socket': String,
  'poll': Number,
  'tmp': String,
  'help': Boolean
};

var shortOpts = {
  'd': ['--debug'],
  'c': ['--config-repository'],
  'f': ['--config-file'],
  'p': ['--poll'],
  's': ['--socket'],
  't': ['--tmp'],
  'h': ['--help']
};

//---- internal support functions

function usage(code, msg) {
  if (msg) {
    console.error('ERROR: ' + msg);
  }
  console.log('usage: ' + path.basename(process.argv[1]) +
              ' [-hd] [-p polling-period] [-s socket-path-or-port] ' +
              '[-c config-repository] [-t tmp-dir]');
  process.exit(code);
}

function _newCheck(plugin, check, callback) {
  if (!plugin) throw new TypeError('plugin is required');
  if (!check) throw new TypeError('check is required');
  if (!callback) throw new TypeError('callback is required');

  if (!plugin || !plugin.newInstance ||
      !(plugin.newInstance instanceof Function)) {
    log.fatal('Plugin not found in config: %o', check);
    process.exit(1);
    return callback(new Error('NoPluginFound'));
  }

  try {
    var instance = plugin.newInstance({
      id: check.id,
      config: check.config,
      _log: log
    });
    instance.start(function(err) {
      if (err) {
        log.error('Plugin.start (id=%s) failed: %s', check.id, err.stack);
        process.exit(1);
        return callback(err);
      }

      log.info('Created plugin(%s) instance: check=%s', check.urn, check.id);
      return callback(undefined, instance);
    });
  } catch (e) {
    log.error('plugin.newInstance failed: config=%o, error=%s', check, e.stack);
    process.exit(1);
    return callback(e);
  }
}

function _loadChecksFromConfig() {
  gConfig.loadChecks(function(err) {
    if (err) {
      log.error('Unabled to read checks: ' + err);
    }
    log.debug('Loaded checks: %o', gConfig.checks);

    var checks = gConfig.checks;

    function _checkCallback(err, check) {
      if (err) return;

      check._notification = new Notification({
        socket: relaySocket,
        id: check.id
      });
      check.on('alarm', function(status, metrics) {
        check._notification.send(status, metrics, function(err) {
          if (err) {
            log.warn('Failed to send notification: ' + err);
            return;
          }
          log.info('Alarm notification sent for: %s', check.id);
        });
      });

      if (gChecks[checks[i].id]) {
        gChecks[checks[i].id].stop();
        delete gChecks[checks[i].id];
      }
      gChecks[checks[i].id] = check;
      if (++loaded >= checks.length) {
        log.info('All checks loaded');
      }
    }

    var loaded = 0;
    var plugins = gConfig.plugins;
    for (var i = 0; i < checks.length; i++) {
      _newCheck(plugins[checks[i].urn], checks[i], _checkCallback);
    }
  });
}

function _updateConfig(force) {
  log.trace('_updateConfig entered');
  gConfig.update(function(err, updated) {
    if (err) {
      log.warn('update-config: Update of configuration failed: ' + err);
      return;
    }
    if (!updated && !force) {
      log.debug('update-config: No config updates.');
      return;
    }
    log.info('update-config: Updated. Stopping all checks and recreating');
    for (var k in gChecks) {
      if (gChecks.hasOwnProperty(k)) {
        gChecks[k].stop();
        delete gChecks[k];
      }
    }
    _loadChecksFromConfig();
  });
}

//---- mainline

function main() {
  var parsed = nopt(opts, shortOpts, process.argv, 2);

  if (parsed.help) usage(0);
  if (parsed.debug) log.level(log.Level.Debug);
  if (!parsed['config-repository']) usage(1, 'config-repository is required');

  relaySocket = parsed.socket || '/var/run/.joyent_amon.sock';
  var poll = parsed.poll || 60; // default to 1m config update
  var tmpDir = parsed.tmp || '/tmp';

  gConfig = new Config({
    root: parsed['config-repository'],
    socket: relaySocket,
    tmp: tmpDir
  });
  gConfig.log = log;
  gConfig.plugins = plugins;
  log.debug('Using config: %o', gConfig);

  // Update config (from relay/master) every `poll` seconds. Also immediately
  // at startup.
  setInterval(_updateConfig, poll * 1000);
  _updateConfig(true);
}

process.on('uncaughtException', function(e) {
  log.warn('uncaughtException: ' + (e.stack ? e.stack : e));
});

main();
<commit_msg>Refactor. No functional change.<commit_after>/*
 * Copyright 2011 Joyent, Inc.  All rights reserved.
 *
 * Main entry-point for the amon agent. This agent is meant to run in all
 * zones. It gets config info (checks to run) from its amon-relay in the
 * global zone and emits alarm (to the relay) when a check fails.
 */

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

var log = require('restify').log;

var Config = require('amon-common').Config;
var plugins = require('amon-plugins');

var Notification = require('./lib/notify');

//---- globals

var gChecks = {};
var gConfig;  // Set to an `amon-common.Config` below.
var relaySocket;  // Socket on which to talk to amon-relay.

var opts = {
  'debug': Boolean,
  'config-repository': String,
  'config-file': String,
  'socket': String,
  'poll': Number,
  'tmp': String,
  'help': Boolean
};

var shortOpts = {
  'd': ['--debug'],
  'c': ['--config-repository'],
  'f': ['--config-file'],
  'p': ['--poll'],
  's': ['--socket'],
  't': ['--tmp'],
  'h': ['--help']
};

//---- internal support functions

function usage(code, msg) {
  if (msg) {
    console.error('ERROR: ' + msg);
  }
  console.log('usage: ' + path.basename(process.argv[1]) +
              ' [-hd] [-p polling-period] [-s socket-path-or-port] ' +
              '[-c config-repository] [-t tmp-dir]');
  process.exit(code);
}

function _newCheck(plugin, check, callback) {
  if (!plugin) throw new TypeError('plugin is required');
  if (!check) throw new TypeError('check is required');
  if (!callback) throw new TypeError('callback is required');

  if (!plugin || !plugin.newInstance ||
      !(plugin.newInstance instanceof Function)) {
    log.fatal('Plugin not found in config: %o', check);
    process.exit(1);
    return callback(new Error('NoPluginFound'));
  }

  try {
    var instance = plugin.newInstance({
      id: check.id,
      config: check.config,
      _log: log
    });
    instance.start(function(err) {
      if (err) {
        log.error('Plugin.start (id=%s) failed: %s', check.id, err.stack);
        process.exit(1);
        return callback(err);
      }

      log.info('Created plugin(%s) instance: check=%s', check.urn, check.id);
      return callback(undefined, instance);
    });
  } catch (e) {
    log.error('plugin.newInstance failed: config=%o, error=%s', check, e.stack);
    process.exit(1);
    return callback(e);
  }
}

function _loadChecksFromConfig() {
  gConfig.loadChecks(function(err) {
    if (err) {
      log.error('Unabled to read checks: ' + err);
    }
    log.debug('Loaded checks: %o', gConfig.checks);

    var checks = gConfig.checks;

    function _checkCallback(err, check) {
      if (err) return;

      check._notification = new Notification({
        socket: relaySocket,
        id: check.id
      });
      check.on('alarm', function(status, metrics) {
        check._notification.send(status, metrics, function(err) {
          if (err) {
            log.warn('Failed to send notification: ' + err);
            return;
          }
          log.info('Alarm notification sent for: %s', check.id);
        });
      });

      if (gChecks[checks[i].id]) {
        gChecks[checks[i].id].stop();
        delete gChecks[checks[i].id];
      }
      gChecks[checks[i].id] = check;
      if (++loaded >= checks.length) {
        log.info('All checks loaded');
      }
    }

    var loaded = 0;
    var plugins = gConfig.plugins;
    for (var i = 0; i < checks.length; i++) {
      _newCheck(plugins[checks[i].urn], checks[i], _checkCallback);
    }
  });
}

function _updateConfig(force) {
  log.trace('_updateConfig entered');
  gConfig.update(function(err, updated) {
    if (err) {
      log.warn('update-config: Update of configuration failed: ' + err);
      return;
    }
    if (!updated && !force) {
      log.debug('update-config: No config updates.');
      return;
    }
    log.info('update-config: Updated. Stopping all checks and recreating');
    for (var k in gChecks) {
      if (gChecks.hasOwnProperty(k)) {
        gChecks[k].stop();
        delete gChecks[k];
      }
    }
    _loadChecksFromConfig();
  });
}

//---- mainline

function main() {
  var parsed = nopt(opts, shortOpts, process.argv, 2);

  if (parsed.help) usage(0);
  if (parsed.debug) log.level(log.Level.Debug);
  if (!parsed['config-repository']) usage(1, 'config-repository is required');

  relaySocket = parsed.socket || '/var/run/.joyent_amon.sock';
  var poll = parsed.poll || 60; // default to 1m config update
  var tmpDir = parsed.tmp || '/tmp';

  gConfig = new Config({
    root: parsed['config-repository'],
    socket: relaySocket,
    tmp: tmpDir
  });
  gConfig.log = log;
  gConfig.plugins = plugins;
  log.debug('Using config: %o', gConfig);

  // Update config (from relay/master) every `poll` seconds. Also immediately
  // at startup.
  setInterval(_updateConfig, poll * 1000);
  _updateConfig(true);
}

process.on('uncaughtException', function(e) {
  log.warn('uncaughtException: ' + (e.stack ? e.stack : e));
});

main();
<|endoftext|>


<commit_before>var Promise = require('bluebird')
  , models = require('./models')
  , async = require('async')
  , redis = require('redis').createClient

exports.init = function(database) {
  "use strict";

  var pubSub = function() {
  }

  pubSub.newPost = function(postId) {
    return new Promise(function(resolve, reject) {
      models.Post.findById(postId)
        .then(function(post) { return post.getSubscribedTimelineIds() })
        .then(function(timelineIds) {
          return Promise.map(timelineIds, function(timelineId) {
            database.publishAsync('post:new',
                                  JSON.stringify({
                                    postId: postId,
                                    timelineId: timelineId
                                  }))
          })
        })
        .then(function(res) { resolve(res) })
    })
  }

  pubSub.destroyPost = function(postId) {
    return new Promise(function(resolve, reject) {
      models.Post.findById(postId)
        .then(function(post) { return post.getSubscribedTimelineIds() })
        .then(function(timelineIds) {
          return Promise.map(timelineIds, function(timelineId) {
            database.publishAsync('post:destroy',
                                  JSON.stringify({
                                    postId: postId,
                                    timelineId: timelineId
                                  }))
          })
        })
        .then(function(res) { resolve(res) })
    })
  }

  pubSub.updatePost = function(postId) {
    return new Promise(function(resolve, reject) {
      models.Post.findById(postId)
        .then(function(post) { return post.getSubscribedTimelineIds() })
        .then(function(timelineIds) {
          return Promise.map(timelineIds, function(timelineId) {
            database.publishAsync('post:update',
                                  JSON.stringify({
                                    postId: postId,
                                    timelineId: timelineId
                                  }))
          })
        })
        .then(function(res) { resolve(res) })
    })
  }

  pubSub.newComment = function(commentId) {
    return new Promise(function(resolve, reject) {
      models.Comment.findById(commentId).bind({})
        .then(function(comment) {
          this.comment = comment
          return comment.getPost()
        })
        .then(function(post) {
          this.post = post
          return post.getCommentsFriendOfFriendTimelines(this.comment.userId)
        })
        .then(function(timelines) {
          return Promise.map(timelines, function(timeline) {
            database.publishAsync('comment:new',
                                  JSON.stringify({
                                    timelineId: timeline.id,
                                    commentId: commentId
                                  }))
          })
        })
        .then(function() {
          return database.publishAsync('comment:new',
                                       JSON.stringify({
                                         postId: this.post.id,
                                         commentId: commentId
                                       }))
        })
        .then(function(res) { resolve(res) })
    })
  }

  pubSub.destroyComment = function(commentId) {
    return new Promise(function(resolve, reject) {
      models.Comment.findById(commentId).bind({})
        .then(function(comment) {
          this.comment = comment
          return comment.getPost()
        })
        .then(function(post) {
          this.post = post
          return database.publishAsync('comment:destroy',
                                JSON.stringify({
                                  postId: post.id,
                                  commentId: this.comment.id
                                }))
        })
        .then(function(res) { resolve(res) })
    })
  }

  pubSub.updateComment = function(commentId) {
    return new Promise(function(resolve, reject) {
      models.Comment.findById(commentId).bind({})
        .then(function(comment) {
          this.comment = comment
          return comment.getPost()
        })
        .then(function(post) {
          this.post = post
          return database.publishAsync('comment:update',
                                       JSON.stringify({
                                         postId: post.id,
                                         commentId: this.comment.id
                                       }))
        })
        .then(function() { return this.post.getSubscribedTimelineIds() })
        .then(function(timelineIds) {
          return Promise.map(timelineIds, function(timelineId) {
            database.publishAsync('comment:update',
                                  JSON.stringify({
                                    timelineId: timelineId,
                                    commentId: commentId
                                  }))
          })
        })
        .then(function(res) { resolve(res) })
    })
  }

  pubSub.newLike = function(postId, userId) {
    return new Promise(function(resolve, reject) {
      models.Post.findById(postId).bind({})
        .then(function(post) {
          this.post = post
          return post.getLikesFriendOfFriendTimelines(userId)
        })
        .then(function(timelines) {
          return Promise.map(timelines, function(timeline) {
            return database.publishAsync('like:new',
                                  JSON.stringify({
                                    timelineId: timeline.id,
                                    userId: userId,
                                    postId: postId
                                  }))

          })
        })
        .then(function() {
          return database.publishAsync('like:new',
                                       JSON.stringify({
                                         userId: userId,
                                         postId: postId
                                       }))
        })
        .then(function(res) { resolve(res) })
    })
  }

  pubSub.removeLike = function(postId, userId) {
    return new Promise(function(resolve, reject) {
      models.Post.findById(postId).bind({})
        .then(function(post) {
          this.post = post
          return post.getSubscribedTimelineIds()
        })
        .then(function(timelineIds) {
          return Promise.map(timelineIds, function(timelineId) {
            return database.publishAsync('like:remove',
                                  JSON.stringify({
                                    timelineId: timelineId,
                                    userId: userId,
                                    postId: postId
                                  }))
          })
        })
        .then(function() {
          return database.publishAsync('like:remove',
                                       JSON.stringify({
                                         userId: userId,
                                         postId: postId
                                       }))
        })
        .then(function(res) { resolve(res) })
    })
  }

  pubSub.hidePost = function(userId, postId) {
    return new Promise(function(resolve, reject) {
      models.User.findById(userId).bind({})
        .then(function(user) { return user.getRiverOfNewsTimelineId() })
        .then(function(riverOfNewsId) {
          return database.publishAsync('post:hide',
                                       JSON.stringify({
                                         timelineId: riverOfNewsId,
                                         postId: postId
                                       }))
        })
        .then(function(res) { resolve(res) })
    })
  }

  pubSub.unhidePost = function(userId, postId) {
    return new Promise(function(resolve, reject) {
      models.User.findById(userId).bind({})
        .then(function(user) { return user.getRiverOfNewsTimelineId() })
        .then(function(riverOfNewsId) {
          return database.publishAsync('post:unhide',
                                       JSON.stringify({
                                         timelineId: riverOfNewsId,
                                         postId: postId
                                       }))
        })
        .then(function(res) { resolve(res) })
    })
  }

  pubSub.listen = function(server, app) {
    var io = require('socket.io')(server)

    var adapter = require('socket.io-redis')
     , redisPub = redis()
     , redisSub = redis({ detect_buffers: true })

    io.adapter(adapter({
      pubClient: redisPub,
      subClient: redisSub
    }))

    io.sockets.on('connection', function(socket) {
      socket.on('subscribe', function(data) {
        for(var channel in data) {
          if (data[channel]) {
            data[channel].forEach(function(id) {
              if (id) {
                app.logger.info('User has subscribed to ' + id + ' ' + channel)

                socket.join(channel + ':' + id)
              }
            })
          }
        }
      })

      socket.on('unsubscribe', function(data) {
        for(var channel in data) {
          if (data[channel]) {
            data[channel].forEach(function(id) {
              if (id) {
                app.logger.info('User has disconnected from ' + id + ' ' + channel)

                socket.leave(channel + ':' + id)
              }
            })
          }
        }
      })
    })

    var channels = redis()
    channels.subscribe('post:new', 'post:destroy', 'post:update',
                       'comment:new', 'comment:destroy', 'comment:update',
                       'like:new', 'like:remove', 'post:hide', 'post:unhide' )

    // TODO: extract to separate functions
    channels.on('message', function(channel, msg) {
      switch(channel) {
      case 'post:destroy':
        var data = JSON.parse(msg)
        var event = { postId: data.postId }

        io.sockets.in('timeline:' + data.timelineId).emit('post:destroy', event)
        io.sockets.in('post:' + data.postId).emit('post:destroy', event)

        break

      case 'post:new':
      var data = JSON.parse(msg)

        models.Post.findById(data.postId)
          .then(function(post) {
            new models.PostSerializer(post).toJSON(function(err, json) {
              io.sockets.in('timeline:' + data.timelineId).emit('post:new', { post: json })
            })
          })

        break

      case 'post:update':
        var data = JSON.parse(msg)

        models.Post.findById(data.postId)
          .then(function(post) {
            new models.PostSerializer(post).toJSON(function(err, json) {
              io.sockets.in('timeline:' + data.timelineId).emit('post:update', json)
              io.sockets.in('post:' + data.postId).emit('post:update', json)
            })
          })

        break

      case 'comment:new':
        var data = JSON.parse(msg)

        models.Comment.findById(data.commentId)
          .then(function(comment) {
            new models.PubsubCommentSerializer(comment).toJSON(function(err, json) {
              if (data.timelineId) {
                io.sockets.in('timeline:' + data.timelineId).emit('comment:new', json)
              } else {
                io.sockets.in('post:' + data.postId).emit('comment:new', json)
              }
            })
          })

        break

      case 'comment:update':
        var data = JSON.parse(msg)

        models.Comment.findById(data.commentId)
          .then(function(comment) {
            new models.PubsubCommentSerializer(comment).toJSON(function(err, json) {
              if (data.timelineId) {
                io.sockets.in('timeline:' + data.timelineId).emit('comment:update', json)
              } else {
                io.sockets.in('post:' + data.postId).emit('comment:update', json)
              }
            })
          })

        break

      case 'comment:destroy':
        var data = JSON.parse(msg)
        var event = { postId: data.postId, commentId: data.commentId }

        io.sockets.in('post:' + data.postId).emit('comment:destroy', event)

        models.Post.findById(data.postId)
          .then(function(post) {
            return post.getTimelineIds()
          })
          .then(function(timelineIds) {
            return Promise.map(timelineIds, function(timelineId) {
              return io.sockets.in('timeline:' + timelineId).emit('comment:destroy', event)
            })
          })

        break

      case 'like:new':
        var data = JSON.parse(msg)

        models.User.findById(data.userId)
          .then(function(user) {
            new models.LikeSerializer(user).toJSON(function(err, json) {
              var event = json
              event.meta = { postId: data.postId }

              if (data.timelineId) {
                io.sockets.in('timeline:' + data.timelineId).emit('like:new', event)
              } else {
                io.sockets.in('post:' + data.postId).emit('like:new', event)
              }
            })
          })

        break

      case 'like:remove':
        var data = JSON.parse(msg)
        var event = { meta: { userId: data.userId, postId: data.postId } }

        if (data.timelineId)
          io.sockets.in('timeline:' + data.timelineId).emit('like:remove', event)
        else
          io.sockets.in('post:' + data.postId).emit('like:remove', event)

        break

      case 'post:hide':
        // NOTE: posts are hidden only on RiverOfNews timeline so this
        // event won't leak any personal information
        var data = JSON.parse(msg)
        var event = { meta: { postId: data.postId } }
        io.sockets.in('timeline:' + data.timelineId).emit('post:hide', event)

        break

      case 'post:unhide':
        // NOTE: posts are hidden only on RiverOfNews timeline so this
        // event won't leak any personal information
        var data = JSON.parse(msg)
        var event = { meta: { postId: data.postId } }
        io.sockets.in('timeline:' + data.timelineId).emit('post:unhide', event)

        break
      }
    })
  }

  return pubSub
}
<commit_msg>Does not embed pubsub post:new json into root element.<commit_after>var Promise = require('bluebird')
  , models = require('./models')
  , async = require('async')
  , redis = require('redis').createClient

exports.init = function(database) {
  "use strict";

  var pubSub = function() {
  }

  pubSub.newPost = function(postId) {
    return new Promise(function(resolve, reject) {
      models.Post.findById(postId)
        .then(function(post) { return post.getSubscribedTimelineIds() })
        .then(function(timelineIds) {
          return Promise.map(timelineIds, function(timelineId) {
            database.publishAsync('post:new',
                                  JSON.stringify({
                                    postId: postId,
                                    timelineId: timelineId
                                  }))
          })
        })
        .then(function(res) { resolve(res) })
    })
  }

  pubSub.destroyPost = function(postId) {
    return new Promise(function(resolve, reject) {
      models.Post.findById(postId)
        .then(function(post) { return post.getSubscribedTimelineIds() })
        .then(function(timelineIds) {
          return Promise.map(timelineIds, function(timelineId) {
            database.publishAsync('post:destroy',
                                  JSON.stringify({
                                    postId: postId,
                                    timelineId: timelineId
                                  }))
          })
        })
        .then(function(res) { resolve(res) })
    })
  }

  pubSub.updatePost = function(postId) {
    return new Promise(function(resolve, reject) {
      models.Post.findById(postId)
        .then(function(post) { return post.getSubscribedTimelineIds() })
        .then(function(timelineIds) {
          return Promise.map(timelineIds, function(timelineId) {
            database.publishAsync('post:update',
                                  JSON.stringify({
                                    postId: postId,
                                    timelineId: timelineId
                                  }))
          })
        })
        .then(function(res) { resolve(res) })
    })
  }

  pubSub.newComment = function(commentId) {
    return new Promise(function(resolve, reject) {
      models.Comment.findById(commentId).bind({})
        .then(function(comment) {
          this.comment = comment
          return comment.getPost()
        })
        .then(function(post) {
          this.post = post
          return post.getCommentsFriendOfFriendTimelines(this.comment.userId)
        })
        .then(function(timelines) {
          return Promise.map(timelines, function(timeline) {
            database.publishAsync('comment:new',
                                  JSON.stringify({
                                    timelineId: timeline.id,
                                    commentId: commentId
                                  }))
          })
        })
        .then(function() {
          return database.publishAsync('comment:new',
                                       JSON.stringify({
                                         postId: this.post.id,
                                         commentId: commentId
                                       }))
        })
        .then(function(res) { resolve(res) })
    })
  }

  pubSub.destroyComment = function(commentId) {
    return new Promise(function(resolve, reject) {
      models.Comment.findById(commentId).bind({})
        .then(function(comment) {
          this.comment = comment
          return comment.getPost()
        })
        .then(function(post) {
          this.post = post
          return database.publishAsync('comment:destroy',
                                JSON.stringify({
                                  postId: post.id,
                                  commentId: this.comment.id
                                }))
        })
        .then(function(res) { resolve(res) })
    })
  }

  pubSub.updateComment = function(commentId) {
    return new Promise(function(resolve, reject) {
      models.Comment.findById(commentId).bind({})
        .then(function(comment) {
          this.comment = comment
          return comment.getPost()
        })
        .then(function(post) {
          this.post = post
          return database.publishAsync('comment:update',
                                       JSON.stringify({
                                         postId: post.id,
                                         commentId: this.comment.id
                                       }))
        })
        .then(function() { return this.post.getSubscribedTimelineIds() })
        .then(function(timelineIds) {
          return Promise.map(timelineIds, function(timelineId) {
            database.publishAsync('comment:update',
                                  JSON.stringify({
                                    timelineId: timelineId,
                                    commentId: commentId
                                  }))
          })
        })
        .then(function(res) { resolve(res) })
    })
  }

  pubSub.newLike = function(postId, userId) {
    return new Promise(function(resolve, reject) {
      models.Post.findById(postId).bind({})
        .then(function(post) {
          this.post = post
          return post.getLikesFriendOfFriendTimelines(userId)
        })
        .then(function(timelines) {
          return Promise.map(timelines, function(timeline) {
            return database.publishAsync('like:new',
                                  JSON.stringify({
                                    timelineId: timeline.id,
                                    userId: userId,
                                    postId: postId
                                  }))

          })
        })
        .then(function() {
          return database.publishAsync('like:new',
                                       JSON.stringify({
                                         userId: userId,
                                         postId: postId
                                       }))
        })
        .then(function(res) { resolve(res) })
    })
  }

  pubSub.removeLike = function(postId, userId) {
    return new Promise(function(resolve, reject) {
      models.Post.findById(postId).bind({})
        .then(function(post) {
          this.post = post
          return post.getSubscribedTimelineIds()
        })
        .then(function(timelineIds) {
          return Promise.map(timelineIds, function(timelineId) {
            return database.publishAsync('like:remove',
                                  JSON.stringify({
                                    timelineId: timelineId,
                                    userId: userId,
                                    postId: postId
                                  }))
          })
        })
        .then(function() {
          return database.publishAsync('like:remove',
                                       JSON.stringify({
                                         userId: userId,
                                         postId: postId
                                       }))
        })
        .then(function(res) { resolve(res) })
    })
  }

  pubSub.hidePost = function(userId, postId) {
    return new Promise(function(resolve, reject) {
      models.User.findById(userId).bind({})
        .then(function(user) { return user.getRiverOfNewsTimelineId() })
        .then(function(riverOfNewsId) {
          return database.publishAsync('post:hide',
                                       JSON.stringify({
                                         timelineId: riverOfNewsId,
                                         postId: postId
                                       }))
        })
        .then(function(res) { resolve(res) })
    })
  }

  pubSub.unhidePost = function(userId, postId) {
    return new Promise(function(resolve, reject) {
      models.User.findById(userId).bind({})
        .then(function(user) { return user.getRiverOfNewsTimelineId() })
        .then(function(riverOfNewsId) {
          return database.publishAsync('post:unhide',
                                       JSON.stringify({
                                         timelineId: riverOfNewsId,
                                         postId: postId
                                       }))
        })
        .then(function(res) { resolve(res) })
    })
  }

  pubSub.listen = function(server, app) {
    var io = require('socket.io')(server)

    var adapter = require('socket.io-redis')
     , redisPub = redis()
     , redisSub = redis({ detect_buffers: true })

    io.adapter(adapter({
      pubClient: redisPub,
      subClient: redisSub
    }))

    io.sockets.on('connection', function(socket) {
      socket.on('subscribe', function(data) {
        for(var channel in data) {
          if (data[channel]) {
            data[channel].forEach(function(id) {
              if (id) {
                app.logger.info('User has subscribed to ' + id + ' ' + channel)

                socket.join(channel + ':' + id)
              }
            })
          }
        }
      })

      socket.on('unsubscribe', function(data) {
        for(var channel in data) {
          if (data[channel]) {
            data[channel].forEach(function(id) {
              if (id) {
                app.logger.info('User has disconnected from ' + id + ' ' + channel)

                socket.leave(channel + ':' + id)
              }
            })
          }
        }
      })
    })

    var channels = redis()
    channels.subscribe('post:new', 'post:destroy', 'post:update',
                       'comment:new', 'comment:destroy', 'comment:update',
                       'like:new', 'like:remove', 'post:hide', 'post:unhide' )

    // TODO: extract to separate functions
    channels.on('message', function(channel, msg) {
      switch(channel) {
      case 'post:destroy':
        var data = JSON.parse(msg)
        var event = { postId: data.postId }

        io.sockets.in('timeline:' + data.timelineId).emit('post:destroy', event)
        io.sockets.in('post:' + data.postId).emit('post:destroy', event)

        break

      case 'post:new':
      var data = JSON.parse(msg)

        models.Post.findById(data.postId)
          .then(function(post) {
            new models.PostSerializer(post).toJSON(function(err, json) {
              io.sockets.in('timeline:' + data.timelineId).emit('post:new', json)
            })
          })

        break

      case 'post:update':
        var data = JSON.parse(msg)

        models.Post.findById(data.postId)
          .then(function(post) {
            new models.PostSerializer(post).toJSON(function(err, json) {
              io.sockets.in('timeline:' + data.timelineId).emit('post:update', json)
              io.sockets.in('post:' + data.postId).emit('post:update', json)
            })
          })

        break

      case 'comment:new':
        var data = JSON.parse(msg)

        models.Comment.findById(data.commentId)
          .then(function(comment) {
            new models.PubsubCommentSerializer(comment).toJSON(function(err, json) {
              if (data.timelineId) {
                io.sockets.in('timeline:' + data.timelineId).emit('comment:new', json)
              } else {
                io.sockets.in('post:' + data.postId).emit('comment:new', json)
              }
            })
          })

        break

      case 'comment:update':
        var data = JSON.parse(msg)

        models.Comment.findById(data.commentId)
          .then(function(comment) {
            new models.PubsubCommentSerializer(comment).toJSON(function(err, json) {
              if (data.timelineId) {
                io.sockets.in('timeline:' + data.timelineId).emit('comment:update', json)
              } else {
                io.sockets.in('post:' + data.postId).emit('comment:update', json)
              }
            })
          })

        break

      case 'comment:destroy':
        var data = JSON.parse(msg)
        var event = { postId: data.postId, commentId: data.commentId }

        io.sockets.in('post:' + data.postId).emit('comment:destroy', event)

        models.Post.findById(data.postId)
          .then(function(post) {
            return post.getTimelineIds()
          })
          .then(function(timelineIds) {
            return Promise.map(timelineIds, function(timelineId) {
              return io.sockets.in('timeline:' + timelineId).emit('comment:destroy', event)
            })
          })

        break

      case 'like:new':
        var data = JSON.parse(msg)

        models.User.findById(data.userId)
          .then(function(user) {
            new models.LikeSerializer(user).toJSON(function(err, json) {
              var event = json
              event.meta = { postId: data.postId }

              if (data.timelineId) {
                io.sockets.in('timeline:' + data.timelineId).emit('like:new', event)
              } else {
                io.sockets.in('post:' + data.postId).emit('like:new', event)
              }
            })
          })

        break

      case 'like:remove':
        var data = JSON.parse(msg)
        var event = { meta: { userId: data.userId, postId: data.postId } }

        if (data.timelineId)
          io.sockets.in('timeline:' + data.timelineId).emit('like:remove', event)
        else
          io.sockets.in('post:' + data.postId).emit('like:remove', event)

        break

      case 'post:hide':
        // NOTE: posts are hidden only on RiverOfNews timeline so this
        // event won't leak any personal information
        var data = JSON.parse(msg)
        var event = { meta: { postId: data.postId } }
        io.sockets.in('timeline:' + data.timelineId).emit('post:hide', event)

        break

      case 'post:unhide':
        // NOTE: posts are hidden only on RiverOfNews timeline so this
        // event won't leak any personal information
        var data = JSON.parse(msg)
        var event = { meta: { postId: data.postId } }
        io.sockets.in('timeline:' + data.timelineId).emit('post:unhide', event)

        break
      }
    })
  }

  return pubSub
}
<|endoftext|>