<commit_before>define(['require', 'exports'], function(require, exports) {
	var defaultData = exports.defaultData = {
		root: parentify(nameify({
			name: 'FILESYSTEM_ROOT_/',
			files: {
				home: {
					files: {
						user: {
							files: {
								'README.md': {
									contents: ''
								}
							}
						}
					}
				}
			}
		}))
	};

	function clone(o) {
		function cloned() {}
		cloned.prototype = o;
		return new cloned;
	}

	var Filesystem = exports.Filesystem = (function() {
		function Filesystem(data) {
			this.data = nameify(parentify(data || clone(defaultData)));
			this.currentDir = this.data.root;
		}

		//var currentDir = exports.currentDir = fs.root;

		Filesystem.prototype.getFile = function getFile(path, curDir) {
				var tmpDir, pathArr, self;

				if(!curDir) curDir = this.currentDir;
				if(!path || path.length == 0) return curDir;
				if(path.length > 0 && path[0] == '/') curDir = this.data.root;

				self = this
				tmpDir = curDir;
				pathArr = path.split('/');

				pathArr.forEach(function(part) {
					if(part) {
						if(part == '..') {
							tmpDir = tmpDir.parent || tmpDir;
						} else if(part == '.') {
							return;
						} else if(self.isDir(tmpDir)) {
							if(self.hasFile(tmpDir, part)) tmpDir = tmpDir.files[part];
							else throw new Error("FileNotFoundError: Can not find file: '" +
								part +
								"' in directory: '" +
								self.pathTo(tmpDir));
							if(self.isSymlink(tmpDir)) {
								tmpDir = self.getSymlink(tmpDir);
							}
						} else {
							return false;
						}
					}
				});

				return tmpDir;
		};

		Filesystem.prototype.pathTo = function pathTo(file, /* internal */ isNested) {
			if(!isNested && file.name == this.data.root.name) return '/';
			if(!!file === false || (!!file && !!file.name && file.name == fs.root.name)) {
				return "";
			}

			return this.pathTo(file.parent, true) + '/' + file.name;
		};

		Filesystem.prototype.changeDir = function changeDir(dir) {
			if(dir && this.isDir(dir)) this.currentDir = dir;

			return dir;
		}

		Filesystem.prototype.createFile = function createFile(fileName, curDir) {
			var split, dir;

			if(!curDir) curDir = this.currentDir;

			split = fileName.split('/');
			dir = this.getFile(split.slice(0, split.length - 2).join('/'), curDir);

			console.log('dir:', dir);

			if(!this.hasFile(dir, split[split.length - 1])) {
				return dir.files[split[split.length - 1]] = {
					name: split[split.length - 1]
				};
			}
		};

		Filesystem.prototype.getSymlink = function getSymlink(file, curDir) {
			if(this.isSymlink(file)) return this.getFile(file.symlink, curDir);

			return file;
		}

		Filesystem.prototype.writeData = function writeData(file, data) {
			if(file && data) file.contents = data;

			return file;
		};

		Filesystem.prototype.initDir = function initDir(file) {
			if(file && !file.files) file.files = {};

			return file;
		};

		Filesystem.prototype.symlink = function symlink(file, where) {
			file.symlink = where;

			return file;
		};

		Filesystem.prototype.readFile = function readFile(file) {
			if(!file) return undefined;

			file = this.getSymlink(file);

			if(file && this.isFile(file)) return file.contents;
		}

		Filesystem.prototype.listFiles = function listFiles(dir) {
			dir = dir || this.currentDir;

			if(!this.isDir(dir)) return undefined;

			return Object.keys(dir.files).map(function(name) {
				return dir.files[name];
			});
		}

		Filesystem.prototype.hasFile = function hasFile(dir, name) {
			return dir && dir.files && dir.files[name];
		};

		Filesystem.prototype.isDir = function isDir(file) {
			return file && file.files;
		};

		Filesystem.prototype.isFile = function isFile(file) {
			return file && file.contents !== null && file.contents !== undefined;
		};

		Filesystem.prototype.isSymlink = function isSymlink(file) {
			return file && file.symlink;
		}

		return Filesystem;
	})();

	function parentify(data) {
		for(var key in data.files) {
			data.files[key].parent = data;

			if(data.files[key].files) data.files[key] = parentify(data.files[key]);
		}

		return data;
	}

	function nameify(data) {
		for(var key in data.files) {
			data.files[key].name = key;

			if(data.files[key].files) data.files[key] = nameify(data.files[key]);
		}

		return data;
	}
});
<commit_msg>Adding executable capabilities<commit_after>define(['require', 'exports'], function(require, exports) {
	var defaultData = exports.defaultData = {
		root: parentify(nameify({
			name: 'FILESYSTEM_ROOT_/',
			files: {
				home: {
					files: {
						user: {
							files: {
								'README.md': {
									contents: ''
								}
							}
						}
					}
				}
			}
		}))
	};

	function clone(o) {
		function cloned() {}
		cloned.prototype = o;
		return new cloned;
	}

	var Filesystem = exports.Filesystem = (function() {
		function Filesystem(data) {
			this.data = nameify(parentify(data || clone(defaultData)));
			this.currentDir = this.data.root;
		}

		//var currentDir = exports.currentDir = fs.root;

		Filesystem.prototype.getFile = function getFile(path, curDir) {
				var tmpDir, pathArr, self;

				if(!curDir) curDir = this.currentDir;
				if(!path || path.length == 0) return curDir;
				if(path.length > 0 && path[0] == '/') curDir = this.data.root;

				self = this
				tmpDir = curDir;
				pathArr = path.split('/');

				pathArr.forEach(function(part) {
					if(part) {
						if(part == '..') {
							tmpDir = tmpDir.parent || tmpDir;
						} else if(part == '.') {
							return;
						} else if(self.isDir(tmpDir)) {
							if(self.hasFile(tmpDir, part)) tmpDir = tmpDir.files[part];
							else throw new Error("FileNotFoundError: Can not find file: '" +
								part +
								"' in directory: '" +
								self.pathTo(tmpDir));
							if(self.isSymlink(tmpDir)) {
								tmpDir = self.getSymlink(tmpDir);
							}
						} else {
							return false;
						}
					}
				});

				return tmpDir;
		};

		Filesystem.prototype.pathTo = function pathTo(file, /* internal */ isNested) {
			if(!isNested && file.name == this.data.root.name) return '/';
			if(!!file === false || (!!file && !!file.name && file.name == fs.root.name)) {
				return "";
			}

			return this.pathTo(file.parent, true) + '/' + file.name;
		};

		Filesystem.prototype.changeDir = function changeDir(dir) {
			if(dir && this.isDir(dir)) this.currentDir = dir;

			return dir;
		}

		Filesystem.prototype.createFile = function createFile(fileName, curDir) {
			var split, dir;

			if(!curDir) curDir = this.currentDir;

			split = fileName.split('/');
			dir = this.getFile(split.slice(0, split.length - 2).join('/'), curDir);

			console.log('dir:', dir);

			if(!this.hasFile(dir, split[split.length - 1])) {
				return dir.files[split[split.length - 1]] = {
					name: split[split.length - 1]
				};
			}
		};

		Filesystem.prototype.getSymlink = function getSymlink(file, curDir) {
			if(this.isSymlink(file)) return this.getFile(file.symlink, curDir);

			return file;
		}

		Filesystem.prototype.writeData = function writeData(file, data) {
			if(file && data) file.contents = data;

			return file;
		};

		Filesystem.prototype.initDir = function initDir(file) {
			if(file && !file.files) file.files = {};

			return file;
		};

		Filesystem.prototype.symlink = function symlink(file, where) {
			file.symlink = where;

			return file;
		};

		Filesystem.prototype.readFile = function readFile(file) {
			if(!file) return undefined;

			file = this.getSymlink(file);

			if(file && this.isFile(file)) return file.contents;
		}

		Filesystem.prototype.listFiles = function listFiles(dir) {
			dir = dir || this.currentDir;

			if(!this.isDir(dir)) return undefined;

			return Object.keys(dir.files).map(function(name) {
				return dir.files[name];
			});
		};

		Filesystem.prototype.exec = function exec(file, args, pipes) {
			return "not-implemented";
		};

		Filesystem.prototype.setAsExec = function setAsExec(file) {
			if(file && !this.isDir(file)) file.executable = true;

			return file;
		};

		Filesystem.prototype.hasFile = function hasFile(dir, name) {
			return dir && dir.files && dir.files[name];
		};

		Filesystem.prototype.isDir = function isDir(file) {
			return file && file.files;
		};

		Filesystem.prototype.isFile = function isFile(file) {
			return file && file.contents !== null && file.contents !== undefined;
		};

		Filesystem.prototype.isSymlink = function isSymlink(file) {
			return file && file.symlink;
		}

		Filesystem.prototype.isExec = function isExec(file) {
			return file && file.executable;
		};

		return Filesystem;
	})();

	function parentify(data) {
		for(var key in data.files) {
			data.files[key].parent = data;

			if(data.files[key].files) data.files[key] = parentify(data.files[key]);
		}

		return data;
	}

	function nameify(data) {
		for(var key in data.files) {
			data.files[key].name = key;

			if(data.files[key].files) data.files[key] = nameify(data.files[key]);
		}

		return data;
	}
});
<|endoftext|>


<commit_before>require('autoreleasepool');
module.exports = require('./build/default/bindings.node');

var Application = module.exports.Application
  , Item = module.exports.Item
  , Artwork = module.exports.Artwork
  , inspect = require('util').inspect

// 'name' on Artwork instances is a no-no apparently...
Artwork.prototype.name = undefined;

Application.prototype.inspect = function () {
  return inspect(Application.prototype.toString.call(this));
}
Item.prototype.inspect = function () {
  return inspect(Item.prototype.toString.call(this));
}
<commit_msg>comment<commit_after>require('autoreleasepool');
module.exports = require('./build/default/bindings.node');

var Application = module.exports.Application
  , Item = module.exports.Item
  , Artwork = module.exports.Artwork
  , inspect = require('util').inspect

// 'name' on Artwork instances is a no-no apparently...
Artwork.prototype.name = undefined;

// Custom inspect functions for `console.log` and friends.
Application.prototype.inspect = function () {
  return inspect(Application.prototype.toString.call(this));
}
Item.prototype.inspect = function () {
  return inspect(Item.prototype.toString.call(this));
}
<|endoftext|>


<commit_before>var fileTree = require('file-size-tree')
var detective = require('detective')
var quotemeta = require('quotemeta')
var commondir = require('commondir')
var mdeps = require('module-deps')
var sdeps = require('deps-sort')
var once = require('once')
var path = require('path')
var fs = require('fs')

module.exports = {
    json: json
  , bundle: bundle
}

var ignore = Object.keys(require('browser-builtins')).concat([
  'os', 'module'
])
ignore = '^(?:' + ignore.join('|') + ')$'
ignore = new RegExp(ignore, 'i')

function json(files, transforms, callback) {
  var found = []

  files = toarray(files)
  transforms = toarray(transforms)
  callback = once(callback)

  mdeps(files, {
      transform: transforms
    , filter: function(module) {
      return !ignore.test(module)
    }
  }).pipe(sdeps())
    .once('error', callback)
    .once('close', function() {
      var root = path.basename(commondir(found))
      var tree = {
          name: root
        , children: fileTree(found)
      }

      dirsizes(tree)
      callback(null, tree)
    })
    .on('data', function(dep) {
      found.push(dep.id)
    })
}

function bundle(opts, callback) {
  opts = opts || {}

  var files = toarray(opts.files || null)
  var transforms = toarray(opts.transforms || null)
  var footer = opts.footer || ''
  var button = opts.button || ''

  json(files, transforms, function(err, data) {
    if (err) return callback(err)

    data = '<script type="text/javascript">'
      + ';window.disc = ('
      + JSON.stringify(data)
      + ');</script>'

    var script = '<script type="text/javascript">'
      + bundled().replace(/\/script/gi, '\\/script')
      + '</script>'

    callback(null, template()({
        scripts: script
      , styles: styles()
      , markdown: footer
      , button: button
      , data: data
    }))
  })
}

function toarray(arg) {
  if (typeof arg === 'undefined') return []
  return Array.isArray(arg) ? arg : [arg]
}

function template() {
  if (template.text) return template.text
  return template.text = require('./lib/lazy-template')(
    fs.readFileSync(__dirname + '/src/base.html', 'utf8')
  )
}

function styles() {
  if (styles.text) return styles.text
  return styles.text = fs.readFileSync(__dirname + '/build/style.css', 'utf8')
}

function bundled() {
  if (bundled.text) return bundled.text
  return bundled.text = fs.readFileSync(__dirname + '/build/bundle.js', 'utf8')
}

function dirsizes(child) {
  return child.size = "size" in child ? child.size : child.children.reduce(function(size, child) {
    return size + ("size" in child ? child.size : dirsizes(child))
  }, 0)
}
<commit_msg>Include browserify builtin modules. Closes #3<commit_after>var builtins = require('browser-builtins')
var fileTree = require('file-size-tree')
var quotemeta = require('quotemeta')
var commondir = require('commondir')
var mdeps = require('module-deps')
var sdeps = require('deps-sort')
var once = require('once')
var path = require('path')
var fs = require('fs')

module.exports = {
    json: json
  , bundle: bundle
}

var ignore = Object.keys(builtins).concat(['os', 'module', 'cluster'])
ignore = '^(?:' + ignore.join('|') + ')$'
ignore = new RegExp(ignore, 'i')

function json(files, transforms, callback) {
  var found = []
    , foundbuiltins = []

  files = toarray(files)
  transforms = toarray(transforms)
  callback = once(callback)

  mdeps(files, {
      transform: transforms
    , filter: function(module) {
      if (builtins[module]) {
        insert(foundbuiltins, builtins[module])
      }
      return !ignore.test(module)
    }
  }).pipe(sdeps())
    .once('error', callback)
    .once('close', function() {
      var root = path.basename(commondir(found))
      var tree = {
          name: root
        , children: fileTree(found)
      }

      foundbuiltins.forEach(function(builtin) {
        tree.children.push({
            name: path.basename(builtin)
          , size: fs.statSync(builtin).size
        })
      })

      dirsizes(tree)
      callback(null, tree)
    })
    .on('data', function(dep) {
      found.push(dep.id)
    })
}

function bundle(opts, callback) {
  opts = opts || {}

  var files = toarray(opts.files || null)
  var transforms = toarray(opts.transforms || null)
  var footer = opts.footer || ''
  var button = opts.button || ''

  json(files, transforms, function(err, data) {
    if (err) return callback(err)

    data = '<script type="text/javascript">'
      + ';window.disc = ('
      + JSON.stringify(data)
      + ');</script>'

    var script = '<script type="text/javascript">'
      + bundled().replace(/\/script/gi, '\\/script')
      + '</script>'

    callback(null, template()({
        scripts: script
      , styles: styles()
      , markdown: footer
      , button: button
      , data: data
    }))
  })
}

function toarray(arg) {
  if (typeof arg === 'undefined') return []
  return Array.isArray(arg) ? arg : [arg]
}

function template() {
  if (template.text) return template.text
  return template.text = require('./lib/lazy-template')(
    fs.readFileSync(__dirname + '/src/base.html', 'utf8')
  )
}

function styles() {
  if (styles.text) return styles.text
  return styles.text = fs.readFileSync(__dirname + '/build/style.css', 'utf8')
}

function bundled() {
  if (bundled.text) return bundled.text
  return bundled.text = fs.readFileSync(__dirname + '/build/bundle.js', 'utf8')
}

function dirsizes(child) {
  return child.size = "size" in child ? child.size : child.children.reduce(function(size, child) {
    return size + ("size" in child ? child.size : dirsizes(child))
  }, 0)
}

function insert(array, value) {
  if (array.indexOf(value) === -1) array.push(value)
  return array
}
<|endoftext|>


<commit_before>var GoogleMapsAPI = require("googlemaps"),
    util = require("util"),
    exec = require("child_process").exec,
    config = require("./config");

if (!config) {
    util.log("config.json missing. Aborting...");
    return;
}

// Globals
var bSimulation = config.simulation,
    bRefreshing = false,
    oDisplayTexts = {
        sRoutes: ""
    };

function setup () {
    initializeDisplay(function (err){
        if (err) {
            util.log("Failed to initialize display: ", err);
        } else {
            refreshRoute(config.commute.origin, config.commute.destination, 3 /* fixed for now*/);
        }
    });
}

/* Display */
function initializeDisplay(callback) {
    if (bSimulation) {
        util.log("Display initialized");
        callback();
        return;
    }
    util.log("Initializing display...");
    exec("oled-exp -i power on dim off scroll stop invert off", function (err/*, stdout, stderr*/) {
        callback(err);
    });
}

function refreshDisplay () {
    var sText = "";

    sText += oDisplayTexts.sRoutes;

    sText = sText.replace("'", "");
    if (bSimulation) {
        util.log("Display write:\n" + sText);
        return;
    }
    if (bRefreshing) {
        util.log("Refresh running - aborting (TBD queue)");
        return;
    }
    bRefreshing = true;
    util.log("Writing:\n" + sText);
    exec("oled-exp -c write '" + sText + "'", function (err/*, stdout, stderr*/) {
        bRefreshing = false;
        util.log("Failed to refresh display text: ", err);
    });
}

/* Commute */
var oGoogleMaps = new GoogleMapsAPI({
    key: config.commute.apiKey,
    secure: true // use https
});

function getRouteTimes(sOrigin, sDestination, callback) {
    // origin, destination, callback, sensor, mode, waypoints, alternatives, avoid, units, language, departureTime, arrivalTime, region
    oGoogleMaps.directions({
        origin: sOrigin,
        destination: sDestination,
        alternatives: true
    }, function(oError, oData) {
        var oRoute, oLeg, aRoutes, aRouteTimes,
            i;

        if (oError) {
            callback(oError);
        } else if (!oData || !oData.routes) {
            callback(new Error("No data received"));
        } else if (oData.status !== "OK") {
            callback(new Error("Bad status: " + oData.status));
        } else {
            aRouteTimes = [];
            aRoutes = oData.routes;
            for (i = aRoutes.length - 1; i >= 0; i--) {
                oRoute = aRoutes[i];
                oLeg = oRoute.legs[0];

                aRouteTimes.push({
                    sSummary: oRoute.summary,
                    iDuration: oLeg.duration.value, // in sec
                    sDuration: oLeg.duration.text // human readable (e.g. "24 min")
                });
            }
            callback(null, aRouteTimes);
        }
    });
}

function createRouteDisplayText(aRoutes) {
    var sText = "", oRoute, i;

    for (i = 0; i < aRoutes.length; i++) {
        if (i !== 0) {
            sText += "\n";
        }
        oRoute = aRoutes[i];
        sText += oRoute.sSummary + ": " + oRoute.sDuration;
    }
    return sText;
}

function updateRouteDisplay(sRouteText) {
    oDisplayTexts.sRoutes = sRouteText;
    refreshDisplay();
}

function refreshRoute(sOrigin, sDestination, iRoutesToDisplay) {
    getRouteTimes(sOrigin, sDestination, function(oError, aRoutes) {
        var sRoutes;
        if (oError) {
            util.log(oError.message);
        } else if (aRoutes.length === 0) {
            util.log("No routes found");
        } else {
            // Sorting the shortest to the top
            aRoutes = aRoutes.sort(function(oRouteA, oRouteB) {
                return oRouteA.iDuration - oRouteB.iDuration;
            });
            aRoutes.splice(iRoutesToDisplay, aRoutes.length - iRoutesToDisplay);
            sRoutes = createRouteDisplayText(aRoutes);
            updateRouteDisplay(sRoutes);
        }
    });
}

setup();
<commit_msg>Fixed line breaks<commit_after>var GoogleMapsAPI = require("googlemaps"),
    util = require("util"),
    exec = require("child_process").exec,
    config = require("./config");

if (!config) {
    util.log("config.json missing. Aborting...");
    return;
}

// Globals
var bSimulation = config.simulation,
    bRefreshing = false,
    oDisplayTexts = {
        sRoutes: ""
    };

function setup () {
    initializeDisplay(function (err){
        if (err) {
            util.log("Failed to initialize display: ", err);
        } else {
            refreshRoute(config.commute.origin, config.commute.destination, 3 /* fixed for now*/);
        }
    });
}

/* Display */
/* We got 11x8 chars of fun! */

function initializeDisplay(callback) {
    if (bSimulation) {
        util.log("Display initialized");
        callback();
        return;
    }
    util.log("Initializing display...");
    exec("oled-exp -i power on dim off scroll stop invert off", function (err/*, stdout, stderr*/) {
        callback(err);
    });
}

function refreshDisplay () {
    var sText = "";

    sText += oDisplayTexts.sRoutes;

    if (bSimulation) {
        util.log("Display write:\n" + sText);
        return;
    }
    if (bRefreshing) {
        util.log("Refresh running - aborting (TBD queue)");
        return;
    }
    bRefreshing = true;
    util.log("Writing:\n" + sText);
    exec("oled-exp -c write \"" + sText + "\"", function (err/*, stdout, stderr*/) {
        bRefreshing = false;
        if (err) {
            util.log("Failed to refresh display text: ", err);
        }
    });
}

/* Commute */
var oGoogleMaps = new GoogleMapsAPI({
    key: config.commute.apiKey,
    secure: true // use https
});

function getRouteTimes(sOrigin, sDestination, callback) {
    // origin, destination, callback, sensor, mode, waypoints, alternatives, avoid, units, language, departureTime, arrivalTime, region
    oGoogleMaps.directions({
        origin: sOrigin,
        destination: sDestination,
        alternatives: true
    }, function(oError, oData) {
        var oRoute, oLeg, aRoutes, aRouteTimes,
            i;

        if (oError) {
            callback(oError);
        } else if (!oData || !oData.routes) {
            callback(new Error("No data received"));
        } else if (oData.status !== "OK") {
            callback(new Error("Bad status: " + oData.status));
        } else {
            aRouteTimes = [];
            aRoutes = oData.routes;
            for (i = aRoutes.length - 1; i >= 0; i--) {
                oRoute = aRoutes[i];
                oLeg = oRoute.legs[0];

                aRouteTimes.push({
                    sSummary: oRoute.summary,
                    iDuration: oLeg.duration.value, // in sec
                    sDuration: oLeg.duration.text // human readable (e.g. "24 min")
                });
            }
            callback(null, aRouteTimes);
        }
    });
}

function createRouteDisplayText(aRoutes) {
    var sText = "", oRoute, i;

    for (i = 0; i < aRoutes.length; i++) {
        if (i !== 0) {
            sText += "\n";
        }
        oRoute = aRoutes[i];
        sText += oRoute.sSummary + ": " + oRoute.sDuration;
    }
    return sText;
}

function updateRouteDisplay(sRouteText) {
    oDisplayTexts.sRoutes = sRouteText;
    refreshDisplay();
}

function refreshRoute(sOrigin, sDestination, iRoutesToDisplay) {
    getRouteTimes(sOrigin, sDestination, function(oError, aRoutes) {
        var sRoutes;
        if (oError) {
            util.log(oError.message);
        } else if (aRoutes.length === 0) {
            util.log("No routes found");
        } else {
            // Sorting the shortest to the top
            aRoutes = aRoutes.sort(function(oRouteA, oRouteB) {
                return oRouteA.iDuration - oRouteB.iDuration;
            });
            aRoutes.splice(iRoutesToDisplay, aRoutes.length - iRoutesToDisplay);
            sRoutes = createRouteDisplayText(aRoutes);
            updateRouteDisplay(sRoutes);
        }
    });
}

setup();
<|endoftext|>


<commit_before>'use strict';

const BbPromise = require('bluebird');

class PrunePlugin {
  constructor(serverless, options) {
    this.serverless = serverless;
    this.options = options || {};
    this.provider = this.serverless.getProvider('aws');

    this.pluginCustom = this.loadCustom(this.serverless.service.custom);

    this.commands = {
      prune: {
        usage: 'Cleans up previously deployed function versions',
        lifecycleEvents: ['prune'],
        options: {
          number: {
            usage: 'Specify the number of previous versions to keep',
            shortcut: 'n',
            required: true
          },
          function: {
            usage: 'Only prune the specified function")',
            shortcut: 'f',
            required: false
          },
          dryRun: {
            usage: 'Dry-run, only list candidate versions for deletion ")',
            shortcut: 'd',
            required: false
          }
        }
      },
    };

    this.hooks = {
      'prune:prune': this.prune.bind(this),
      'after:deploy:deploy': this.postDeploy.bind(this)
    };

  }

  getNumber() {
    return this.options.number || this.pluginCustom.number;
  }

  loadCustom(custom) {
    const pluginCustom = {};
    if (custom && custom.prune) {

      if (custom.prune.number != null) {
        const number = parseInt(custom.prune.number);
        if (!isNaN(number)) pluginCustom.number = number;
      }

      if (custom.prune.automatic != null && typeof custom.prune.automatic === 'boolean') {
        pluginCustom.automatic = custom.prune.automatic;
      }

    }

    return pluginCustom;
  }

  postDeploy() {

    if (this.options.noDeploy === true) {
      return BbPromise.resolve();
    }

    if (this.pluginCustom.automatic && this.pluginCustom.number >= 1) {
      this.serverless.cli.log('Prune: Running post-deployment pruning');
      return this.prune();
    } else {
      return BbPromise.resolve();
    }
  }

  prune() {

    const selectedFunctions = this.options.function ? [this.options.function] : this.serverless.service.getAllFunctions();
    const functionNames = selectedFunctions.map(key => this.serverless.service.getFunction(key).name);

    this.serverless.cli.log('Prune: Querying for deployed versions');

    return BbPromise.mapSeries(functionNames, functionName => {

      return BbPromise.all([
        BbPromise.resolve(functionName),
        this.listVersionForFunction(functionName),
        this.listAliasesForFunction(functionName)
      ]).spread((name, versions, aliases) => {
        return { name: name, versions: versions, aliases: aliases };
      });

    }).each(functionResult => {

      if (!functionResult.versions.length)
        return BbPromise.resolve();

      const deletionVersions = this.selectPruneVersionsForFunction(
        functionResult.name, functionResult.versions, functionResult.aliases
      );

      if (this.options.dryRun) {
        return BbPromise.resolve();
      } else {
        return this.deleteVersionsForFunction(functionResult.name, deletionVersions);
      }

    }).then(() => {
      const actions = this.options.dryRun ? ' Dry-run, no actions taken.' : '';
      this.serverless.cli.log('Prune: Pruning complete.' + actions);
    });
  }

  deleteVersionsForFunction(functionName, versions) {

    return BbPromise.each(versions, version => {

      this.serverless.cli.log(`Prune: Deleting ${functionName} v${version}...`);

      const params = {
        FunctionName: functionName,
        Qualifier: version
      };

      return BbPromise.resolve()
      .then(() => this.provider.request('Lambda', 'deleteFunction', params))
      .catch(e => {
        //ignore if trying to delete replicated lambda edge function
        if (e.statusCode === 400 && e.message.startsWith('Lambda was unable to delete') && e.message.endsWith('because it is a replicated function.')) this.serverless.cli.log(`Prune: Unable to delete replicated edge function ${functionName} v${version}...`);
        else throw e;
      });
    });
  }

  listAliasesForFunction(functionName) {
    const params = {
      FunctionName: functionName
    };

    return this.makeLambdaRequest('listAliases', params, r => r.Aliases)
      .catch(e => {
        //ignore if function not deployed
        if (e.statusCode === 404) return [];
        else throw e;
      });
  }

  listVersionForFunction(functionName) {
    const params = {
      FunctionName: functionName
    };

    return this.makeLambdaRequest('listVersionsByFunction', params, r => r.Versions)
      .catch(e => {
        //ignore if function not deployed
        if (e.statusCode === 404) return [];
        else throw e;
      });
  }

  makeLambdaRequest(action, params, responseMapping) {

    const results = [];
    const responseHandler = response => {

      Array.prototype.push.apply(results, responseMapping(response));

      if (response.NextMarker) {
        return this.provider.request('Lambda', action, Object.assign({}, params, { Marker: response.NextMarker }))
          .then(responseHandler);

      } else {
        return BbPromise.resolve(results);
      }
    };

    return this.provider.request('Lambda', action, params)
      .then(responseHandler);
  }

  selectPruneVersionsForFunction(functionName, versions, aliases) {

    const aliasedVersion = aliases.map(a => a.FunctionVersion);

    const deletionCandidates = versions
      .map(f => f.Version)
      .filter(v => v !== '$LATEST') //skip $LATEST
      .filter(v => aliasedVersion.indexOf(v) === -1) //skip aliased versions
      .sort((a, b) => {
        return parseInt(b) - parseInt(a);
      })
      .slice(this.getNumber());

    const puralized = (count, single, plural) => `${count} ${count != 1 ? plural : single}`;
    this.serverless.cli.log(`Prune: ${functionName} has ${puralized(versions.length - 1, 'version', 'versions')} published and ${puralized(aliases.length, 'alias', 'aliases')}, ${puralized(deletionCandidates.length, 'version', 'versions')} selected for deletion`);

    return deletionCandidates;
  }

}

module.exports = PrunePlugin;<commit_msg>internal refactoring<commit_after>'use strict';

const BbPromise = require('bluebird');

class PrunePlugin {
  constructor(serverless, options) {
    this.serverless = serverless;
    this.options = options || {};
    this.provider = this.serverless.getProvider('aws');

    this.pluginCustom = this.loadCustom(this.serverless.service.custom);

    this.commands = {
      prune: {
        usage: 'Cleans up previously deployed function versions',
        lifecycleEvents: ['prune'],
        options: {
          number: {
            usage: 'Specify the number of previous versions to keep',
            shortcut: 'n',
            required: true
          },
          function: {
            usage: 'Only prune the specified function',
            shortcut: 'f',
            required: false
          },
          dryRun: {
            usage: 'Dry-run, only list candidate versions for deletion',
            shortcut: 'd',
            required: false
          }
        }
      },
    };

    this.hooks = {
      'prune:prune': this.prune.bind(this),
      'after:deploy:deploy': this.postDeploy.bind(this)
    };

  }

  getNumber() {
    return this.options.number || this.pluginCustom.number;
  }

  loadCustom(custom) {
    const pluginCustom = {};
    if (custom && custom.prune) {

      if (custom.prune.number != null) {
        const number = parseInt(custom.prune.number);
        if (!isNaN(number)) pluginCustom.number = number;
      }

      if (custom.prune.automatic != null && typeof custom.prune.automatic === 'boolean') {
        pluginCustom.automatic = custom.prune.automatic;
      }

    }

    return pluginCustom;
  }

  postDeploy() {

    if (this.options.noDeploy === true) {
      return BbPromise.resolve();
    }

    if (this.pluginCustom.automatic && this.pluginCustom.number >= 1) {
      this.serverless.cli.log('Prune: Running post-deployment pruning');
      return this.prune();
    } else {
      return BbPromise.resolve();
    }
  }

  prune() {

    const selectedFunctions = this.options.function ? [this.options.function] : this.serverless.service.getAllFunctions();
    const functionNames = selectedFunctions.map(key => this.serverless.service.getFunction(key).name);

    this.serverless.cli.log('Prune: Querying for deployed versions');

    return BbPromise.mapSeries(functionNames, functionName => {

      return BbPromise.join(
        this.listVersionForFunction(functionName),
        this.listAliasesForFunction(functionName),
        (versions, aliases) => ( { name: functionName, versions: versions, aliases: aliases } )
      );

    }).each(functionResult => {

      if (!functionResult.versions.length)
        return BbPromise.resolve();

      const deletionVersions = this.selectPruneVersionsForFunction(functionResult.versions, functionResult.aliases);

      const puralized = (count, single, plural) => `${count} ${count != 1 ? plural : single}`;

      const nonLatestVersionCount = functionResult.versions.length - 1;
      const aliasCount = functionResult.aliases.length;
      this.serverless.cli.log(`Prune: ${functionResult.name} has ${puralized(nonLatestVersionCount, 'additional version', 'additional versions')} published and ${puralized(aliasCount, 'alias', 'aliases')}, ${puralized(deletionVersions.length, 'version', 'versions')} selected for deletion`);

      if (this.options.dryRun) {
        return BbPromise.resolve();
      } else {
        return this.deleteVersionsForFunction(functionResult.name, deletionVersions);
      }

    }).then(() => {
      const actions = this.options.dryRun ? 'Dry-run complete, no actions taken.' : 'Pruning complete.';
      this.serverless.cli.log('Prune: ' + actions);
    });
  }

  deleteVersionsForFunction(functionName, versions) {

    return BbPromise.each(versions, version => {

      this.serverless.cli.log(`Prune: Deleting ${functionName} v${version}...`);

      const params = {
        FunctionName: functionName,
        Qualifier: version
      };

      return BbPromise.resolve()
      .then(() => this.provider.request('Lambda', 'deleteFunction', params))
      .catch(e => {
        //ignore if trying to delete replicated lambda edge function
        if (e.statusCode === 400 && e.message.startsWith('Lambda was unable to delete') && e.message.endsWith('because it is a replicated function.')) this.serverless.cli.log(`Prune: Unable to delete replicated edge function ${functionName} v${version}...`);
        else throw e;
      });
    });
  }

  listAliasesForFunction(functionName) {
    const params = {
      FunctionName: functionName
    };

    return this.makeLambdaRequest('listAliases', params, r => r.Aliases)
      .catch(e => {
        //ignore if function not deployed
        if (e.statusCode === 404) return [];
        else throw e;
      });
  }

  listVersionForFunction(functionName) {
    const params = {
      FunctionName: functionName
    };

    return this.makeLambdaRequest('listVersionsByFunction', params, r => r.Versions)
      .catch(e => {
        //ignore if function not deployed
        if (e.statusCode === 404) return [];
        else throw e;
      });
  }

  makeLambdaRequest(action, params, responseMapping) {

    const results = [];
    const responseHandler = response => {

      Array.prototype.push.apply(results, responseMapping(response));

      if (response.NextMarker) {
        return this.provider.request('Lambda', action, Object.assign({}, params, { Marker: response.NextMarker }))
          .then(responseHandler);

      } else {
        return BbPromise.resolve(results);
      }
    };

    return this.provider.request('Lambda', action, params)
      .then(responseHandler);
  }

  selectPruneVersionsForFunction(versions, aliases) {

    const aliasedVersion = aliases.map(a => a.FunctionVersion);

    const deletionCandidates = versions
      .map(f => f.Version)
      .filter(v => v !== '$LATEST') //skip $LATEST
      .filter(v => aliasedVersion.indexOf(v) === -1) //skip aliased versions
      .sort((a, b) => parseInt(b) - parseInt(a))
      .slice(this.getNumber());

    return deletionCandidates;
  }

}

module.exports = PrunePlugin;<|endoftext|>


<commit_before>var qs = require('querystring');

var debug   = require('debug')('chirp-rest');
var request = require('request');
var OAuth   = require('oauth-1.0a');

module.exports = ChirpRest;

function ChirpRest(opt) {
    if(!(this instanceof ChirpRest)) {
        return new ChirpRest(opt);
    }

    if(!(opt.consumer && opt.consumer.public && opt.consumer.secret)) {
        throw new Error('consumer.public and consumer.secret are required');
    }

    if(!(opt.token && opt.token.public && opt.token.secret)) {
        throw new Error('token.public and token.secret are required');
    }

    this.consumer = opt.consumer;
    this.token    = opt.token;

    this.oauth = OAuth({
        consumer: this.consumer
    });
}

/**
 * debug
 *
 * @api private
 */
ChirpRest.prototype._log = debug;

/**
 * send api request
 * @param  {Object}   opt
 * @param  {Function} callback
 *
 * @api private
 */
ChirpRest.prototype._api = function(opt, callback) {
    //enable json
    opt.json = true;

    this._log('api', opt);

    request(opt, callback);
};

ChirpRest.prototype.get = function(url, param, callback) {
    var self = this;

    if(arguments.length === 2) {
        callback = param;
        param = {};
    }

    if(!url) {
        throw new Error('url is required');
    }

    if(!callback) {
        throw new Error('callback is required');
    }

    var request_data = {
        url: url,
        method: 'GET',
        data: param
    };

    self._api({
        url: url,
        method: 'GET',
        qs: self.oauth.authorize(request_data, self.token)
    }, callback);
};

ChirpRest.prototype.post = function(url, param, callback) {
    var self = this;

    if(arguments.length === 2) {
        callback = param;
        param = {};
    }

    if(!url) {
        throw new Error('url is required');
    }

    if(!callback) {
        throw new Error('callback is required');
    }

    var request_data = {
        url: url,
        method: 'POST',
        data: param
    };

    /*
    LOL this shit take me a whole day !

    Cant use !!!

    self._api({
        url: url,
        method: 'POST',
        form: self.oauth.authorize(request_data, self.token)
    }, callback);

    below is the correct way
    */

    var body = qs.stringify(self.oauth.authorize(request_data, self.token))
        .replace(/\-/g, "%2D")
        .replace(/\_/g, "%5F")
        .replace(/\./g, "%2E")
        .replace(/\!/g, "%21")
        .replace(/\*/g, "%2A")
        .replace(/\'/g, "%27")
        .replace(/\(/g, "%28")
        .replace(/\)/g, "%29");

    self._api({
        url: url,
        method: 'POST',
        body: body,
        headers: {
            'content-type': 'application/x-www-form-urlencoded'
        }
    }, callback);
};<commit_msg>remove 3 useless lines<commit_after>var qs = require('querystring');

var debug   = require('debug')('chirp-rest');
var request = require('request');
var OAuth   = require('oauth-1.0a');

module.exports = ChirpRest;

function ChirpRest(opt) {
    if(!(this instanceof ChirpRest)) {
        return new ChirpRest(opt);
    }

    if(!(opt.consumer && opt.consumer.public && opt.consumer.secret)) {
        throw new Error('consumer.public and consumer.secret are required');
    }

    if(!(opt.token && opt.token.public && opt.token.secret)) {
        throw new Error('token.public and token.secret are required');
    }

    this.consumer = opt.consumer;
    this.token    = opt.token;

    this.oauth = OAuth({
        consumer: this.consumer
    });
}

/**
 * debug
 *
 * @api private
 */
ChirpRest.prototype._log = debug;

/**
 * send api request
 * @param  {Object}   opt
 * @param  {Function} callback
 *
 * @api private
 */
ChirpRest.prototype._api = function(opt, callback) {
    //enable json
    opt.json = true;

    this._log('api', opt);

    request(opt, callback);
};

ChirpRest.prototype.get = function(url, param, callback) {
    var self = this;

    if(arguments.length === 2) {
        callback = param;
        param = {};
    }

    if(!url) {
        throw new Error('url is required');
    }

    if(!callback) {
        throw new Error('callback is required');
    }

    var request_data = {
        url: url,
        method: 'GET',
        data: param
    };

    self._api({
        url: url,
        method: 'GET',
        qs: self.oauth.authorize(request_data, self.token)
    }, callback);
};

ChirpRest.prototype.post = function(url, param, callback) {
    var self = this;

    if(arguments.length === 2) {
        callback = param;
        param = {};
    }

    if(!url) {
        throw new Error('url is required');
    }

    if(!callback) {
        throw new Error('callback is required');
    }

    var request_data = {
        url: url,
        method: 'POST',
        data: param
    };

    /*
    LOL this shit take me a whole day !

    Cant use !!!

    self._api({
        url: url,
        method: 'POST',
        form: self.oauth.authorize(request_data, self.token)
    }, callback);

    below is the correct way
    */

    var body = qs.stringify(self.oauth.authorize(request_data, self.token))
        .replace(/\!/g, "%21")
        .replace(/\*/g, "%2A")
        .replace(/\'/g, "%27")
        .replace(/\(/g, "%28")
        .replace(/\)/g, "%29");

    self._api({
        url: url,
        method: 'POST',
        body: body,
        headers: {
            'content-type': 'application/x-www-form-urlencoded'
        }
    }, callback);
};<|endoftext|>


<commit_before>"use strict";
const Socket = require("./common/floop");
const _ = require("lodash");
// const editorAction = require("./common/editor_action");
const CompositeDisposable = require('event-kit').CompositeDisposable;

function TerminalManager () {
  // floobits term id to this.Term3 TermialView
  this.terms = {};

  this.term3_name_to_ids = {};

  this.term3 = null;
  this.username = null;
  this.floobits_terms = null;
}

TerminalManager.prototype.send_create_term = function (t) {
  if (!t.getForked()) {
    console.log("not sending create event for remotely driven terminal");
    return;
  }
  const d = t.getDimensions();
  const name = this.nameForTerm(t);
  this.term3_name_to_ids[name] = t.id;
  Socket.send_create_term({term_name: name, size: [d.cols, d.rows]});
};

TerminalManager.prototype.nameForTerm = function (term) {
  return `atom-${this.username}-${term.id}-${Math.floor(Math.random() * 10000)}`;
};

TerminalManager.prototype.on_floobits = function(username, floobits_terms) {
  this.username = username;
  this.floobits_terms = floobits_terms;

  if (!this.term3) {
    return;
  }
  this.start_();
};

TerminalManager.prototype.on_term3_service = function(term3) {
  this.term3 = term3;

  if (!this.floobits_terms || !this.username) {
    return;
  }
  this.start_();
};

TerminalManager.prototype.start_ = function () {
  const that = this;

  this.subs = new CompositeDisposable();

  const disposable = that.term3.onTerm(that.send_create_term.bind(that));

  this.subs.add(disposable);

  that.term3.getTerminals().forEach(that.send_create_term.bind(that));

  _.each(that.floobits_terms, function (t, termID) {
    const term = that.term3.newTerm(false, t.size[1], t.size[0], t.owner);
    that.terms[termID] = term;

    const subs = new CompositeDisposable();

    subs.add(term.onSTDIN(function (d) {
      Socket.send_term_stdin({'data': new Buffer(d).toString("base64"), id: termID});
    }));

    subs.add(term.onExit(function () {
      that.subs.remove(subs);
      subs.dispose();
      delete that.terms[termID];
    }));

    that.subs.add(subs);
  });

  Socket.onCREATE_TERM(function (req) {
    const name = req.term_name;
    const termID = req.id;

    const term3_ID = that.term3_name_to_ids[name];
    const term = _.find(that.term3.getTerminals(), function (t) {
      return t.id === term3_ID;
    });

    if (!term) {
      that.terms[termID] = that.term3.newTerm(false);
      that.subs.add(that.terms[termID].onSTDIN(function (d) {
        Socket.send_term_stdin({'data': new Buffer(d).toString("base64"), id: termID});
      }));
      return;
    }

    const subs = new CompositeDisposable();

    subs.add(term.onSTDOUT(function (d) {
      Socket.send_term_stdout({data: new Buffer(d).toString("base64"), id: termID});
    }));

    subs.add(term.onResize(function (size) {
      Socket.send_update_term({id: termID, size: [size.cols, size.rows]});
    }));

    subs.add(term.onExit(function () {
      Socket.send_delete_term({id: termID});
      that.subs.remove(subs);
      subs.dispose();
      delete that.terms[termID];
    }));

    that.subs.add(subs);
  });

  Socket.onTERM_STDIN(function (data) {
    const term = that.terms[data.id];

    if (!term) {
      return;
    }

    try {
      term.input(new Buffer(data.data, "base64").toString("utf-8"));
    } catch (e) {
      console.warn(e);
    }
  });

  Socket.onDELETE_TERM(function (data) {
    const term = that.terms[data.id];

    if (!term) {
      return;
    }

    term.input("\r\n   *** TERMINAL CLOSED ***   \r\n");
  });

  Socket.onTERM_STDOUT(function (data) {
    const term = that.terms[data.id];

    if (!term) {
      return;
    }

    try {
      term.input(new Buffer(data.data, "base64").toString("utf-8"));
    } catch (e) {
      console.warn(e);
    }
  });

  Socket.onUPDATE_TERM(function (data) {
    const term = that.terms[data.id];

    if (!term) {
      return;
    }

    console.log("update term", data);
    if (data.size) {
      term.resize(data.size[0], data.size[1]);
    }
  });

  Socket.onSYNC(function (terms) {
    console.log("Attempting to sync...");
    _.each(terms, function (data, id) {
      const term = that.terms[id];

      if (!term) {
        return;
      }

      term.resize(data.cols, data.rows);
    });
  });
};

TerminalManager.prototype.stop = function(term3_disposed) {
  if (this.subs) {
    this.subs.dispose();
    this.subs = null;
  }
  // we may not get another term3...
  if (term3_disposed) {
    this.term3 = null;
  }
  this.floobits_terms = null;
  this.username = null;
};

module.exports = new TerminalManager();
<commit_msg>Send terminal dimensions after colab responds with create_term.<commit_after>"use strict";
const Socket = require("./common/floop");
const _ = require("lodash");
// const editorAction = require("./common/editor_action");
const CompositeDisposable = require('event-kit').CompositeDisposable;

function TerminalManager () {
  // floobits term id to this.Term3 TermialView
  this.terms = {};

  this.term3_name_to_ids = {};

  this.term3 = null;
  this.username = null;
  this.floobits_terms = null;
}

TerminalManager.prototype.send_create_term = function (t) {
  if (!t.getForked()) {
    console.log("not sending create event for remotely driven terminal");
    return;
  }
  const d = t.getDimensions();
  const name = this.nameForTerm(t);
  this.term3_name_to_ids[name] = t.id;
  Socket.send_create_term({term_name: name, size: [d.cols, d.rows]});
};

TerminalManager.prototype.nameForTerm = function (term) {
  return `atom-${this.username}-${term.id}-${Math.floor(Math.random() * 10000)}`;
};

TerminalManager.prototype.on_floobits = function(username, floobits_terms) {
  this.username = username;
  this.floobits_terms = floobits_terms;

  if (!this.term3) {
    return;
  }
  this.start_();
};

TerminalManager.prototype.on_term3_service = function(term3) {
  this.term3 = term3;

  if (!this.floobits_terms || !this.username) {
    return;
  }
  this.start_();
};

TerminalManager.prototype.start_ = function () {
  const that = this;

  this.subs = new CompositeDisposable();

  const disposable = that.term3.onTerm(that.send_create_term.bind(that));

  this.subs.add(disposable);

  that.term3.getTerminals().forEach(that.send_create_term.bind(that));

  _.each(that.floobits_terms, function (t, termID) {
    const term = that.term3.newTerm(false, t.size[1], t.size[0], t.owner);
    that.terms[termID] = term;

    const subs = new CompositeDisposable();

    subs.add(term.onSTDIN(function (d) {
      Socket.send_term_stdin({'data': new Buffer(d).toString("base64"), id: termID});
    }));

    subs.add(term.onExit(function () {
      that.subs.remove(subs);
      subs.dispose();
      delete that.terms[termID];
    }));

    that.subs.add(subs);
  });

  Socket.onCREATE_TERM(function (req) {
    const name = req.term_name;
    const termID = req.id;

    const term3_ID = that.term3_name_to_ids[name];
    const term = _.find(that.term3.getTerminals(), function (t) {
      return t.id === term3_ID;
    });

    if (!term) {
      that.terms[termID] = that.term3.newTerm(false);
      that.subs.add(that.terms[termID].onSTDIN(function (d) {
        Socket.send_term_stdin({'data': new Buffer(d).toString("base64"), id: termID});
      }));
      return;
    }

    const d = term.getDimensions();
    Socket.send_update_term({id: termID, size: [d.cols, d.rows]});

    const subs = new CompositeDisposable();

    subs.add(term.onSTDOUT(function (d) {
      Socket.send_term_stdout({data: new Buffer(d).toString("base64"), id: termID});
    }));

    subs.add(term.onResize(function (size) {
      Socket.send_update_term({id: termID, size: [size.cols, size.rows]});
    }));

    subs.add(term.onExit(function () {
      Socket.send_delete_term({id: termID});
      that.subs.remove(subs);
      subs.dispose();
      delete that.terms[termID];
    }));

    that.subs.add(subs);
  });

  Socket.onTERM_STDIN(function (data) {
    const term = that.terms[data.id];

    if (!term) {
      return;
    }

    try {
      term.input(new Buffer(data.data, "base64").toString("utf-8"));
    } catch (e) {
      console.warn(e);
    }
  });

  Socket.onDELETE_TERM(function (data) {
    const term = that.terms[data.id];

    if (!term) {
      return;
    }

    term.input("\r\n   *** TERMINAL CLOSED ***   \r\n");
  });

  Socket.onTERM_STDOUT(function (data) {
    const term = that.terms[data.id];

    if (!term) {
      return;
    }

    try {
      term.input(new Buffer(data.data, "base64").toString("utf-8"));
    } catch (e) {
      console.warn(e);
    }
  });

  Socket.onUPDATE_TERM(function (data) {
    const term = that.terms[data.id];

    if (!term) {
      return;
    }

    console.log("update term", data);
    if (data.size) {
      term.resize(data.size[0], data.size[1]);
    }
  });

  Socket.onSYNC(function (terms) {
    console.log("Attempting to sync...");
    _.each(terms, function (data, id) {
      const term = that.terms[id];

      if (!term) {
        return;
      }

      term.resize(data.cols, data.rows);
    });
  });
};

TerminalManager.prototype.stop = function(term3_disposed) {
  if (this.subs) {
    this.subs.dispose();
    this.subs = null;
  }
  // we may not get another term3...
  if (term3_disposed) {
    this.term3 = null;
  }
  this.floobits_terms = null;
  this.username = null;
};

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


<commit_before>var spawn = require('child_process').spawn,
  es    = require('event-stream')
  ;

module.exports = childrenOfPid
function childrenOfPid( pid, callback) {
  var headers = null

  if('function' !== typeof callback)
    throw new Error('childrenOfPid(pid, callback) expects callback')
  if('number' == typeof pid)
    pid = pid.toString()

  es.connect(
    spawn('ps', ['-A', '-o', 'ppid,pid,cmd']).stdout,
    es.split(),
    es.map(function (line, cb) { //this could parse alot of unix command output
      var columns = line.trim().split(/\s+/)
      if(!headers)
        headers = columns
      else {
        var row = {}
        //for each header,
        var h = headers.slice()
        while (h.length) {
          row[h.shift()] = h.length ? columns.shift() : columns.join(' ')
        }
        return cb(null, row)
      }
      return cb()
    }),
    es.writeArray(function (err, ps) {
      var parents = [pid], children = []
      ps.forEach(function (proc) {
        if(-1 != parents.indexOf(proc.PPID)) {
          parents.push(proc.PID)
          children.push(proc)
        }
      })
      callback(null, children)
    })
  ).on('error', callback)
}

if(!module.parent) {
  childrenOfPid(process.argv[2] || 1, function (err, data) {
  console.log(data)
  })
}<commit_msg>cmd is not supported on OSX and actually causes an error on Solaris:<commit_after>var spawn = require('child_process').spawn,
  es    = require('event-stream')
  ;

module.exports = childrenOfPid
function childrenOfPid( pid, callback) {
  var headers = null

  if('function' !== typeof callback)
    throw new Error('childrenOfPid(pid, callback) expects callback')
  if('number' == typeof pid)
    pid = pid.toString()

  es.connect(
    spawn('ps', ['-A', '-o', 'ppid,pid']).stdout,
    es.split(),
    es.map(function (line, cb) { //this could parse alot of unix command output
      var columns = line.trim().split(/\s+/)
      if(!headers)
        headers = columns
      else {
        var row = {}
        //for each header,
        var h = headers.slice()
        while (h.length) {
          row[h.shift()] = h.length ? columns.shift() : columns.join(' ')
        }
        return cb(null, row)
      }
      return cb()
    }),
    es.writeArray(function (err, ps) {
      var parents = [pid], children = []
      ps.forEach(function (proc) {
        if(-1 != parents.indexOf(proc.PPID)) {
          parents.push(proc.PID)
          children.push(proc)
        }
      })
      callback(null, children)
    })
  ).on('error', callback)
}

if(!module.parent) {
  childrenOfPid(process.argv[2] || 1, function (err, data) {
  console.log(data)
  })
}<|endoftext|>


<commit_before>/*!
 * Sitemap
 * Copyright(c) 2011 Eugene Kalinin
 * MIT Licensed
 */

module.exports = require('./lib/sitemap');
module.exports.utils = require('./lib/utils');
module.exports.errors = require('./lib/errors');

/**
 * Framework version.
 */
var fs = require('fs')
  , path = require('path')
  , pack_file = path.join(__dirname, 'package.json');

if (!module.exports.version) {
  module.exports.version = JSON.parse(
    fs.readFileSync(pack_file, 'utf8')).version;
}
<commit_msg>fixed #28<commit_after>/*!
 * Sitemap
 * Copyright(c) 2011 Eugene Kalinin
 * MIT Licensed
 */

module.exports = require('./lib/sitemap');
module.exports.utils = require('./lib/utils');
module.exports.errors = require('./lib/errors');

/**
 * Framework version.
 */
var fs = require('fs');

if (!module.exports.version) {
  module.exports.version = JSON.parse(
    fs.readFileSync(__dirname + "/package.json", 'utf8')).version;
}
<|endoftext|>


<commit_before>/**
 * Copyright 2016 vmarchaud. All rights reserved.
 * Use of this source code is governed by a license that
 * can be found in the LICENSE file.
 */

var http = require('http');
var crypto = require('crypto');
var pmx = require('pmx');
var pm2 = require('pm2');
var util = require('util');
var spawn = require('child_process').spawn;
var async = require('async');
var vizion = require('vizion');
var ipaddr = require('ipaddr.js');

/**
 * Init pmx module
 */
pmx.initModule({}, function (err, conf) {
  pm2.connect(function (err2) {
    if (err || err2) {
      console.error(err || err2);
      return process.exit(1);
    }
    // init the worker only if we can connect to pm2
    new Worker(conf).start();
  });
});

/**
 * Constructor of our worker
 *
 * @param {object} opts The options
 * @returns {Worker} The instance of our worker
 * @constructor
 */
var Worker = function (opts) {
  if (!(this instanceof Worker)) {
    return new Worker(opts);
  }

  this.opts = opts;
  this.port = this.opts.port || 8888;
  this.apps = opts.apps;

  if (typeof (this.apps) !== 'object') {
    this.apps = JSON.parse(this.apps);
  }

  this.server = http.createServer(this._handleHttp.bind(this));
  return this;
};

/**
 * Main function for http server
 *
 * @param req The Request
 * @param res The Response
 * @private
 */
Worker.prototype._handleHttp = function (req, res) {
  var self = this;

  // send instant answer since its useless to respond to the webhook
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.write('OK');

  // do something only with post request
  if (req.method !== 'POST') {
    res.end();
    return;
  }

  // get source ip
  req.ip = req.headers['x-forwarded-for'] || (req.connection ? req.connection.remoteAddress : false) ||
            (req.socket ? req.socket.remoteAddress : false) || ((req.connection && req.connection.socket)
              ? req.connection.socket.remoteAddress : false) || '';
  if (req.ip.indexOf('::ffff:') !== -1) {
    req.ip = req.ip.replace('::ffff:', '');
  }

  // get the whole body before processing
  req.body = '';
  req.on('data', function (data) {
    req.body += data;
  }).on('end', function () {
    self.processRequest(req);
  });

  res.end();
};

/**
 * Main function of the module
 *
 * @param req The Request of the call
 */
Worker.prototype.processRequest = function (req) {
  var targetName = reqToAppName(req);
  if (targetName.length === 0) return;

  var targetApp = this.apps[targetName];
  if (!targetApp) return;

  var error = this.checkRequest(targetApp, req);
  if (error) {
    console.log(error);
    return;
  }

  console.log('[%s] Received valid hook for app %s', new Date().toISOString(), targetName);

  var execOptions = {
    cwd: targetApp.cwd,
    env: process.env,
    shell: true
  };
  var phases = {
    resolveCWD: function resolveCWD(cb) {
      // if cwd is provided, we expect that it isnt a pm2 app
      if (targetApp.cwd) return cb();

      // try to get the cwd to execute it correctly
      pm2.describe(targetName, function (err, apps) {
        if (err || !apps || apps.length === 0) return cb(err || new Error('Application not found'));

        // execute the actual command in the cwd of the application
        targetApp.cwd = apps[0].pm_cwd ? apps[0].pm_cwd : apps[0].pm2_env.pm_cwd;
        return cb();
      });
    },
    pullTheApplication: function pullTheApplication(cb) {
      vizion.update({
        folder: targetApp.cwd
      }, logCallback(cb, '[%s] Successfuly pulled application %s', new Date().toISOString(), targetName));
    },
    preHook: function preHook(cb) {
      if (!targetApp.prehook) return cb();

      spawnAsExec(targetApp.prehook, execOptions,
          logCallback(cb, '[%s] Prehook command has been successfuly executed for app %s', new Date().toISOString(), targetName));
    },
    reloadApplication: function reloadApplication(cb) {
      if (!targetApp.nopm2) return cb();

      pm2.gracefulReload(targetName,
	    logCallback(cb, '[%s] Successfuly reloaded application %s', new Date().toISOString(), targetName));
    },
    postHook: function postHook(cb) {
      if (!targetApp.posthook) return cb();

      // execute the actual command in the cwd of the application
      spawnAsExec(targetApp.posthook, execOptions,
          logCallback(cb, '[%s] Posthook command has been successfuly executed for app %s', new Date().toISOString(), targetName));
    }
  };
  async.series(Object.keys(phases).map(function(k){ return phases[k]; }),
    function (err, results) {
      if (err) {
        console.log('[%s] An error has occuring while processing app %s', new Date().toISOString(), targetName);
        console.error(err);
      }
    });
};

/**
 * Checks if a request is valid for an app.
 *
 * @param targetApp The app which the request has to be valid
 * @param req The request to analyze
 * @returns {string|true} True if success or the string of the error if not.
 */
Worker.prototype.checkRequest = function checkRequest(targetApp, req) {
  var targetName = reqToAppName(req);
  switch (targetApp.service) {
    case 'gitlab': {
      if (!req.headers['x-gitlab-token']) {
        return util.format('[%s] Received invalid request for app %s (no headers found)', new Date().toISOString(), targetName);
      }

      if (req.headers['x-gitlab-token'] !== targetApp.secret) {
        return util.format('[%s] Received invalid request for app %s (not matching secret)', new Date().toISOString(), targetName);
      }
      break;
    }
    case 'jenkins': {
      // ip must match the secret
      if (req.ip.indexOf(targetApp.secret) < 0) {
        return util.format('[%s] Received request from %s for app %s but ip configured was %s', new Date().toISOString(), req.ip, targetName, targetApp.secret);
      }

      var body = JSON.parse(req.body);
      if (body.build.status !== 'SUCCESS') {
        return util.format('[%s] Received valid hook but with failure build for app %s', new Date().toISOString(), targetName);
      }
      if (targetApp.branch && body.build.scm.branch.indexOf(targetApp.branch) < 0) {
        return util.format('[%s] Received valid hook but with a branch %s than configured for app %s', new Date().toISOString(), body.build.scm.branch, targetName);
      }
      break;
    }
    case 'droneci': {
      // Authorization header must match configured secret
      if (!req.headers['Authorization']) {
        return util.format('[%s] Received invalid request for app %s (no headers found)', new Date().toISOString(), targetName);
      }
      if (req.headers['Authorization'] !== targetApp.secret) {
        return util.format('[%s] Received request from %s for app %s but incorrect secret', new Date().toISOString(), req.ip, targetName);
      }

      var data = JSON.parse(req.body);
      if (data.build.status !== 'SUCCESS') {
        return util.format('[%s] Received valid hook but with failure build for app %s', new Date().toISOString(), targetName);
      }
      if (targetApp.branch && data.build.branch.indexOf(targetApp.branch) < 0) {
        return util.format('[%s] Received valid hook but with a branch %s than configured for app %s', new Date().toISOString(), data.build.branch, targetName);
      }
      break;
    }
    case 'bitbucket': {
      var tmp = JSON.parse(req.body);
      var ip = targetApp.secret || '104.192.143.0/24';
      var configured = ipaddr.parseCIDR(ip);
      var source = ipaddr.parse(req.ip);

      if (!source.match(configured)) {
        return util.format('[%s] Received request from %s for app %s but ip configured was %s', new Date().toISOString(), req.ip, targetName, ip);
      }
      if (!tmp.push) {
        return util.format("[%s] Received valid hook but without 'push' data for app %s", new Date().toISOString(), targetName);
      }
      if (targetApp.branch && tmp.push.changes[0] && tmp.push.changes[0].new.name.indexOf(targetApp.branch) < 0) {
        return util.format('[%s] Received valid hook but with a branch %s than configured for app %s', new Date().toISOString(), tmp.push.changes[0].new.name, targetName);
      }
      break;
    }
    case 'github' :
    default: {
      if (!req.headers['x-github-event'] || !req.headers['x-hub-signature']) {
        return util.format('[%s] Received invalid request for app %s (no headers found)', new Date().toISOString(), targetName);
      }

      // compute hash of body with secret, github should send this to verify authenticity
      var temp = crypto.createHmac('sha1', targetApp.secret);
      temp.update(req.body, 'utf-8');
      var hash = temp.digest('hex');

      if ('sha1=' + hash !== req.headers['x-hub-signature']) {
        return util.format('[%s] Received invalid request for app %s', new Date().toISOString(), targetName);
      }
      break;
    }
  }
  return false;
};

/**
 * Lets start our server
 */
Worker.prototype.start = function () {
  var self = this;
  this.server.listen(this.opts.port, function () {
    console.log('Server is ready and listen on port %s', self.port);
  });
};

/**
 * Executes the callback, but in case of success shows a message.
 * Also accepts extra arguments to pass to console.log.
 *
 * Example:
 * logCallback(next, '% worked perfect', appName)
 *
 * @param {Function} cb The callback to be called
 * @param {string} message The message to show if success
 * @returns {Function} The callback wrapped
 */
function logCallback(cb, message) {
  var wrappedArgs = Array.prototype.slice.call(arguments);
  return function (err, data) {
    if (err) return cb(err);

    wrappedArgs.shift();
    console.log.apply(console, wrappedArgs);
    cb(data);
  }
}

/**
 * Given a request, returns the name of the target App.
 *
 * Example:
 * Call to 34.23.34.54:3000/api-2
 * Will return 'api-2'
 *
 * @param req The request to be analysed
 * @returns {string|null} The name of the app, or null if not found.
 */
function reqToAppName(req) {
  var targetName = null;
  try {
    targetName = req.url.split('/').pop();
  } catch (e) {}
  return targetName || null;
}

/**
 * Wraps the node spawn function to work as exec (line, options, callback).
 * This avoid the maxBuffer issue, as no buffer will be stored.
 *
 * @param {string} command The line to execute
 * @param {object} options The options to pass to spawn
 * @param {function} cb The callback, called with error as first argument
 */
function spawnAsExec(command, options, cb) {
  var child = spawn('eval', [command], options);
  child.on('close', cb);
}
<commit_msg>fixed some refactoring issues<commit_after>/**
 * Copyright 2016 vmarchaud. All rights reserved.
 * Use of this source code is governed by a license that
 * can be found in the LICENSE file.
 */

var http = require('http');
var crypto = require('crypto');
var pmx = require('pmx');
var pm2 = require('pm2');
var util = require('util');
var spawn = require('child_process').spawn;
var async = require('async');
var vizion = require('vizion');
var ipaddr = require('ipaddr.js');

/**
 * Init pmx module
 */
pmx.initModule({}, function (err, conf) {
  pm2.connect(function (err2) {
    if (err || err2) {
      console.error(err || err2);
      return process.exit(1);
    }
    // init the worker only if we can connect to pm2
    new Worker(conf).start();
  });
});

/**
 * Constructor of our worker
 *
 * @param {object} opts The options
 * @returns {Worker} The instance of our worker
 * @constructor
 */
var Worker = function (opts) {
  if (!(this instanceof Worker)) {
    return new Worker(opts);
  }

  this.opts = opts;
  this.port = this.opts.port || 8888;
  this.apps = opts.apps;

  if (typeof (this.apps) !== 'object') {
    this.apps = JSON.parse(this.apps);
  }

  this.server = http.createServer(this._handleHttp.bind(this));
  return this;
};

/**
 * Main function for http server
 *
 * @param req The Request
 * @param res The Response
 * @private
 */
Worker.prototype._handleHttp = function (req, res) {
  var self = this;

  // send instant answer since its useless to respond to the webhook
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.write('OK');

  // do something only with post request
  if (req.method !== 'POST') {
    res.end();
    return;
  }

  // get source ip
  req.ip = req.headers['x-forwarded-for'] || (req.connection ? req.connection.remoteAddress : false) ||
            (req.socket ? req.socket.remoteAddress : false) || ((req.connection && req.connection.socket)
              ? req.connection.socket.remoteAddress : false) || '';
  if (req.ip.indexOf('::ffff:') !== -1) {
    req.ip = req.ip.replace('::ffff:', '');
  }

  // get the whole body before processing
  req.body = '';
  req.on('data', function (data) {
    req.body += data;
  }).on('end', function () {
    self.processRequest(req);
  });

  res.end();
};

/**
 * Main function of the module
 *
 * @param req The Request of the call
 */
Worker.prototype.processRequest = function (req) {
  var targetName = reqToAppName(req);
  if (targetName.length === 0) return;

  var targetApp = this.apps[targetName];
  if (!targetApp) return;

  var error = this.checkRequest(targetApp, req);
  if (error) {
    console.log(error);
    return;
  }

  console.log('[%s] Received valid hook for app %s', new Date().toISOString(), targetName);

  var execOptions = {
    cwd: targetApp.cwd,
    env: process.env,
    shell: true
  };
  var phases = {
    resolveCWD: function resolveCWD(cb) {
      // if cwd is provided, we expect that it isnt a pm2 app
      if (targetApp.cwd) return cb();

      // try to get the cwd to execute it correctly
      pm2.describe(targetName, function (err, apps) {
        if (err || !apps || apps.length === 0) return cb(err || new Error('Application not found'));

        // execute the actual command in the cwd of the application
        targetApp.cwd = apps[0].pm_cwd ? apps[0].pm_cwd : apps[0].pm2_env.pm_cwd;
        return cb();
      });
    },
    pullTheApplication: function pullTheApplication(cb) {
      vizion.update({
        folder: targetApp.cwd
      }, logCallback(cb, '[%s] Successfuly pulled application %s', new Date().toISOString(), targetName));
    },
    preHook: function preHook(cb) {
      if (!targetApp.prehook) return cb();

      spawnAsExec(targetApp.prehook, execOptions,
          logCallback(cb, '[%s] Prehook command has been successfuly executed for app %s', new Date().toISOString(), targetName));
    },
    reloadApplication: function reloadApplication(cb) {
      if (targetApp.nopm2) return cb();

      pm2.gracefulReload(targetName,
	    logCallback(cb, '[%s] Successfuly reloaded application %s', new Date().toISOString(), targetName));
    },
    postHook: function postHook(cb) {
      if (!targetApp.posthook) return cb();

      // execute the actual command in the cwd of the application
      spawnAsExec(targetApp.posthook, execOptions,
          logCallback(cb, '[%s] Posthook command has been successfuly executed for app %s', new Date().toISOString(), targetName));
    }
  };
  async.series(Object.keys(phases).map(function(k){ return phases[k]; }),
    function (err, results) {
      if (err) {
        console.log('[%s] An error has occuring while processing app %s', new Date().toISOString(), targetName);
        console.error(err);
      }
    });
};

/**
 * Checks if a request is valid for an app.
 *
 * @param targetApp The app which the request has to be valid
 * @param req The request to analyze
 * @returns {string|true} True if success or the string of the error if not.
 */
Worker.prototype.checkRequest = function checkRequest(targetApp, req) {
  var targetName = reqToAppName(req);
  switch (targetApp.service) {
    case 'gitlab': {
      if (!req.headers['x-gitlab-token']) {
        return util.format('[%s] Received invalid request for app %s (no headers found)', new Date().toISOString(), targetName);
      }

      if (req.headers['x-gitlab-token'] !== targetApp.secret) {
        return util.format('[%s] Received invalid request for app %s (not matching secret)', new Date().toISOString(), targetName);
      }
      break;
    }
    case 'jenkins': {
      // ip must match the secret
      if (req.ip.indexOf(targetApp.secret) < 0) {
        return util.format('[%s] Received request from %s for app %s but ip configured was %s', new Date().toISOString(), req.ip, targetName, targetApp.secret);
      }

      var body = JSON.parse(req.body);
      if (body.build.status !== 'SUCCESS') {
        return util.format('[%s] Received valid hook but with failure build for app %s', new Date().toISOString(), targetName);
      }
      if (targetApp.branch && body.build.scm.branch.indexOf(targetApp.branch) < 0) {
        return util.format('[%s] Received valid hook but with a branch %s than configured for app %s', new Date().toISOString(), body.build.scm.branch, targetName);
      }
      break;
    }
    case 'droneci': {
      // Authorization header must match configured secret
      if (!req.headers['Authorization']) {
        return util.format('[%s] Received invalid request for app %s (no headers found)', new Date().toISOString(), targetName);
      }
      if (req.headers['Authorization'] !== targetApp.secret) {
        return util.format('[%s] Received request from %s for app %s but incorrect secret', new Date().toISOString(), req.ip, targetName);
      }

      var data = JSON.parse(req.body);
      if (data.build.status !== 'SUCCESS') {
        return util.format('[%s] Received valid hook but with failure build for app %s', new Date().toISOString(), targetName);
      }
      if (targetApp.branch && data.build.branch.indexOf(targetApp.branch) < 0) {
        return util.format('[%s] Received valid hook but with a branch %s than configured for app %s', new Date().toISOString(), data.build.branch, targetName);
      }
      break;
    }
    case 'bitbucket': {
      var tmp = JSON.parse(req.body);
      var ip = targetApp.secret || '104.192.143.0/24';
      var configured = ipaddr.parseCIDR(ip);
      var source = ipaddr.parse(req.ip);

      if (!source.match(configured)) {
        return util.format('[%s] Received request from %s for app %s but ip configured was %s', new Date().toISOString(), req.ip, targetName, ip);
      }
      if (!tmp.push) {
        return util.format("[%s] Received valid hook but without 'push' data for app %s", new Date().toISOString(), targetName);
      }
      if (targetApp.branch && tmp.push.changes[0] && tmp.push.changes[0].new.name.indexOf(targetApp.branch) < 0) {
        return util.format('[%s] Received valid hook but with a branch %s than configured for app %s', new Date().toISOString(), tmp.push.changes[0].new.name, targetName);
      }
      break;
    }
    case 'github' :
    default: {
      if (!req.headers['x-github-event'] || !req.headers['x-hub-signature']) {
        return util.format('[%s] Received invalid request for app %s (no headers found)', new Date().toISOString(), targetName);
      }

      // compute hash of body with secret, github should send this to verify authenticity
      var temp = crypto.createHmac('sha1', targetApp.secret);
      temp.update(req.body, 'utf-8');
      var hash = temp.digest('hex');

      if ('sha1=' + hash !== req.headers['x-hub-signature']) {
        return util.format('[%s] Received invalid request for app %s', new Date().toISOString(), targetName);
      }
      break;
    }
  }
  return false;
};

/**
 * Lets start our server
 */
Worker.prototype.start = function () {
  var self = this;
  this.server.listen(this.opts.port, function () {
    console.log('Server is ready and listen on port %s', self.port);
  });
};

/**
 * Executes the callback, but in case of success shows a message.
 * Also accepts extra arguments to pass to console.log.
 *
 * Example:
 * logCallback(next, '% worked perfect', appName)
 *
 * @param {Function} cb The callback to be called
 * @param {string} message The message to show if success
 * @returns {Function} The callback wrapped
 */
function logCallback(cb, message) {
  var wrappedArgs = Array.prototype.slice.call(arguments);
  return function (err, data) {
    if (err) return cb(err);

    wrappedArgs.shift();
    console.log.apply(console, wrappedArgs);
    cb();
  }
}

/**
 * Given a request, returns the name of the target App.
 *
 * Example:
 * Call to 34.23.34.54:3000/api-2
 * Will return 'api-2'
 *
 * @param req The request to be analysed
 * @returns {string|null} The name of the app, or null if not found.
 */
function reqToAppName(req) {
  var targetName = null;
  try {
    targetName = req.url.split('/').pop();
  } catch (e) {}
  return targetName || null;
}

/**
 * Wraps the node spawn function to work as exec (line, options, callback).
 * This avoid the maxBuffer issue, as no buffer will be stored.
 *
 * @param {string} command The line to execute
 * @param {object} options The options to pass to spawn
 * @param {function} cb The callback, called with error as first argument
 */
function spawnAsExec(command, options, cb) {
  var child = spawn('eval', [command], options);
  child.on('close', cb);
}
<|endoftext|>


<commit_before>// ------------------------------------------------------------------------------
// Tetra.js
// Native controller functions of Tetra.js
// ------------------------------------------------------------------------------
// Copyright (c) Viadeo/APVO Corp., Olivier Hory and other Tetra contributors.
//
// 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.
// ------------------------------------------------------------------------------
tetra.extend('controller', function(_conf, _mod, _) {

	var
		_controllers = {}, // controller objects
		_actions = {}, // actions for templating feature
		_debug
	;

	// DEBUG functions
	// --------------------
	_debug = {
		page: _mod.pipe.page,

		app: function(scope) {
			return _mod.pipe.appBuilder('controller', scope);
		},

		list: function() {
			var list = {};
			for(var name in _controllers) {
				if(_controllers.hasOwnProperty(name)) {
					_mod.debug.log(_controllers[name].scope + ' / ' + name);
					if(typeof list[_controllers[name].scope] === 'undefined') {
						list[_controllers[name].scope] = [];
					}
					list[_controllers[name].scope].push(name);
				}
			}
			return list;
		},

		retrieve : function(scope, name) {
		    var ctrl = _controllers[scope + "/" + name];
		    if(ctrl) {
		        ctrl.actions = _actions[scope + "/" + name];
		    }

			return ctrl;
		},

		msg: function(ctrlName) {
			var
				msgs = [],
				viewEvents
			;
			if(_controllers[ctrlName] && _controllers[ctrlName].events.view) {
				viewEvents = _controllers[ctrlName].events.view;
				for(var msg in viewEvents) {
					if(viewEvents.hasOwnProperty(msg)) {
						_mod.debug.log(msg);
						msgs.push(msg);
					}
				}
			} else {
				_mod.debug.log(ctrlName + ' was not found');
			}

			return msgs;
		},

		man : function() {
			_mod.debug.log('Tetra.js ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
			_mod.debug.log('> Controller specs:');
			_mod.debug.log('		- notify app controllers as a view		> tetra.debug.ctrl.app(scope).notify(message, data)');
			_mod.debug.log('		- notify all as a controller			> tetra.debug.ctrl.page.notify(message, data)');
			_mod.debug.log('		- list all controllers with their scope	> tetra.debug.ctrl.list()');
			_mod.debug.log('		- list all view messages listened		> tetra.debug.ctrl.msg(ctrlName)');
			_mod.debug.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');

			return true;
		}
	};

	// Instantiation
	// --------------------
	var Builder = function(ctrlName, params) {
		var
			me = this,
			app = _mod.pipe.appBuilder('view', params.scope),
			constr = params.constr(me, app, _mod.pipe.page, _mod.orm(params.scope))
		;

		this.scope = params.scope;
		this.events = constr.events;
		this.methods = constr.methods;

		_actions[ctrlName] = constr.actions;

		return this;
	};

	// Registers a controller when *all* its dependencies have been loaded.
	var _register = function(ctrlName, params) {
		_controllers[ctrlName] = new Builder(ctrlName, params);

		_mod.debug.log('controller ' + ctrlName + ' : registered', _controllers[ctrlName].scope, 'info');

		if(typeof _controllers[ctrlName].methods !== 'undefined' &&
				typeof _controllers[ctrlName].methods.init !== 'undefined') {
			_controllers[ctrlName].methods.init();
		}

		return _controllers[ctrlName];
	};

	// Interface implementation
	// --------------------
	return {
		// Registers a controller
		// Note that at a minimum a controller must be given a name, and a params object literal with
		// the following structure
		//
		// {
		//	scope: 'theScope',
		//  constr: function(me, app, page, orm) {
		//		return {
		//			events: {}
		//		};
		//  }
		// }
		register: function(name, params) {

			if(_conf.env === 'Node') params.scope = 'node';

			var
				ctrlName = params.scope + '/' + name
			;

			if(!name || !params) {
				throw new Error(
						"tetra.controller.register(name, params) : " +
						"name and params are both required arguments");
			}

			if(!params.hasOwnProperty('scope') || !params.hasOwnProperty('constr')) {
				throw new Error(
						"tetra.controller.register(name, params) : " +
						"params must define a scope attribute and a constr method");
			}

			if(_controllers[ctrlName]) {
				throw new Error(
						"A controller with the scope/name " + ctrlName + " already exists");
			}

			var deps = [], modelName;
			if(typeof params.use !== 'undefined') {
				for(var i = 0, len = params.use.length; i < len; i++) {
					modelName = params.use[i];
					if(modelName.substring(0,2) === 'g/') {
						modelName = modelName.substring(2);
						deps.push('g/model/'+ modelName +'.class');
					} else {
						deps.push(params.scope +'/model/'+ modelName +'.class');
					}
				}
			}

			_mod.dep.define(params.scope + '/controller/' + name +'.ctrl', deps, function() {
				_register(ctrlName, params);
			});

			_mod.dep.require([params.scope + '/controller/' + name +'.ctrl']);
		},

		destroy: function(name, scope) {
			var ctrlName = scope + '/' + name;

			_mod.dep.undef(scope + '/controller/' + name +'.ctrl');

			delete _controllers[ctrlName];
		},

		// Notification from views in the given scope
		notify: function(message, data, scope) {
			scope = scope || 'all';

			var ctrl, ctrlScope, ctrlView;

			for(var name in _controllers) {
				if(_controllers.hasOwnProperty(name)) {
					ctrl = _controllers[name];
					ctrlScope = ctrl.scope;

					if(scope === 'all' && ctrl.events.view || ctrl.events.controller) {
						ctrlListener = (scope !== 'all') ? ctrl.events.view : ctrl.events.controller;

						if((scope === 'all' || scope === ctrlScope) &&
								typeof ctrlListener[message] !== 'undefined') {
							_mod.debug.log('ctrl ' + name + ' : exec ' + message, scope, 'info');
							ctrlListener[message](data);
						}
					}
				}
			}
		},

		// Notification from models in the given scope
		modelNotify: function(modelName, type, args) {
			var thisCtrl;
			for(var ctrlName in _controllers) {
				if(_controllers.hasOwnProperty(ctrlName)) {
					thisCtrl = _controllers[ctrlName];
					if(thisCtrl.events && typeof thisCtrl.events.model !== 'undefined' &&
							typeof thisCtrl.events.model[modelName] !== 'undefined') {
						_mod.debug.log('ctrl ' + ctrlName + ' : model ' + modelName + ' ' + type, thisCtrl.scope, 'info');
						if(typeof thisCtrl.events.model[modelName][type] !== 'undefined') {
							thisCtrl.events.model[modelName][type].apply(thisCtrl, args);
						}
					}
				}
			}
		},

		exec: function(actionName, ctrlName, data, callback, scope, uid, cid) {
			var defaultTmpl;
			if(typeof ctrlName != 'string') {
				cid = uid;
				uid = scope;
				scope = callback;
				callback = data;
				data = ctrlName;
				ctrlName = undefined;

				defaultTmpl = actionName;
			} else {
				var ctrlId = scope + '/' + ctrlName;
				defaultTmpl = ctrlName + '/' + actionName;
			}

			var
				_render = function(data, template) {
					if (!template) template = defaultTmpl;
					_mod.tmpl(template, data, callback, scope, uid, cid);
				},

				_execute = function() {
					if(ctrlId && _actions[ctrlId] && _actions[ctrlId][actionName]) {
						_actions[ctrlId][actionName](data, _render);
					} else {
						_render(data);
					}
				}
			;

			if(ctrlName) {
				_mod.dep.require([scope + '/controller/' + ctrlName +'.ctrl'], _execute);
			} else {
				_execute();
			}
		},

		debug: _debug
	};
});
<commit_msg>Fix undefined variable<commit_after>// ------------------------------------------------------------------------------
// Tetra.js
// Native controller functions of Tetra.js
// ------------------------------------------------------------------------------
// Copyright (c) Viadeo/APVO Corp., Olivier Hory and other Tetra contributors.
//
// 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.
// ------------------------------------------------------------------------------
tetra.extend('controller', function(_conf, _mod, _) {

	var
		_controllers = {}, // controller objects
		_actions = {}, // actions for templating feature
		_debug
	;

	// DEBUG functions
	// --------------------
	_debug = {
		page: _mod.pipe.page,

		app: function(scope) {
			return _mod.pipe.appBuilder('controller', scope);
		},

		list: function() {
			var list = {};
			for(var name in _controllers) {
				if(_controllers.hasOwnProperty(name)) {
					_mod.debug.log(_controllers[name].scope + ' / ' + name);
					if(typeof list[_controllers[name].scope] === 'undefined') {
						list[_controllers[name].scope] = [];
					}
					list[_controllers[name].scope].push(name);
				}
			}
			return list;
		},

		retrieve : function(scope, name) {
		    var ctrl = _controllers[scope + "/" + name];
		    if(ctrl) {
		        ctrl.actions = _actions[scope + "/" + name];
		    }

			return ctrl;
		},

		msg: function(ctrlName) {
			var
				msgs = [],
				viewEvents
			;
			if(_controllers[ctrlName] && _controllers[ctrlName].events.view) {
				viewEvents = _controllers[ctrlName].events.view;
				for(var msg in viewEvents) {
					if(viewEvents.hasOwnProperty(msg)) {
						_mod.debug.log(msg);
						msgs.push(msg);
					}
				}
			} else {
				_mod.debug.log(ctrlName + ' was not found');
			}

			return msgs;
		},

		man : function() {
			_mod.debug.log('Tetra.js ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
			_mod.debug.log('> Controller specs:');
			_mod.debug.log('		- notify app controllers as a view		> tetra.debug.ctrl.app(scope).notify(message, data)');
			_mod.debug.log('		- notify all as a controller			> tetra.debug.ctrl.page.notify(message, data)');
			_mod.debug.log('		- list all controllers with their scope	> tetra.debug.ctrl.list()');
			_mod.debug.log('		- list all view messages listened		> tetra.debug.ctrl.msg(ctrlName)');
			_mod.debug.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');

			return true;
		}
	};

	// Instantiation
	// --------------------
	var Builder = function(ctrlName, params) {
		var
			me = this,
			app = _mod.pipe.appBuilder('view', params.scope),
			constr = params.constr(me, app, _mod.pipe.page, _mod.orm(params.scope))
		;

		this.scope = params.scope;
		this.events = constr.events;
		this.methods = constr.methods;

		_actions[ctrlName] = constr.actions;

		return this;
	};

	// Registers a controller when *all* its dependencies have been loaded.
	var _register = function(ctrlName, params) {
		_controllers[ctrlName] = new Builder(ctrlName, params);

		_mod.debug.log('controller ' + ctrlName + ' : registered', _controllers[ctrlName].scope, 'info');

		if(typeof _controllers[ctrlName].methods !== 'undefined' &&
				typeof _controllers[ctrlName].methods.init !== 'undefined') {
			_controllers[ctrlName].methods.init();
		}

		return _controllers[ctrlName];
	};

	// Interface implementation
	// --------------------
	return {
		// Registers a controller
		// Note that at a minimum a controller must be given a name, and a params object literal with
		// the following structure
		//
		// {
		//	scope: 'theScope',
		//  constr: function(me, app, page, orm) {
		//		return {
		//			events: {}
		//		};
		//  }
		// }
		register: function(name, params) {

			if(_conf.env === 'Node') params.scope = 'node';

			var
				ctrlName = params.scope + '/' + name
			;

			if(!name || !params) {
				throw new Error(
						"tetra.controller.register(name, params) : " +
						"name and params are both required arguments");
			}

			if(!params.hasOwnProperty('scope') || !params.hasOwnProperty('constr')) {
				throw new Error(
						"tetra.controller.register(name, params) : " +
						"params must define a scope attribute and a constr method");
			}

			if(_controllers[ctrlName]) {
				throw new Error(
						"A controller with the scope/name " + ctrlName + " already exists");
			}

			var deps = [], modelName;
			if(typeof params.use !== 'undefined') {
				for(var i = 0, len = params.use.length; i < len; i++) {
					modelName = params.use[i];
					if(modelName.substring(0,2) === 'g/') {
						modelName = modelName.substring(2);
						deps.push('g/model/'+ modelName +'.class');
					} else {
						deps.push(params.scope +'/model/'+ modelName +'.class');
					}
				}
			}

			_mod.dep.define(params.scope + '/controller/' + name +'.ctrl', deps, function() {
				_register(ctrlName, params);
			});

			_mod.dep.require([params.scope + '/controller/' + name +'.ctrl']);
		},

		destroy: function(name, scope) {
			var ctrlName = scope + '/' + name;

			_mod.dep.undef(scope + '/controller/' + name +'.ctrl');

			delete _controllers[ctrlName];
		},

		// Notification from views in the given scope
		notify: function(message, data, scope) {
			scope = scope || 'all';

			var ctrl, ctrlScope, ctrlListener;

			for(var name in _controllers) {
				if(_controllers.hasOwnProperty(name)) {
					ctrl = _controllers[name];
					ctrlScope = ctrl.scope;

					if(scope === 'all' && ctrl.events.view || ctrl.events.controller) {
						ctrlListener = (scope !== 'all') ? ctrl.events.view : ctrl.events.controller;

						if((scope === 'all' || scope === ctrlScope) &&
								typeof ctrlListener[message] !== 'undefined') {
							_mod.debug.log('ctrl ' + name + ' : exec ' + message, scope, 'info');
							ctrlListener[message](data);
						}
					}
				}
			}
		},

		// Notification from models in the given scope
		modelNotify: function(modelName, type, args) {
			var thisCtrl;
			for(var ctrlName in _controllers) {
				if(_controllers.hasOwnProperty(ctrlName)) {
					thisCtrl = _controllers[ctrlName];
					if(thisCtrl.events && typeof thisCtrl.events.model !== 'undefined' &&
							typeof thisCtrl.events.model[modelName] !== 'undefined') {
						_mod.debug.log('ctrl ' + ctrlName + ' : model ' + modelName + ' ' + type, thisCtrl.scope, 'info');
						if(typeof thisCtrl.events.model[modelName][type] !== 'undefined') {
							thisCtrl.events.model[modelName][type].apply(thisCtrl, args);
						}
					}
				}
			}
		},

		exec: function(actionName, ctrlName, data, callback, scope, uid, cid) {
			var defaultTmpl;
			if(typeof ctrlName != 'string') {
				cid = uid;
				uid = scope;
				scope = callback;
				callback = data;
				data = ctrlName;
				ctrlName = undefined;

				defaultTmpl = actionName;
			} else {
				var ctrlId = scope + '/' + ctrlName;
				defaultTmpl = ctrlName + '/' + actionName;
			}

			var
				_render = function(data, template) {
					if (!template) template = defaultTmpl;
					_mod.tmpl(template, data, callback, scope, uid, cid);
				},

				_execute = function() {
					if(ctrlId && _actions[ctrlId] && _actions[ctrlId][actionName]) {
						_actions[ctrlId][actionName](data, _render);
					} else {
						_render(data);
					}
				}
			;

			if(ctrlName) {
				_mod.dep.require([scope + '/controller/' + ctrlName +'.ctrl'], _execute);
			} else {
				_execute();
			}
		},

		debug: _debug
	};
});
<|endoftext|>