<commit_before>import Vue from 'vue';
import _ from 'lodash';
import delegate from 'delegate';
import store from '../core-data/store';
import { prependChild, closest } from '@nymag/dom';
import { refAttr, layoutAttr, editAttr, refProp, componentListProp, componentProp, getComponentName, isComponent } from '../utils/references';
import { getComponentEl, getFieldEl } from '../utils/component-elements';
import { getData, getSchema } from '../core-data/components';
import { getEventPath } from '../utils/events';
import logger from '../utils/log';

const log = logger(__filename),
  delegated = {};

/**
 * handle clicks on the component itself
 * @param {string} uri
 * @param {MouseEvent} e
 */
function componentClickHandler(uri, e) {
  const targetComponent = getComponentEl(e.target);

  // allow events to propagate upwards, but set a flag
  // this allows the document event listener to catch the events and unfocus forms,
  // but prevents the same document event listener from unselecting the current component
  // when the event propagates up to it
  if (!e.stopSelection && uri === targetComponent.getAttribute(refAttr)) {
    e.stopSelection = true;

    if (!targetComponent.classList.contains('selected')) {
      // note: we don't unfocus before selecting another component,
      // since that would cause double-saving in certain scenarios
      // (legacy components that need to send data to the server before re-rendering)
      store.dispatch('select', targetComponent);
    }
  }
}

/**
 * get parent field (and type of field) that child component lives in
 * note: this sends warnings to the console if it's missing schema stuff
 * @param  {string} child  uri
 * @param  {string} parent uri
 * @return {object}
 */
export function getParentField(child, parent) {
  const parentData = getData(parent),
    path = _.findKey(parentData, (prop) => {
      if (_.isArray(prop)) {
        return _.find(prop, (item) => item[refProp] === child);
      } else if (_.isObject(prop)) {
        return prop[refProp] === child;
      }
    });

  if (path) {
    const schema = getSchema(parent),
      el = getFieldEl(parent, path),
      isFieldEditable = !!el && el.hasAttribute(editAttr);

    if (_.has(schema, `${path}.${componentListProp}`)) {
      return { path, type: 'list', isEditable: isFieldEditable };
    } else if (_.has(schema, `${path}.${componentProp}`)) {
      return { path, type: 'prop', isEditable: isFieldEditable };
    } else {
      log.warn(`${getComponentName(parent)} has no field for ${path} in its schema, but has ${getComponentName(child)} in its data`, { action: 'getParentField' });
      // note: the selector buttons that rely on isEditable will not display (since there's no type),
      // but this will expose more information for developers to troubleshoot their schemae
      return { path, isEditable: isFieldEditable };
    }
  } else {
    return {};
  }
}

/**
 * add selector to element
 * @param {string} uri
 * @param {element} el  root element of component
 */
export function addSelector(uri, el) {
  const selectorTpl = require('./selector.vue'),
    Selector = Vue.component('selector', selectorTpl);
  let selector = new Selector({ store, componentEl: el}).$mount();

  // make sure components are relatively positioned
  el.classList.add('component-selector-wrapper');

  if (parent) {
    if (delegated[uri]) {
      // destroy delegated handlers before adding new ones (e.g. when re-rendering)
      delegated[uri].destroy();
    }

    delegated[uri] = delegate(document.body, `[${refAttr}="${uri}"]`, 'click', componentClickHandler.bind(null, uri), false);

    // add global mouseover handler if it hasn't been added yet
    if (!delegated.bodyMouseover) {
      delegated.bodyMouseover = document.body.addEventListener('mouseover', _.debounce((e) => {
        const closestComponent = closest(e.target, `[${refAttr}]`);

        if (closestComponent &&
            isComponent(closestComponent.getAttribute(refAttr)) && // if hovering over a component
            getComponentName(closestComponent.getAttribute(refAttr)) !== 'clay-kiln' && // and that component isn't kiln
            !_.get(store, 'state.ui.currentForm') && // and there are no forms open
            !closestComponent.classList.contains('selected')) { // and the hovered component isn't selected
          store.dispatch('select', closestComponent); // ...select it!
        } else if (closestComponent &&
            !isComponent(closestComponent.getAttribute(refAttr)) && // if hovering over something that isn't a component
            !_.get(store, 'state.ui.currentForm')) { // and there are no forms open
          // unselect if mousing back over the page
          store.dispatch('unselect');
        }
      }, 300));
    }

    // add selector to the component el, BEHIND the component's children
    prependChild(el, selector.$el);
  }
}

/**
 * determine if a user has clicked into a focusable element
 * @param  {MouseEvent}  e
 * @return {Boolean}
 */
export function hasClickedSelectableEl(e) {
  return !!_.find(getEventPath(e), (node) => node.nodeType &&
    node.nodeType === node.ELEMENT_NODE &&
    node.hasAttribute(refAttr) &&
    !node.hasAttribute(layoutAttr) &&
    getComponentName(node.getAttribute(refAttr)) !== 'clay-kiln');
}
<commit_msg>optimized mouseover<commit_after>import Vue from 'vue';
import _ from 'lodash';
import delegate from 'delegate';
import store from '../core-data/store';
import { prependChild, closest } from '@nymag/dom';
import { refAttr, layoutAttr, editAttr, refProp, componentListProp, componentProp, getComponentName, isComponent } from '../utils/references';
import { getComponentEl, getFieldEl } from '../utils/component-elements';
import { getData, getSchema } from '../core-data/components';
import { getEventPath } from '../utils/events';
import logger from '../utils/log';

const log = logger(__filename),
  delegated = {};

/**
 * handle clicks on the component itself
 * @param {string} uri
 * @param {MouseEvent} e
 */
function componentClickHandler(uri, e) {
  const targetComponent = getComponentEl(e.target);

  // allow events to propagate upwards, but set a flag
  // this allows the document event listener to catch the events and unfocus forms,
  // but prevents the same document event listener from unselecting the current component
  // when the event propagates up to it
  if (!e.stopSelection && uri === targetComponent.getAttribute(refAttr)) {
    e.stopSelection = true;

    if (!targetComponent.classList.contains('selected')) {
      // note: we don't unfocus before selecting another component,
      // since that would cause double-saving in certain scenarios
      // (legacy components that need to send data to the server before re-rendering)
      store.dispatch('select', targetComponent);
    }
  }
}

/**
 * get parent field (and type of field) that child component lives in
 * note: this sends warnings to the console if it's missing schema stuff
 * @param  {string} child  uri
 * @param  {string} parent uri
 * @return {object}
 */
export function getParentField(child, parent) {
  const parentData = getData(parent),
    path = _.findKey(parentData, (prop) => {
      if (_.isArray(prop)) {
        return _.find(prop, (item) => item[refProp] === child);
      } else if (_.isObject(prop)) {
        return prop[refProp] === child;
      }
    });

  if (path) {
    const schema = getSchema(parent),
      el = getFieldEl(parent, path),
      isFieldEditable = !!el && el.hasAttribute(editAttr);

    if (_.has(schema, `${path}.${componentListProp}`)) {
      return { path, type: 'list', isEditable: isFieldEditable };
    } else if (_.has(schema, `${path}.${componentProp}`)) {
      return { path, type: 'prop', isEditable: isFieldEditable };
    } else {
      log.warn(`${getComponentName(parent)} has no field for ${path} in its schema, but has ${getComponentName(child)} in its data`, { action: 'getParentField' });
      // note: the selector buttons that rely on isEditable will not display (since there's no type),
      // but this will expose more information for developers to troubleshoot their schemae
      return { path, isEditable: isFieldEditable };
    }
  } else {
    return {};
  }
}

/**
 * add selector to element
 * @param {string} uri
 * @param {element} el  root element of component
 */
export function addSelector(uri, el) {
  const selectorTpl = require('./selector.vue'),
    Selector = Vue.component('selector', selectorTpl);
  let selector = new Selector({ store, componentEl: el}).$mount();

  // make sure components are relatively positioned
  el.classList.add('component-selector-wrapper');

  if (parent) {
    if (delegated[uri]) {
      // destroy delegated handlers before adding new ones (e.g. when re-rendering)
      delegated[uri].destroy();
    }

    delegated[uri] = delegate(document.body, `[${refAttr}="${uri}"]`, 'click', componentClickHandler.bind(null, uri), false);

    // add global mouseover handler if it hasn't been added yet
    if (!delegated.bodyMouseover) {
      delegated.bodyMouseover = true;
      document.body.addEventListener('mouseover', _.debounce((e) => {
        const closestComponent = closest(e.target, `[${refAttr}]`);

        if (closestComponent &&
            isComponent(closestComponent.getAttribute(refAttr)) && // if hovering over a component
            getComponentName(closestComponent.getAttribute(refAttr)) !== 'clay-kiln' && // and that component isn't kiln
            !_.get(store, 'state.ui.currentForm') && // and there are no forms open
            !closestComponent.classList.contains('selected')) { // and the hovered component isn't selected
          store.dispatch('select', closestComponent); // ...select it!
        } else if (closestComponent &&
            !isComponent(closestComponent.getAttribute(refAttr)) && // if hovering over something that isn't a component
            !_.get(store, 'state.ui.currentForm')) { // and there are no forms open
          // unselect if mousing back over the page
          store.dispatch('unselect');
        }
      }, 300));
    }

    // add selector to the component el, BEHIND the component's children
    prependChild(el, selector.$el);
  }
}

/**
 * determine if a user has clicked into a focusable element
 * @param  {MouseEvent}  e
 * @return {Boolean}
 */
export function hasClickedSelectableEl(e) {
  return !!_.find(getEventPath(e), (node) => node.nodeType &&
    node.nodeType === node.ELEMENT_NODE &&
    node.hasAttribute(refAttr) &&
    !node.hasAttribute(layoutAttr) &&
    getComponentName(node.getAttribute(refAttr)) !== 'clay-kiln');
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2012 Andreas Madsen
 * MIT License
 */

(function () {
  "use strict";

  var helpers = require('./helpers.js');
  var path = require('path');
  var core = require(path.join(helpers.core, 'core.js'));

  // get and parse the options
  var options = helpers.getOptions();

  var child;
  if (options.mode === 'unattached') {
    child = core.spawnPump(options);
  } else if (options.mode === 'daemon') {
    child = core.spawnDaemon(options);
  }

  child.close(function () {
    process.exit(0);
  });

})();
<commit_msg>[refactor] update execute.js file after core refactor<commit_after>/**
 * Copyright (c) 2012 Andreas Madsen
 * MIT License
 */

(function () {
  "use strict";

  var helpers = require('./helpers.js');
  var path = require('path');
  var core = require(path.join(helpers.core, 'core.js'));

  // get and parse the options
  var options = JSON.stringify(process.env.nestedOptions);

  var child;
  if (options.mode === 'unattached') {
    child = core.spawnPump(options);
  } else if (options.mode === 'daemon') {
    child = core.spawnDaemon(options);
  }

  child.close(function () {
    process.exit(0);
  });

})();
<|endoftext|>


<commit_before>var async  = require('async'),
    fs     = require('fs'),
    glob   = require('glob'),
    path   = require('path'),
    semver = require('semver');

// -- Utilites -----------------------------------------------------------------

function extend(obj) {
    Array.prototype.slice.call(arguments, 1).forEach(function (source) {
        if (!source) { return; }

        for (var key in source) {
            obj[key] = source[key];
        }
    });

    return obj;
}

function getHandlebarsSemver(handlebars) {
    var version = handlebars.VERSION || '';

    // Makes sure the Handlebars version is a valid semver.
    if (version && !semver.valid(version)) {
        version = version.replace(/(\d\.\d)\.(\D.*)/, '$1.0-$2');
    }

    return version;
}

// -- Constructor --------------------------------------------------------------

function ExpressHandlebars(config) {
    config || (config = {});

    var handlebars = config.handlebars || require('handlebars');

    if ('extname'     in config) { this.extname     = config.extname;     }
    if ('layoutsDir'  in config) { this.layoutsDir  = config.layoutsDir;  }
    if ('partialsDir' in config) { this.partialsDir = config.partialsDir; }

    this.defaultLayout     = config.defaultLayout;
    this.handlebars        = handlebars;
    this.handlebarsVersion = getHandlebarsSemver(handlebars);
    this.helpers           = extend({}, handlebars.helpers, config.helpers);

    this.compiled    = {};
    this.precompiled = {};

    this.engine = this.renderView.bind(this);
}

ExpressHandlebars._dirCache     = {};
ExpressHandlebars._fileCache    = {};
ExpressHandlebars._pendingReads = {};

extend(ExpressHandlebars.prototype, {
    // -- Public Properties ----------------------------------------------------

    extname    : '.handlebars',
    layoutsDir : 'views/layouts/',
    partialsDir: 'views/partials/',

    // -- Public Methods -------------------------------------------------------

    loadPartials: function (options, callback) {
        if (typeof options === 'function') {
            callback = options;
            options  = {};
        }

        options || (options = {});

        var partialsDir = this.partialsDir;

        function loadPartial(filePath, callback) {
            filePath = path.join(partialsDir, filePath);
            this.loadTemplate(filePath, options, callback);
        }

        function loadPartials(filePaths, callback) {
            async.map(filePaths, loadPartial.bind(this), function (err, partials) {
                callback(err, filePaths, partials);
            });
        }

        function mapPartials(filePaths, partials, callback) {
            var getPartialName = this._getPartialName.bind(this),
                partialsMap    = {};

            filePaths.forEach(function (filePath, i) {
                partialsMap[getPartialName(filePath)] = partials[i];
            }, this);

            callback(null, partialsMap);
        }

        async.waterfall([
            this._loadDir.bind(this, partialsDir, options),
            loadPartials.bind(this),
            mapPartials.bind(this)
        ], callback);
    },

    loadTemplate: function (filePath, options, callback) {
        filePath = path.resolve(filePath);

        if (typeof options === 'function') {
            callback = options;
            options  = {};
        }

        options || (options = {});

        var precompiled = options.precompiled,
            cache       = precompiled ? this.precompiled : this.compiled,
            template    = options.cache && cache[filePath],
            compile;

        if (template) {
            callback(null, template);
            return;
        }

        compile = this.handlebars[precompiled ? 'precompile' : 'compile'];

        this._loadFile(filePath, options, function (err, file) {
            if (err) { return callback(err); }

            try {
                template = cache[filePath] = compile(file);
                callback(null, template);
            } catch (ex) {
                callback(ex);
            }
        });
    },

    render: function (filePath, options, callback) {
        if (typeof options === 'function') {
            callback = options;
            options  = {};
        }

        options || (options = {});

        function loadTemplates(callback) {
            async.parallel({
                partials: this.loadPartials.bind(this, options),
                template: this.loadTemplate.bind(this, filePath, options)
            }, callback);
        }

        function renderTemplate(templates, callback) {
            this._renderTemplate(templates.template, options, {
                helpers : this.helpers,
                partials: templates.partials
            }, callback);
        }

        // Force `{precompiled: false}` option, before passing options along to
        // `getPartials()` and `getTemplate()` methods.
        if (options.precompiled) {
            options = extend({}, options, {precompiled: false});
        }

        async.waterfall([
            loadTemplates.bind(this),
            renderTemplate.bind(this)
        ], callback);
    },

    renderView: function (viewPath, options, callback) {
        if (typeof options === 'function') {
            callback = options;
            options  = {};
        }

        options || (options = {});

        var layoutPath = 'layout' in options ? options.layout :
                this.defaultLayout;

        function renderLayout(body, callback) {
            var context = extend({}, options, {body: body});
            this.render(layoutPath, context, callback);
        }

        // Simple render when no layout is used.
        if (!layoutPath) {
            this.render.apply(this, arguments);
            return;
        }

        layoutPath = this._resolveLayoutPath(layoutPath);

        // Force `{precompiled: false}` option, before passing options along to
        // `getPartials()` and `getTemplate()` methods.
        if (options.precompiled) {
            options = extend({}, options, {precompiled: false});
        }

        async.waterfall([
            this.render.bind(this, viewPath, options),
            renderLayout.bind(this)
        ], callback);
    },

    // -- Private Methods ------------------------------------------------------

    _getPartialName: function (filePath) {
        var extRegex = new RegExp(this.extname + '$'),
            name     = filePath.replace(extRegex, ''),
            version  = this.handlebarsVersion;

        // Fixes a Handlebars bug in versions prior to 1.0.rc.2 which caused
        // partials with "/"s in their name to not be found.
        // https://github.com/wycats/handlebars.js/pull/389
        if (version && !semver.satisfies(version, '>=1.0.0-rc.2')) {
            name = name.replace('/', '.');
        }

        return name;
    },

    _loadDir: function (dirPath, options, callback) {
        dirPath = path.resolve(dirPath);

        var dirCache     = ExpressHandlebars._dirCache,
            pendingReads = ExpressHandlebars._pendingReads,
            dir          = options.cache && dirCache[dirPath],
            callbacks, pattern;

        if (dir) {
            callback(null, dir.concat());
            return;
        }

        callbacks = pendingReads[dirPath];

        if (callbacks) {
            callbacks.push(callback);
            return;
        }

        callbacks = pendingReads[dirPath] = [callback];
        pattern   = '**/*' + this.extname;

        glob(pattern, {cwd: dirPath}, function (err, dir) {
            if (!err) {
                dirCache[dirPath] = dir;
            }

            while (callbacks.length) {
                callbacks.shift().call(null, err, dir && dir.concat());
            }

            delete pendingReads[dirPath];
        });
    },

    _loadFile: function (filePath, options, callback) {
        filePath = path.resolve(filePath);

        var fileCache    = ExpressHandlebars._fileCache,
            pendingReads = ExpressHandlebars._pendingReads,
            file         = options.cache && fileCache[filePath],
            callbacks;

        if (file) {
            callback(null, file);
            return;
        }

        callbacks = pendingReads[filePath];

        if (callbacks) {
            callbacks.push(callback);
            return;
        }

        callbacks = pendingReads[filePath] = [callback];

        fs.readFile(filePath, 'utf8', function (err, file) {
            if (!err) {
                fileCache[filePath] = file;
            }

            while (callbacks.length) {
                callbacks.shift().call(null, err, file);
            }

            delete pendingReads[filePath];
        });
    },

    _renderTemplate: function (template, context, options, callback) {
        var output;

        try {
            output = template(context, options);
            callback(null, output);
        } catch (ex) {
            callback(ex);
        }
    },

    _resolveLayoutPath: function (layoutPath) {
        if (!path.extname(layoutPath)) {
            layoutPath += this.extname;
        }

        if (layoutPath[0] !== '/') {
            layoutPath = path.join(this.layoutsDir, layoutPath);
        }

        return layoutPath;
    }
});

// Aliases for back-compat.
ExpressHandlebars.prototype.getPartials = ExpressHandlebars.prototype.loadPartials;
ExpressHandlebars.prototype.getTemplate = ExpressHandlebars.prototype.loadTemplate;

// -- Exports ------------------------------------------------------------------

function exphbs(config) {
    return exphbs.create(config).engine;
}

exphbs.create = function (config) {
    return new ExpressHandlebars(config);
};

exphbs.ExpressHandlebars = ExpressHandlebars;

module.exports = exphbs;
<commit_msg>Rearrange property initialization in ExpressHandlebars constructor<commit_after>var async  = require('async'),
    fs     = require('fs'),
    glob   = require('glob'),
    path   = require('path'),
    semver = require('semver');

// -- Utilites -----------------------------------------------------------------

function extend(obj) {
    Array.prototype.slice.call(arguments, 1).forEach(function (source) {
        if (!source) { return; }

        for (var key in source) {
            obj[key] = source[key];
        }
    });

    return obj;
}

function getHandlebarsSemver(handlebars) {
    var version = handlebars.VERSION || '';

    // Makes sure the Handlebars version is a valid semver.
    if (version && !semver.valid(version)) {
        version = version.replace(/(\d\.\d)\.(\D.*)/, '$1.0-$2');
    }

    return version;
}

// -- Constructor --------------------------------------------------------------

function ExpressHandlebars(config) {
    config || (config = {});

    var handlebars = config.handlebars || require('handlebars');

    if ('extname'     in config) { this.extname     = config.extname;     }
    if ('layoutsDir'  in config) { this.layoutsDir  = config.layoutsDir;  }
    if ('partialsDir' in config) { this.partialsDir = config.partialsDir; }

    this.defaultLayout = config.defaultLayout;
    this.handlebars    = handlebars;
    this.helpers       = extend({}, handlebars.helpers, config.helpers);

    this.handlebarsVersion = getHandlebarsSemver(handlebars);

    this.compiled    = {};
    this.precompiled = {};

    this.engine = this.renderView.bind(this);
}

ExpressHandlebars._dirCache     = {};
ExpressHandlebars._fileCache    = {};
ExpressHandlebars._pendingReads = {};

extend(ExpressHandlebars.prototype, {
    // -- Public Properties ----------------------------------------------------

    extname    : '.handlebars',
    layoutsDir : 'views/layouts/',
    partialsDir: 'views/partials/',

    // -- Public Methods -------------------------------------------------------

    loadPartials: function (options, callback) {
        if (typeof options === 'function') {
            callback = options;
            options  = {};
        }

        options || (options = {});

        var partialsDir = this.partialsDir;

        function loadPartial(filePath, callback) {
            filePath = path.join(partialsDir, filePath);
            this.loadTemplate(filePath, options, callback);
        }

        function loadPartials(filePaths, callback) {
            async.map(filePaths, loadPartial.bind(this), function (err, partials) {
                callback(err, filePaths, partials);
            });
        }

        function mapPartials(filePaths, partials, callback) {
            var getPartialName = this._getPartialName.bind(this),
                partialsMap    = {};

            filePaths.forEach(function (filePath, i) {
                partialsMap[getPartialName(filePath)] = partials[i];
            }, this);

            callback(null, partialsMap);
        }

        async.waterfall([
            this._loadDir.bind(this, partialsDir, options),
            loadPartials.bind(this),
            mapPartials.bind(this)
        ], callback);
    },

    loadTemplate: function (filePath, options, callback) {
        filePath = path.resolve(filePath);

        if (typeof options === 'function') {
            callback = options;
            options  = {};
        }

        options || (options = {});

        var precompiled = options.precompiled,
            cache       = precompiled ? this.precompiled : this.compiled,
            template    = options.cache && cache[filePath],
            compile;

        if (template) {
            callback(null, template);
            return;
        }

        compile = this.handlebars[precompiled ? 'precompile' : 'compile'];

        this._loadFile(filePath, options, function (err, file) {
            if (err) { return callback(err); }

            try {
                template = cache[filePath] = compile(file);
                callback(null, template);
            } catch (ex) {
                callback(ex);
            }
        });
    },

    render: function (filePath, options, callback) {
        if (typeof options === 'function') {
            callback = options;
            options  = {};
        }

        options || (options = {});

        function loadTemplates(callback) {
            async.parallel({
                partials: this.loadPartials.bind(this, options),
                template: this.loadTemplate.bind(this, filePath, options)
            }, callback);
        }

        function renderTemplate(templates, callback) {
            this._renderTemplate(templates.template, options, {
                helpers : this.helpers,
                partials: templates.partials
            }, callback);
        }

        // Force `{precompiled: false}` option, before passing options along to
        // `getPartials()` and `getTemplate()` methods.
        if (options.precompiled) {
            options = extend({}, options, {precompiled: false});
        }

        async.waterfall([
            loadTemplates.bind(this),
            renderTemplate.bind(this)
        ], callback);
    },

    renderView: function (viewPath, options, callback) {
        if (typeof options === 'function') {
            callback = options;
            options  = {};
        }

        options || (options = {});

        var layoutPath = 'layout' in options ? options.layout :
                this.defaultLayout;

        function renderLayout(body, callback) {
            var context = extend({}, options, {body: body});
            this.render(layoutPath, context, callback);
        }

        // Simple render when no layout is used.
        if (!layoutPath) {
            this.render.apply(this, arguments);
            return;
        }

        layoutPath = this._resolveLayoutPath(layoutPath);

        // Force `{precompiled: false}` option, before passing options along to
        // `getPartials()` and `getTemplate()` methods.
        if (options.precompiled) {
            options = extend({}, options, {precompiled: false});
        }

        async.waterfall([
            this.render.bind(this, viewPath, options),
            renderLayout.bind(this)
        ], callback);
    },

    // -- Private Methods ------------------------------------------------------

    _getPartialName: function (filePath) {
        var extRegex = new RegExp(this.extname + '$'),
            name     = filePath.replace(extRegex, ''),
            version  = this.handlebarsVersion;

        // Fixes a Handlebars bug in versions prior to 1.0.rc.2 which caused
        // partials with "/"s in their name to not be found.
        // https://github.com/wycats/handlebars.js/pull/389
        if (version && !semver.satisfies(version, '>=1.0.0-rc.2')) {
            name = name.replace('/', '.');
        }

        return name;
    },

    _loadDir: function (dirPath, options, callback) {
        dirPath = path.resolve(dirPath);

        var dirCache     = ExpressHandlebars._dirCache,
            pendingReads = ExpressHandlebars._pendingReads,
            dir          = options.cache && dirCache[dirPath],
            callbacks, pattern;

        if (dir) {
            callback(null, dir.concat());
            return;
        }

        callbacks = pendingReads[dirPath];

        if (callbacks) {
            callbacks.push(callback);
            return;
        }

        callbacks = pendingReads[dirPath] = [callback];
        pattern   = '**/*' + this.extname;

        glob(pattern, {cwd: dirPath}, function (err, dir) {
            if (!err) {
                dirCache[dirPath] = dir;
            }

            while (callbacks.length) {
                callbacks.shift().call(null, err, dir && dir.concat());
            }

            delete pendingReads[dirPath];
        });
    },

    _loadFile: function (filePath, options, callback) {
        filePath = path.resolve(filePath);

        var fileCache    = ExpressHandlebars._fileCache,
            pendingReads = ExpressHandlebars._pendingReads,
            file         = options.cache && fileCache[filePath],
            callbacks;

        if (file) {
            callback(null, file);
            return;
        }

        callbacks = pendingReads[filePath];

        if (callbacks) {
            callbacks.push(callback);
            return;
        }

        callbacks = pendingReads[filePath] = [callback];

        fs.readFile(filePath, 'utf8', function (err, file) {
            if (!err) {
                fileCache[filePath] = file;
            }

            while (callbacks.length) {
                callbacks.shift().call(null, err, file);
            }

            delete pendingReads[filePath];
        });
    },

    _renderTemplate: function (template, context, options, callback) {
        var output;

        try {
            output = template(context, options);
            callback(null, output);
        } catch (ex) {
            callback(ex);
        }
    },

    _resolveLayoutPath: function (layoutPath) {
        if (!path.extname(layoutPath)) {
            layoutPath += this.extname;
        }

        if (layoutPath[0] !== '/') {
            layoutPath = path.join(this.layoutsDir, layoutPath);
        }

        return layoutPath;
    }
});

// Aliases for back-compat.
ExpressHandlebars.prototype.getPartials = ExpressHandlebars.prototype.loadPartials;
ExpressHandlebars.prototype.getTemplate = ExpressHandlebars.prototype.loadTemplate;

// -- Exports ------------------------------------------------------------------

function exphbs(config) {
    return exphbs.create(config).engine;
}

exphbs.create = function (config) {
    return new ExpressHandlebars(config);
};

exphbs.ExpressHandlebars = ExpressHandlebars;

module.exports = exphbs;
<|endoftext|>


<commit_before>'use strict';

var hasOwnProperty = Object.prototype.hasOwnProperty;

function each(processChunk, list) {
    var cursor = list.head;

    while (cursor !== null) {
        this.generate(processChunk, cursor.data, cursor, list);
        cursor = cursor.next;
    }
}

function eachComma(processChunk, list) {
    var cursor = list.head;

    while (cursor !== null) {
        if (cursor.prev) {
            processChunk(',');
        }

        this.generate(processChunk, cursor.data, cursor, list);
        cursor = cursor.next;
    }
}

function createGenerator(types) {
    var context = {
        generate: function(processChunk, node, item, list) {
            if (hasOwnProperty.call(types, node.type)) {
                types[node.type].call(this, processChunk, node, item, list);
            } else {
                throw new Error('Unknown node type: ' + node.type);
            }
        },
        each: each,
        eachComma: eachComma
    };

    return function(node, fn) {
        if (typeof fn !== 'function') {
            var buffer = [];
            context.generate(function(chunk) {
                buffer.push(chunk);
            }, node);
            return buffer.join('');
        }
        context.generate(fn, node);
    };
}

function createMarkupGenerator(types) {
    var context = {
        generate: function(buffer, node, item, list) {
            if (hasOwnProperty.call(types, node.type)) {
                var nodeBuffer = [];
                types[node.type].call(this, function(chunk) {
                    nodeBuffer.push(chunk);
                }, node, item, list);
                buffer({
                    node: node,
                    value: nodeBuffer
                });
            } else {
                throw new Error('Unknown node type: ' + node.type);
            }
        },
        each: each,
        eachComma: eachComma
    };

    return function(node, before, after) {
        function walk(node, buffer) {
            var value = node.value;

            before(node.node, buffer, value);

            if (typeof value === 'string') {
                buffer += value;
            } else {
                for (var i = 0; i < value.length; i++) {
                    if (typeof value[i] === 'string') {
                        buffer += value[i];
                    } else {
                        buffer = walk(value[i], buffer);
                    }
                }
            }

            after(node.node, buffer, value);

            return buffer;
        }

        if (typeof before !== 'function') {
            before = function() {};
        }
        if (typeof after !== 'function') {
            after = function() {};
        }

        var buffer = [];
        context.generate(function() {
            buffer.push.apply(buffer, arguments);
        }, node);
        return walk(buffer[0], '');
    };
}

module.exports = {
    createGenerator: createGenerator,
    createMarkupGenerator: createMarkupGenerator,
    sourceMap: require('./sourceMap')
};
<commit_msg>internal renaming<commit_after>'use strict';

var hasOwnProperty = Object.prototype.hasOwnProperty;

function each(processChunk, list) {
    var cursor = list.head;

    while (cursor !== null) {
        this.generate(processChunk, cursor.data, cursor, list);
        cursor = cursor.next;
    }
}

function eachComma(processChunk, list) {
    var cursor = list.head;

    while (cursor !== null) {
        if (cursor.prev) {
            processChunk(',');
        }

        this.generate(processChunk, cursor.data, cursor, list);
        cursor = cursor.next;
    }
}

function createGenerator(types) {
    var context = {
        generate: function(processChunk, node, item, list) {
            if (hasOwnProperty.call(types, node.type)) {
                types[node.type].call(this, processChunk, node, item, list);
            } else {
                throw new Error('Unknown node type: ' + node.type);
            }
        },
        each: each,
        eachComma: eachComma
    };

    return function(node, fn) {
        if (typeof fn !== 'function') {
            var buffer = [];
            context.generate(function(chunk) {
                buffer.push(chunk);
            }, node);
            return buffer.join('');
        }
        context.generate(fn, node);
    };
}

function createMarkupGenerator(types) {
    var context = {
        generate: function(processChunk, node, item, list) {
            if (hasOwnProperty.call(types, node.type)) {
                var nodeBuffer = [];
                types[node.type].call(this, function(chunk) {
                    nodeBuffer.push(chunk);
                }, node, item, list);
                processChunk({
                    node: node,
                    value: nodeBuffer
                });
            } else {
                throw new Error('Unknown node type: ' + node.type);
            }
        },
        each: each,
        eachComma: eachComma
    };

    return function(node, before, after) {
        function walk(node, buffer) {
            var value = node.value;

            before(node.node, buffer, value);

            if (typeof value === 'string') {
                buffer += value;
            } else {
                for (var i = 0; i < value.length; i++) {
                    if (typeof value[i] === 'string') {
                        buffer += value[i];
                    } else {
                        buffer = walk(value[i], buffer);
                    }
                }
            }

            after(node.node, buffer, value);

            return buffer;
        }

        if (typeof before !== 'function') {
            before = function() {};
        }
        if (typeof after !== 'function') {
            after = function() {};
        }

        var buffer = [];
        context.generate(function() {
            buffer.push.apply(buffer, arguments);
        }, node);
        return walk(buffer[0], '');
    };
}

module.exports = {
    createGenerator: createGenerator,
    createMarkupGenerator: createMarkupGenerator,
    sourceMap: require('./sourceMap')
};
<|endoftext|>


<commit_before>var fs = require('fs');
var crypto = require('crypto');
var path = require('path');
var url = require('url');

module.exports = function favicons(dir, opts) {
  dir = dir || process.cwd() + '/public';
  opts = opts || {};

  var cache = Object.create(null);
  var maxAge = opts.maxAge || 86400000;
  var filenames = [
    'favicon.ico',
    'apple-touch-icon.png',
    'apple-touch-icon-precomposed.png',
    'apple-touch-icon-57x57.png',
    'apple-touch-icon-57x57-precomposed.png',
    'apple-touch-icon-72x72.png',
    'apple-touch-icon-72x72-precomposed.png',
    'apple-touch-icon-114x114.png',
    'apple-touch-icon-114x114-precomposed.png',
    'apple-touch-icon-144x144.png',
    'apple-touch-icon-144x144-precomposed.png'
  ];

  return function favicons(req, res, next) {
    var pathname = url.parse(req.url).pathname;
    var basename = path.basename(pathname);
    var index = filenames.indexOf(basename);
    var cached;
    var extname;

    if ( pathname.split('/').length > 2 ) {
      return next();
    }

    if ( index < 0 ) {
      return next();
    }

    extname = path.extname(basename);
    cached = cache[basename];

    if (cached) {
      res.set(cached.headers);
      res.send(cached.body);
      return;
    }

    fs.readFile(path.join(dir, req.path), function(err, buf) {
      if (err) {
        if (err.errno && err.errno === 34) {
          res.statusCode = 404;
        }

        return next(err);
      }

      cached = cache[basename] = {
        headers: {
          'Content-Type': extname === '.ico' ? 'image/x-icon' : 'image/'+extname.split('.').pop(),
          'Content-Length': buf.length,
          'ETag': '"' + crypto.createHash('md5').update(buf).digest("hex") + '"',
          'Cache-Control': 'public, max-age=' + (maxAge / 1000)
        },
        body: buf
      };

      res.set(cached.headers);
      res.send(cached.body);
    });
  };
};
<commit_msg>more file formats supported in favicons-middleware.js<commit_after>var fs = require('fs');
var crypto = require('crypto');
var path = require('path');
var url = require('url');

module.exports = function favicons(dir, opts) {
  dir = dir || process.cwd() + '/public';
  opts = opts || {};

  var cache = Object.create(null);
  var maxAge = opts.maxAge || 86400000;
  var filenames = [
    'favicon.ico',
    'favicon.png',
    'apple-touch-icon.png',
    'apple-touch-icon-precomposed.png',
    'apple-touch-icon-57x57.png',
    'apple-touch-icon-57x57-precomposed.png',
    'apple-touch-icon-72x72.png',
    'apple-touch-icon-72x72-precomposed.png',
    'apple-touch-icon-76x76.png',
    'apple-touch-icon-76x76-precomposed.png',
    'apple-touch-icon-114x114.png',
    'apple-touch-icon-114x114-precomposed.png',
    'apple-touch-icon-120x120.png',
    'apple-touch-icon-120x120-precomposed.png',
    'apple-touch-icon-144x144.png',
    'apple-touch-icon-144x144-precomposed.png'
    'apple-touch-icon-152x152.png',
    'apple-touch-icon-152x152-precomposed.png'
    'apple-touch-icon-180x180.png',
    'apple-touch-icon-180x180-precomposed.png',
    'touch-icon-192x192.png'
  ];

  return function favicons(req, res, next) {
    var pathname = url.parse(req.url).pathname;
    var basename = path.basename(pathname);
    var index = filenames.indexOf(basename);
    var cached;
    var extname;

    if ( pathname.split('/').length > 2 ) {
      return next();
    }

    if ( index < 0 ) {
      return next();
    }

    extname = path.extname(basename);
    cached = cache[basename];

    if (cached) {
      res.set(cached.headers);
      res.send(cached.body);
      return;
    }

    fs.readFile(path.join(dir, req.path), function(err, buf) {
      if (err) {
        if (err.errno && err.errno === 34) {
          res.statusCode = 404;
        }

        return next(err);
      }

      cached = cache[basename] = {
        headers: {
          'Content-Type': extname === '.ico' ? 'image/x-icon' : 'image/'+extname.split('.').pop(),
          'Content-Length': buf.length,
          'ETag': '"' + crypto.createHash('md5').update(buf).digest("hex") + '"',
          'Cache-Control': 'public, max-age=' + (maxAge / 1000)
        },
        body: buf
      };

      res.set(cached.headers);
      res.send(cached.body);
    });
  };
};
<|endoftext|>


<commit_before>'use babel'

import path from 'path'

class GuruCommand {
  constructor (goconfigFunc, gogetFunc) {
    this.goconfig = goconfigFunc
    this.goget = gogetFunc
  }

  onCommandComplete (callback) {
    this.complete = callback
  }

  run (mode) {
    let config = this.goconfig()
    if (!config || !config.executor) {
      this.result = {
        success: false,
        result: null
      }
      return
    }

    this.mode = mode
    let args = this.computeArgs(mode)
    this.exec(args)
  }

  exec (args) {
    let config = this.goconfig()
    if (!config || !config.executor) {
      return
    }
    return config.executor.exec('guru', args).then((r) => {
      if (r.error) {
        atom.notifications.addError('Failed to execute guru', {
          detail: r.message + '\r\n' + r.stderr.trim(),
          dismissable: true
        })
        this.result = {
          success: false,
          result: r
        }

        return false
      }

      let message = r.stderr.trim() + '\r\n' + r.stdout.trim()
      if (r.exitcode !== 0 || r.stderr && r.stderr.trim() !== '') {
        atom.notifications.addWarning('Guru error', {
          detail: message.trim(),
          dismissable: true
        })

        this.result = {
          success: false,
          result: r
        }

        return false
      }
      this.result = {
        success: true,
        result: message.trim()
      }

      this.complete()
      return true
    })
  }

  computeArgs (mode) {
    let filePath = this.getPath()
    let pos = this.getPosition()
    let start = pos[0]
    let end = pos[1]
    let scope = ''

    if (atom.config.get('go-guru.guruComputeScope') === 'yes') {
      // retrieve the atom project root from the current file.
      let relPath = atom.project.relativizePath(filePath)
      if (relPath && relPath.length > 0) {
        // Make it relative to GOPATH because guru tool requires it.
        let goconfig = this.goconfig()
        if (goconfig && goconfig.locator) {
          let gopath = goconfig.locator.gopath()
          if (gopath) {
            scope = path.relative(gopath + '/src', relPath[0] + '/...')
          }
        }
      }
    }

    let userScope = atom.config.get('go-guru.guruUserScope')
    if (userScope) {
      scope += ', ' + userScope
    }

    console.log(scope)

    let args = ['-json', '-scope', scope, `${mode}`, `${filePath}:#${start},#${end}`]
    return args
  }

  getPath () {
    let editor = atom.workspace.getActiveTextEditor()
    if (editor) {
      return editor.getPath()
    }
    return undefined
  }

  getPosition () {
    let editor = atom.workspace.getActiveTextEditor()
    if (editor) {
      let cursor = editor.getLastCursor()
      let buffer = editor.getBuffer()

      if (cursor && buffer) {
        let wordPosition = cursor.getCurrentWordBufferRange()
        let start = buffer.characterIndexForPosition(wordPosition.start)
        let end = buffer.characterIndexForPosition(wordPosition.end)
        return [start, end]
      }
    }

    return undefined
  }
}

export {GuruCommand}
<commit_msg>wrong range passed to the go guru tool. This closes #6<commit_after>'use babel'

import path from 'path'

class GuruCommand {
  constructor (goconfigFunc, gogetFunc) {
    this.goconfig = goconfigFunc
    this.goget = gogetFunc
  }

  onCommandComplete (callback) {
    this.complete = callback
  }

  run (mode) {
    let config = this.goconfig()
    if (!config || !config.executor) {
      this.result = {
        success: false,
        result: null
      }
      return
    }

    this.mode = mode
    let args = this.computeArgs(mode)
    this.exec(args)
  }

  exec (args) {
    let config = this.goconfig()
    if (!config || !config.executor) {
      return
    }
    return config.executor.exec('guru', args).then((r) => {
      if (r.error) {
        atom.notifications.addError('Failed to execute guru', {
          detail: r.message + '\r\n' + r.stderr.trim(),
          dismissable: true
        })
        this.result = {
          success: false,
          result: r
        }

        return false
      }

      let message = r.stderr.trim() + '\r\n' + r.stdout.trim()
      if (r.exitcode !== 0 || r.stderr && r.stderr.trim() !== '') {
        atom.notifications.addWarning('Guru error', {
          detail: message.trim(),
          dismissable: true
        })

        this.result = {
          success: false,
          result: r
        }

        return false
      }
      this.result = {
        success: true,
        result: message.trim()
      }

      this.complete()
      return true
    })
  }

  computeArgs (mode) {
    let filePath = this.getPath()
    let pos = this.getPosition()
    let start = pos[0]
    let end = pos[1]-1
    let scope = ''

    if (atom.config.get('go-guru.guruComputeScope') === 'yes') {
      // retrieve the atom project root from the current file.
      let relPath = atom.project.relativizePath(filePath)
      if (relPath && relPath.length > 0) {
        // Make it relative to GOPATH because guru tool requires it.
        let goconfig = this.goconfig()
        if (goconfig && goconfig.locator) {
          let gopath = goconfig.locator.gopath()
          if (gopath) {
            scope = path.relative(gopath + '/src', relPath[0] + '/...')
          }
        }
      }
    }

    let userScope = atom.config.get('go-guru.guruUserScope')
    if (userScope) {
      scope += ', ' + userScope
    }

    console.log(scope)

    let args = ['-json', '-scope', scope, `${mode}`, `${filePath}:#${start},#${end}`]
    return args
  }

  getPath () {
    let editor = atom.workspace.getActiveTextEditor()
    if (editor) {
      return editor.getPath()
    }
    return undefined
  }

  getPosition () {
    let editor = atom.workspace.getActiveTextEditor()
    if (editor) {
      let cursor = editor.getLastCursor()
      let buffer = editor.getBuffer()

      if (cursor && buffer) {
        let wordPosition = cursor.getCurrentWordBufferRange()
        let start = buffer.characterIndexForPosition(wordPosition.start)
        let end = buffer.characterIndexForPosition(wordPosition.end)
        return [start, end]
      }
    }

    return undefined
  }
}

export {GuruCommand}
<|endoftext|>


<commit_before>/**
 *  lib.filters.base_assets(params, callback) -> Void
 *
 *  Middleware that populates `env.response.head.assets` with generic assets
 *  needed for the given method (based on locale, theme and namespace), such as:
 *  translations, views, etc.
 **/

"use strict";

/*global nodeca*/

// stdlib
var path = require('path');

// nodeca
var NLib = require('nlib');

////////////////////////////////////////////////////////////////////////////////

function append_assets(env, names) {
  _.each(names, function (pathname) {
    var link = env.helpers.asset_path(pathname);

    if ('#' !== link) {
      env.response.data.head.assets.push({
        type: path.extname(link).substring(1),
        link: link
      });
    }
  });
}

////////////////////////////////////////////////////////////////////////////////

nodeca.filters.before('', {weight: 50}, function base_assets(params, callback) {
  var ns = this.request.namespace;

  if (this.origin.http) {
    append_assets(this, ['lib.js', 'app.js']);

    if ('admin' !== ns) {
      // include main app.css only for non-admin namespace
      append_assets(this, ['app.css']);
    }
  }

  append_assets(this, [ns + '/app.css', ns + '/app.js']);
  callback();
});
<commit_msg>Add list of generic assets (commented)<commit_after>/**
 *  lib.filters.base_assets(params, callback) -> Void
 *
 *  Middleware that populates `env.response.head.assets` with generic assets
 *  needed for the given method (based on locale, theme and namespace), such as:
 *  translations, views, etc.
 **/

"use strict";

/*global nodeca*/

// stdlib
var path = require('path');

// nodeca
var NLib = require('nlib');

////////////////////////////////////////////////////////////////////////////////

function append_assets(env, names) {
  _.each(names, function (pathname) {
    var link = env.helpers.asset_path(pathname);

    if ('#' !== link) {
      env.response.data.head.assets.push({
        type: path.extname(link).substring(1),
        link: link
      });
    }
  });
}

////////////////////////////////////////////////////////////////////////////////

nodeca.filters.before('', {weight: 50}, function base_assets(params, callback) {
  var ns = this.request.namespace;

  if (this.origin.http) {
    append_assets(this, ['lib.js', 'app.js']);

    if ('admin' !== ns) {
      // include main app.css only for non-admin namespace
      append_assets(this, ['app.css']);
    }
  }

  //// common-wide
  //parts.push('views/' + locale + '/' + theme + '/layouts.js');
  //parts.push('views/' + locale + '/' + theme + '/common.js');
  //parts.push('common/i18n/' + locale + '.js');
  //parts.push('common/app.(?:js|css)');
  //parts.push('app.(?:js|css)');

  //// namespace-specific
  //parts.push('views/' + locale + '/' + theme + '/' + namespace + '.js');
  //parts.push(namespace + '/i18n/' + locale + '.js');
  //parts.push(namespace + 'app.(?:js|css)');

  append_assets(this, [ns + '/app.css', ns + '/app.js']);
  callback();
});
<|endoftext|>


<commit_before>var moment = require('moment');
var googleapis = require('googleapis');
var GoogleToken = require('gapitoken');
var OAuth2Client = googleapis.OAuth2Client;

var oauth2Client;

var curApp;

var numHangoutUrlsAvailable = 0;

// The rationale for this crazy situation is covered in DEVELOPMENT.md

exports.init = function(app) {
	curApp = app;

	// keep track of the total number of hangout urls we've farmed so far, so we
	// can put it in the UI.
	app.redis.llen('global:hangout_urls', function(err, len) {
		numHangoutUrlsAvailable = len;
	});

	// set up an HTTP endpoint that will put us in the endpoint redirect loop
	// people who load this url
	app.express.get('/hangout-farming', function(req, res){
		var url = req.protocol + "://" + app.options.HOST + ":" + app.options.PORT + "/hangout-callback";

		// initialize an oauth client request, using our google client id
		oauth2Client =
		new OAuth2Client(app.options.GOOGLE_CLIENT_ID, app.options.GOOGLE_CLIENT_SECRET, url);

		var url = oauth2Client.generateAuthUrl({
			access_type: 'offline',
			scope: 'https://www.googleapis.com/auth/calendar'
		});

		// redirect the request to the google calendar api
		res.redirect(url);
	});

	// users who complete the authentication request will get redirected back here
	// from google, after they authorize our app. The request they make back to
	// our server will have a token attached to it, that we will use to
	// place requests on behalf of this user.
	app.express.get('/hangout-callback', function(req, res) {
		// console.log(req.query["code"]);
		oauth2Client.getToken(req.query["code"], function(err, token) {
			if(err) {
				res.send(500, "Error getting token.");
				return;
			}

			oauth2Client.credentials = token;

			// okay, we've got a token now.	lets actually issue a request.
			// all we're doing here is creating a calendar event.
			googleapis.discover('calendar', 'v3').execute(function(err, client) {
				var now = moment().format();

				client.calendar
				.events
				.insert({
					calendarId: 'primary'}, {
						summary: 'hangout',
						description: 'hangout',
						anyoneCanAddSelf: true,
						visibility: "public",
						transparency: "transparent",
						reminders: {
							overrides: {
								method: 'popup',
								minutes: 0
							}
						},
						start: {
							dateTime: moment().add('days', 1).format()
						},
						end: {
							dateTime: moment().add('days', 1).add('hours', 1).format()
						},
						attendees: []
					})
					.withAuthClient(oauth2Client)
					.execute(function(err, event) {
						// this event fires when google tells us the calendar
						// event has been created. it includes the new calendar
						// event object.
						if(!err && "hangoutLink" in event) {
							// push it into redis for safekeeping.
							app.redis.lpush("global:hangout_urls", event.hangoutLink, function(err, num) {
								app.logger.info("logged new hangout url: " + event.hangoutLink + "; total: " + num);
								// purely for convenience of clicking to farm another url.
								res.send("urls available: " + num + "
CLICK ME");

								// update the tracking number.
								numHangoutUrlsAvailable = num;

								// TODO test whether it's okay to do this.
								// now delete the event so it doesn't clutter up the user's calendar.
								// as far as I can tell,
								// client.calendar.events.delete({
								// 	calendarId:'primary',
								// 	eventId:event.id
								// 	}).withAuthClient(oauth2Client)
								// 	.execute();
							});
						} else {
							if(err) {
								res.send("There was an error creating a new calendar event on your calendar!
" + err + "; " + err.message + "; " + JSON.stringify(err));
							} else {
								// we send this error if the calendar event created doesn't have a hangout url
								// included in the object. Give the user some rudimentary instructions about
								// how to fix this situation.
								res.send("your account doesn't seem to have the 'create video calls for events I create' option enabled. go to google calendar, settings (in the upper right hand corner) and enable that option. Then CLICK HERE!
" + JSON.stringify(event));
							}
						}
					});
				});

		});
	});

	app.logger.info("registered hangout-faming urls");
}

// get a hangout url from redis
exports.getNextHangoutUrl = function(callback) {

	// just hit redis directly here, with an rpop.
	curApp.redis.rpop("global:hangout_urls", function(err, url) {
		curApp.logger.debug("returning hangout url: " + url + " (err: " + err + ")");
		callback && callback(err, url);
	});
}

// put a hangout url back into redis that was unused
// (this situation occurs in some limited situations where people
//  join a new hangout in rapid succession)
exports.reuseUrl = function(url) {
	curApp.redis.rpush("global:hangout_urls", url, function(err) {
		curApp.logger.debug("re-added a url that was no longer needed: " + url);
	});
}

// used for UI purposes
exports.getNumHangoutsAvailable = function() {
	return numHangoutUrlsAvailable;
}<commit_msg>Fixed a protocol bug in hangout farming.<commit_after>var moment = require('moment');
var googleapis = require('googleapis');
var GoogleToken = require('gapitoken');
var OAuth2Client = googleapis.OAuth2Client;

var oauth2Client;

var curApp;

var numHangoutUrlsAvailable = 0;

// The rationale for this crazy situation is covered in DEVELOPMENT.md

exports.init = function(app) {
	curApp = app;

	// keep track of the total number of hangout urls we've farmed so far, so we
	// can put it in the UI.
	app.redis.llen('global:hangout_urls', function(err, len) {
		numHangoutUrlsAvailable = len;
	});

	// set up an HTTP endpoint that will put us in the endpoint redirect loop
	// people who load this url
	app.express.get('/hangout-farming', function(req, res){
		var url = req.protocol + "://" + app.options.HOST + ":" + app.options.PORT + "/hangout-callback";

		// initialize an oauth client request, using our google client id
		oauth2Client =
		new OAuth2Client(app.options.GOOGLE_CLIENT_ID, app.options.GOOGLE_CLIENT_SECRET, url);

		var url = oauth2Client.generateAuthUrl({
			access_type: 'offline',
			scope: 'https://www.googleapis.com/auth/calendar'
		});

		// redirect the request to the google calendar api
		res.redirect(url);
	});

	// users who complete the authentication request will get redirected back here
	// from google, after they authorize our app. The request they make back to
	// our server will have a token attached to it, that we will use to
	// place requests on behalf of this user.
	app.express.get('/hangout-callback', function(req, res) {
		// console.log(req.query["code"]);
		oauth2Client.getToken(req.query["code"], function(err, token) {
			if(err) {
				res.send(500, "Error getting token.");
				return;
			}

			oauth2Client.credentials = token;

			// okay, we've got a token now.	lets actually issue a request.
			// all we're doing here is creating a calendar event.
			googleapis.discover('calendar', 'v3').execute(function(err, client) {
				var now = moment().format();

				client.calendar
				.events
				.insert({
					calendarId: 'primary'}, {
						summary: 'hangout',
						description: 'hangout',
						anyoneCanAddSelf: true,
						visibility: "public",
						transparency: "transparent",
						reminders: {
							overrides: {
								method: 'popup',
								minutes: 0
							}
						},
						start: {
							dateTime: moment().add('days', 1).format()
						},
						end: {
							dateTime: moment().add('days', 1).add('hours', 1).format()
						},
						attendees: []
					})
					.withAuthClient(oauth2Client)
					.execute(function(err, event) {
						// this event fires when google tells us the calendar
						// event has been created. it includes the new calendar
						// event object.
						if(!err && "hangoutLink" in event) {
							// push it into redis for safekeeping.
							app.redis.lpush("global:hangout_urls", event.hangoutLink, function(err, num) {
								app.logger.info("logged new hangout url: " + event.hangoutLink + "; total: " + num);
								// purely for convenience of clicking to farm another url.
								res.send("urls available: " + num + "
CLICK ME");

								// update the tracking number.
								numHangoutUrlsAvailable = num;

								// TODO test whether it's okay to do this.
								// now delete the event so it doesn't clutter up the user's calendar.
								// as far as I can tell,
								// client.calendar.events.delete({
								// 	calendarId:'primary',
								// 	eventId:event.id
								// 	}).withAuthClient(oauth2Client)
								// 	.execute();
							});
						} else {
							if(err) {
								res.send("There was an error creating a new calendar event on your calendar!
" + err + "; " + err.message + "; " + JSON.stringify(err));
							} else {
								// we send this error if the calendar event created doesn't have a hangout url
								// included in the object. Give the user some rudimentary instructions about
								// how to fix this situation.
								res.send("your account doesn't seem to have the 'create video calls for events I create' option enabled. go to google calendar, settings (in the upper right hand corner) and enable that option. Then CLICK HERE!
" + JSON.stringify(event));
							}
						}
					});
				});

		});
	});

	app.logger.info("registered hangout-faming urls");
}

// get a hangout url from redis
exports.getNextHangoutUrl = function(callback) {

	// just hit redis directly here, with an rpop.
	curApp.redis.rpop("global:hangout_urls", function(err, url) {
		curApp.logger.debug("returning hangout url: " + url + " (err: " + err + ")");
		callback && callback(err, url);
	});
}

// put a hangout url back into redis that was unused
// (this situation occurs in some limited situations where people
//  join a new hangout in rapid succession)
exports.reuseUrl = function(url) {
	curApp.redis.rpush("global:hangout_urls", url, function(err) {
		curApp.logger.debug("re-added a url that was no longer needed: " + url);
	});
}

// used for UI purposes
exports.getNumHangoutsAvailable = function() {
	return numHangoutUrlsAvailable;
}<|endoftext|>


<commit_before>const Got = require('got');

const pkg = require('../../package.json');

const { deep: defaultsDeep } = require('./defaults');
const isAbsoluteUrl = require('./is_absolute_url');
const { HTTP_OPTIONS } = require('./consts');

let DEFAULT_HTTP_OPTIONS;
let got;

const setDefaults = (options) => {
  DEFAULT_HTTP_OPTIONS = defaultsDeep({}, options, DEFAULT_HTTP_OPTIONS);
  got = Got.extend(DEFAULT_HTTP_OPTIONS);
};

setDefaults({
  followRedirect: false,
  headers: { 'User-Agent': `${pkg.name}/${pkg.version} (${pkg.homepage})` },
  retry: 0,
  timeout: 2500,
  throwHttpErrors: false,
});

module.exports = function request(options, { mTLS = false } = {}) {
  const { url } = options;
  isAbsoluteUrl(url);
  const optsFn = this[HTTP_OPTIONS];
  let opts;
  if (optsFn) {
    opts = optsFn.call(this, defaultsDeep({}, options, DEFAULT_HTTP_OPTIONS));
  } else {
    opts = options;
  }

  if (mTLS && (!opts.key || !opts.cert)) {
    throw new TypeError('mutual-TLS certificate and key not set');
  }
  return got(opts);
};

module.exports.setDefaults = setDefaults;
<commit_msg>refactor: default http timeout increased to 3500ms<commit_after>const Got = require('got');

const pkg = require('../../package.json');

const { deep: defaultsDeep } = require('./defaults');
const isAbsoluteUrl = require('./is_absolute_url');
const { HTTP_OPTIONS } = require('./consts');

let DEFAULT_HTTP_OPTIONS;
let got;

const setDefaults = (options) => {
  DEFAULT_HTTP_OPTIONS = defaultsDeep({}, options, DEFAULT_HTTP_OPTIONS);
  got = Got.extend(DEFAULT_HTTP_OPTIONS);
};

setDefaults({
  followRedirect: false,
  headers: { 'User-Agent': `${pkg.name}/${pkg.version} (${pkg.homepage})` },
  retry: 0,
  timeout: 3500,
  throwHttpErrors: false,
});

module.exports = function request(options, { mTLS = false } = {}) {
  const { url } = options;
  isAbsoluteUrl(url);
  const optsFn = this[HTTP_OPTIONS];
  let opts;
  if (optsFn) {
    opts = optsFn.call(this, defaultsDeep({}, options, DEFAULT_HTTP_OPTIONS));
  } else {
    opts = options;
  }

  if (mTLS && (!opts.key || !opts.cert)) {
    throw new TypeError('mutual-TLS certificate and key not set');
  }
  return got(opts);
};

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


<commit_before>/*
 * This script represents an operator over Gearman protocol.
 * {@see http://gearman.org/protocol}
 *
 * (C) 2013 Vaclav Sykora
 * Apache License, Version 2.0, http://www.apache.org/licenses/
 *
 */

var winston = require('winston');

exports.PACKET_TYPES = {
    CAN_DO: 1,              // W->J: FUNC
    PRE_SLEEP: 4,           // W->J: --
    NOOP: 6,                // J->W: --
    SUBMIT_JOB: 7,          // C->J: FUNC[0]UNIQ[0]ARGS
    JOB_CREATED: 8,         // J->C: HANDLE
    GRAB_JOB: 9,            // W->J: --
    WORK_STATUS: 12,        // W->J/C: HANDLE[0]NUMERATOR[0]DENOMINATOR
    WORK_COMPLETE: 13,      // W->J/C: HANDLE[0]RES
    GET_STATUS: 15,         // C->J: HANDLE
    SUBMIT_JOB_BG: 18,      // C->J: FUNC[0]UNIQ[0]ARGS
    ERROR: 19,              // J->C: ERRCODE[0]ERR_TEXT
    STATUS_RES: 20,         // C->J: HANDLE[0]KNOWN[0]RUNNING[0]NUM[0]DENOM
    SUBMIT_JOB_HIGH: 21,    // C->J: FUNC[0]UNIQ[0]ARGS
    SUBMIT_JOB_HIGH_BG: 32, // C->J: FUNC[0]UNIQ[0]ARGS
    SUBMIT_JOB_LOW: 33,     // C->J: FUNC[0]UNIQ[0]ARGS
    SUBMIT_JOB_LOW_BG: 34,  // C->J: FUNC[0]UNIQ[0]ARGS
    // --
    WORK_FAIL: 14,
    ECHO_REQ: 16,
    WORK_EXCEPTION: 25,
    WORK_DATA: 28,
    WORK_WARNING: 29
};

exports.PACKET_CODES = {};
for (var i in exports.PACKET_TYPES) {
    exports.PACKET_CODES[exports.PACKET_TYPES[i]] = i;
}

var logger = winston.loggers.get('protocol');

/**
 * Parses given buffer according to defined format.
 *
 * *format*
 *   *N* NULL byte terminated string (encoding according to job's encoding)
 *   *n* NULL byte terminated string (ASCII encoding)
 *   *L* last segment of buffer (encoding according to job's encoding)
 *
 * return array
 *   *rslt[0]* number of processed bytes
 *   *rslt[1..]* chunks with order defined by format
 */
exports.parsePacket = function (buff, format) {
    var i, j, key;
    var rslt = [];
    var offset = 12; // packet header len
    var packetType = buff.readUInt32BE(4);
    var packetLength = offset + buff.readUInt32BE(8);

    format = format || '';

    for (i = 0; i < format.length; i ++) {
        key = format.charAt(i);

        if ('N' == key || 'n' == key) {
            // find next NULL
            for (j = offset; j < buff.length; j ++) {
                if (buff.readUInt8(j) == 0) {
                    break;
                }
            }
            rslt[i + 1] = buff.toString('n' == key ? 'ascii' : this.encoding, offset, j);
            offset = j + 1; // +1 == skip NULL
        } else if ('L' == key) { // LAST segment up to packetLength
            rslt[i + 1] = buff.toString(this.encoding, offset, packetLength);
            offset = packetLength;
        } else {
            return new Error('unknow format: ' + format);
        }
    }

    rslt[0] = offset;
    logger.log('debug', 'packet parsed, bytes=%d, type=%s', offset, exports.PACKET_CODES[packetType]);
    return rslt;
}

exports.encodePacket = function (packetType, encoding, args) {
    var i, buff;
    var packetLength = 0;
    var offset = 12;  // 12 byte header

    // default values
    args = args || [];
    encoding = encoding || 'ascii';

    // compute packet length
    for (i = 0; i < args.length; i ++) {
        if (args[i].constructor.name === 'String') {
            packetLength += Buffer.byteLength(args[i], encoding);
        } else if (args[i].constructor.name === 'Buffer') {
            packetLength += args[i].length;
        } else {
            logger.log('warn', 'unrecognized argument to encode, class=%s', args[i].constructor.name);
            packetLength += Buffer.byteLength(args[i].toString(), encoding);
        }
    }
    if (args.length > 0) {
        packetLength += args.length - 1; // NULL byte terminations
    }

    buff = new Buffer(12 + packetLength);

    buff.writeUInt32BE(0x00524551, 0); // \0REQ
    buff.writeUInt32BE(packetType, 4);
    buff.writeUInt32BE(packetLength, 8);

    // construct packet
    for (i = 0; i < args.length; i ++) {
        if (args[i].constructor.name === 'String') {
            buff.write(args[i], offset, encoding);
            offset += Buffer.byteLength(args[i], encoding);
        } else if (args[i].constructor.name === 'Buffer') {
            args[i].copy(buff, offset);
            offset += args[i].length;
        } else {
            buff.write(args[i].toString(), offset, encoding);
            offset += Buffer.byteLength(args[i].toString(), encoding);
        }

        if (i < (args.length - 1)) {
            buff.writeUInt8(0, offset); // NULL byte terminated chunk
            offset ++;
        }
    }

    logger.log('debug', 'packet encoded, type=%s, buffer.size=%d',
        exports.PACKET_CODES[packetType], packetLength + 12);
    return buff;
}
<commit_msg>new definition of protocol<commit_after>/*
 * This script represents an operator over Gearman protocol.
 * {@see http://gearman.org/protocol}
 *
 * (C) 2013 Vaclav Sykora
 * Apache License, Version 2.0, http://www.apache.org/licenses/
 *
 */

var winston = require('winston'),
    util    = require('util');

// various constants used in protocol
var constants = exports.CONSTANTS = {
    TYPE_REQ: 1,
    TYPE_RESP: 2
};
var logger = winston.loggers.get('protocol');

exports.DEFINITION = {
    CAN_DO: [1, constants.TYPE_REQ],                // W->J: FUNC
    PRE_SLEEP: [4, constants.TYPE_REQ],             // W->J: --
    NOOP: [6, constants.TYPE_RESP, ''],             // J->W: --
    SUBMIT_JOB: [7, constants.TYPE_REQ],            // C->J: FUNC[0]UNIQ[0]ARGS
    JOB_CREATED: [8, constants.TYPE_RESP, 'L'],     // J->C: HANDLE
    GRAB_JOB: [9, constants.TYPE_REQ],              // W->J: --
    WORK_STATUS: [12, constants.TYPE_REQ],          // W->J/C: HANDLE[0]NUMERATOR[0]DENOMINATOR
    WORK_COMPLETE: [13, constants.TYPE_REQ],        // W->J/C: HANDLE[0]RES
    GET_STATUS: [15, constants.TYPE_REQ],           // C->J: HANDLE
    SUBMIT_JOB_BG: [18, constants.TYPE_REQ],        // C->J: FUNC[0]UNIQ[0]ARGS
    ERROR: [19, constants.TYPE_RESP, 'nL'],         // J->C: ERRCODE[0]ERR_TEXT
    STATUS_RES: [20, constants.TYPE_RESP, 'nnnnL'], // C->J: HANDLE[0]KNOWN[0]RUNNING[0]NUM[0]DENOM
    SUBMIT_JOB_HIGH: [21, constants.TYPE_REQ],      // C->J: FUNC[0]UNIQ[0]ARGS
    SUBMIT_JOB_HIGH_BG: [32, constants.TYPE_REQ],   // C->J: FUNC[0]UNIQ[0]ARGS
    SUBMIT_JOB_LOW: [33, constants.TYPE_REQ],       // C->J: FUNC[0]UNIQ[0]ARGS
    SUBMIT_JOB_LOW_BG: [34, constants.TYPE_REQ],    // C->J: FUNC[0]UNIQ[0]ARGS
    // --
    WORK_FAIL: [14, constants.TYPE_REQ],
    ECHO_REQ: [16, constants.TYPE_RESP, ''],
    WORK_EXCEPTION: [25, constants.TYPE_REQ],
    WORK_DATA: [28, constants.TYPE_REQ],
    WORK_WARNING: [29, constants.TYPE_REQ]
};

// desc=>code - {CAN_DO: 1}
exports.PACKET_TYPES = {}
// code=>desc - {1: CAN_DO}
exports.PACKET_CODES = {};
// code=>format for RESP - {19: 'nL'}
exports.PACKET_RESP_FORMAT = {};

var def;
for (var i in exports.DEFINITION) {
    def = exports.DEFINITION[i];

    exports.PACKET_TYPES[i] = def[0];
    exports.PACKET_CODES[def[0]] = i;

    if (constants.TYPE_RESP === def[1]) {
        exports.PACKET_RESP_FORMAT[def[0]] = def[2];
    }
}

/**
 * Parses given buffer according to defined format.
 *
 * *format*
 *   *N* NULL byte terminated string (encoding according to job's encoding)
 *   *n* NULL byte terminated string (ASCII encoding)
 *   *L* last segment of buffer (encoding according to job's encoding)
 *
 * return array
 *   *rslt[0]* number of processed bytes
 *   *rslt[1..]* chunks with order defined by format
 */
exports.parsePacket = function (buff, format) {
    var i, j, key;
    var rslt = [];
    var offset = 12; // packet header len
    var packetType = buff.readUInt32BE(4);
    var packetLength = offset + buff.readUInt32BE(8);

    format = format || '';

    for (i = 0; i < format.length; i ++) {
        key = format.charAt(i);

        if ('N' == key || 'n' == key) {
            // find next NULL
            for (j = offset; j < buff.length; j ++) {
                if (buff.readUInt8(j) == 0) {
                    break;
                }
            }
            rslt[i + 1] = buff.toString('n' == key ? 'ascii' : this.encoding, offset, j);
            offset = j + 1; // +1 == skip NULL
        } else if ('L' == key) { // LAST segment up to packetLength
            rslt[i + 1] = buff.toString(this.encoding, offset, packetLength);
            offset = packetLength;
        } else {
            return new Error('unknow format: ' + format);
        }
    }

    rslt[0] = offset;
    logger.log('debug', 'packet parsed, bytes=%d, type=%s', offset, exports.PACKET_CODES[packetType]);
    return rslt;
}

exports.encodePacket = function (packetType, encoding, args) {
    var i, buff;
    var packetLength = 0;
    var offset = 12;  // 12 byte header

    // default values
    args = args || [];
    encoding = encoding || 'ascii';

    // compute packet length
    for (i = 0; i < args.length; i ++) {
        if (args[i].constructor.name === 'String') {
            packetLength += Buffer.byteLength(args[i], encoding);
        } else if (args[i].constructor.name === 'Buffer') {
            packetLength += args[i].length;
        } else {
            logger.log('warn', 'unrecognized argument to encode, class=%s', args[i].constructor.name);
            packetLength += Buffer.byteLength(args[i].toString(), encoding);
        }
    }
    if (args.length > 0) {
        packetLength += args.length - 1; // NULL byte terminations
    }

    buff = new Buffer(12 + packetLength);

    buff.writeUInt32BE(0x00524551, 0); // \0REQ
    buff.writeUInt32BE(packetType, 4);
    buff.writeUInt32BE(packetLength, 8);

    // construct packet
    for (i = 0; i < args.length; i ++) {
        if (args[i].constructor.name === 'String') {
            buff.write(args[i], offset, encoding);
            offset += Buffer.byteLength(args[i], encoding);
        } else if (args[i].constructor.name === 'Buffer') {
            args[i].copy(buff, offset);
            offset += args[i].length;
        } else {
            buff.write(args[i].toString(), offset, encoding);
            offset += Buffer.byteLength(args[i].toString(), encoding);
        }

        if (i < (args.length - 1)) {
            buff.writeUInt8(0, offset); // NULL byte terminated chunk
            offset ++;
        }
    }

    logger.log('debug', 'packet encoded, type=%s, buffer.size=%d',
        exports.PACKET_CODES[packetType], packetLength + 12);
    return buff;
}
<|endoftext|>


<commit_before>var _ = require("lodash");
var util = require("util");
var path = require("path");
var Q = require("q");
var swig = require('swig');
var hljs = require('highlight.js');

var fs = require("../fs");
var parse = require("../../parse");
var BaseGenerator = require("../site");

// Swig filter: highlight coloration
swig.setFilter('code', function(code, lang) {
    try {
        return hljs.highlight(lang, code).value;
    } catch(e) {
        return hljs.highlightAuto(code).value;
    }
});

/*
 *  This generator will generate a simple index.html which can be converted as a PDF
 */
var Generator = function() {
    BaseGenerator.apply(this, arguments);

    // Load base template
    this.template = swig.compileFile(path.resolve(this.options.theme, 'templates/page.html'));

    // List of pages content
    this.pages = {};
};
util.inherits(Generator, BaseGenerator);

Generator.prototype.transferFile = function(input) {
    // ignore
};

Generator.prototype.transferFolder = function(input) {
    // ignore
};

Generator.prototype.convertFile = function(content, input) {
    var that = this;
    var json = {
        path: input,
        progress: parse.progress(this.options.navigation, input)
    };

    return Q()
    .then(function() {
        return parse.page(content, {
            repo: that.options.githubId,
            dir: path.dirname(input) || '/'
        });
    })
    .then(function(sections) {
        json.content = sections;
    })
    .then(function() {
        that.pages[input] = json;
    });
};

Generator.prototype.finish = function() {
    var that = this;
    var basePath = ".";
    var output = path.join(this.options.output, "index.html");

    return Q()
    // Generate html
    .then(function(pages) {
        return that._writeTemplate(that.template, {
            pages: that.pages,

            basePath: basePath,
            staticBase: path.join(basePath, "gitbook"),
        }, output);
    })

    // Copy assets
    .then(function() {
        return fs.copy(
            path.join(that.options.theme, "assets"),
            path.join(that.options.output, "gitbook")
        );
    });
};

module.exports = Generator;<commit_msg>Fix #33: copy files when generating pdf or single page<commit_after>var _ = require("lodash");
var util = require("util");
var path = require("path");
var Q = require("q");
var swig = require('swig');
var hljs = require('highlight.js');

var fs = require("../fs");
var parse = require("../../parse");
var BaseGenerator = require("../site");

// Swig filter: highlight coloration
swig.setFilter('code', function(code, lang) {
    try {
        return hljs.highlight(lang, code).value;
    } catch(e) {
        return hljs.highlightAuto(code).value;
    }
});

/*
 *  This generator will generate a simple index.html which can be converted as a PDF
 */
var Generator = function() {
    BaseGenerator.apply(this, arguments);

    // Load base template
    this.template = swig.compileFile(path.resolve(this.options.theme, 'templates/page.html'));

    // List of pages content
    this.pages = {};
};
util.inherits(Generator, BaseGenerator);

Generator.prototype.convertFile = function(content, input) {
    var that = this;
    var json = {
        path: input,
        progress: parse.progress(this.options.navigation, input)
    };

    return Q()
    .then(function() {
        return parse.page(content, {
            repo: that.options.githubId,
            dir: path.dirname(input) || '/'
        });
    })
    .then(function(sections) {
        json.content = sections;
    })
    .then(function() {
        that.pages[input] = json;
    });
};

Generator.prototype.finish = function() {
    var that = this;
    var basePath = ".";
    var output = path.join(this.options.output, "index.html");

    return Q()
    // Generate html
    .then(function(pages) {
        return that._writeTemplate(that.template, {
            pages: that.pages,

            basePath: basePath,
            staticBase: path.join(basePath, "gitbook"),
        }, output);
    })

    // Copy assets
    .then(function() {
        return fs.copy(
            path.join(that.options.theme, "assets"),
            path.join(that.options.output, "gitbook")
        );
    });
};

module.exports = Generator;<|endoftext|>


<commit_before>var _ = require('underscore');
var fs = require('fs');
var path = require('path');

exports.docsFilename = function (name) {
	return name.replace(/ /g, "_")
		.replace(/./g, ".")
		.replace(/>/g, "_gt_")
		.replace(/\*/g, "_star_")
		.replace(/\//g, "|") + '.html';
}
exports.name = function (file) {
	return file.substring(0, file.lastIndexOf('.'));
}

exports.handlebarsHelpers = function (helpers, Handlebars) {
	if (helpers && Handlebars) {
		_.each(helpers, function (helper, name) {
			if (!Handlebars.helpers[name]) {
				Handlebars.registerHelper(name, helper);
			}
		});
	}
	return Handlebars;
}

exports.handlebarsPartials = function (folder, Handlebars) {
	var files = fs.readdirSync(folder);
	files.forEach(function (filename) {
		var template = fs.readFileSync(path.join(folder, filename));
		Handlebars.registerPartial(filename, template.toString());
	});
	return Handlebars;
}

exports.activateItems = function (root, name) {
	var traverse = function (children) {
		var anyActive = false;
		_.each(children, function (child) {
			var active = false;
			if (child.children) {
				active = traverse(child.children);
			}
			child.active = active || child.name == name;
			if (child.active) {
				anyActive = true;
			}
		});

		return anyActive;
	}

	traverse(root.children);

	return root;
}

exports.menuTree = function (data, root) {
	var copies = _.map(data, function (value) {
		return _.extend({
			active: false
		}, value);
	});

	_.each(copies, function (current, index, arr) {
		var parent = _.find(arr, function (value) {
			return value.name === current.parent;
		});

		if (parent) {
			parent.children = parent.children || [];
			parent.children.push(current);
			parent.children = _.sortBy(parent.children, function (child) {
				return child.order || child.name;
			});
		}
	});

	if (root) {
		return _.find(copies, function (current) {
			return current.name == root;
		});
	}

	return copies;
}

exports.replaceLinks = function (text, data) {
	var replacer = function (match, content) {
		var parts = content.match(/^(\S+)\s(.*)/);
		var link = parts ? parts[1].replace('::', '.prototype.') : content;
		var description = parts && parts[2] ? parts[2] : link;

		if (data[link]) {
			return '' + description + '';
		}

		return match;
	};

	return text.replace(/[\[](.*?)\]/g, replacer);
}

exports.helpers = {
	activePage: function(current, expected) {
		return current == this.page ? 'active' : '';
	},

	url: function(url) {
		return path.join(this.root, url);
	},

	makeHref: function (name) {
		return exports.docsFilename(name);
	}
};
<commit_msg>Always overwrite handlebars helpers<commit_after>var _ = require('underscore');
var fs = require('fs');
var path = require('path');

exports.docsFilename = function (name) {
	return name.replace(/ /g, "_")
		.replace(/./g, ".")
		.replace(/>/g, "_gt_")
		.replace(/\*/g, "_star_")
		.replace(/\//g, "|") + '.html';
}
exports.name = function (file) {
	return file.substring(0, file.lastIndexOf('.'));
}

exports.handlebarsHelpers = function (helpers, Handlebars) {
	if (helpers && Handlebars) {
		_.each(helpers, function (helper, name) {
			Handlebars.registerHelper(name, helper);
		});
	}
	return Handlebars;
}

exports.handlebarsPartials = function (folder, Handlebars) {
	var files = fs.readdirSync(folder);
	files.forEach(function (filename) {
		var template = fs.readFileSync(path.join(folder, filename));
		Handlebars.registerPartial(filename, template.toString());
	});
	return Handlebars;
}

exports.activateItems = function (root, name) {
	var traverse = function (children) {
		var anyActive = false;
		_.each(children, function (child) {
			var active = false;
			if (child.children) {
				active = traverse(child.children);
			}
			child.active = active || child.name == name;
			if (child.active) {
				anyActive = true;
			}
		});

		return anyActive;
	}

	traverse(root.children);

	return root;
}

exports.menuTree = function (data, root) {
	var copies = _.map(data, function (value) {
		return _.extend({
			active: false
		}, value);
	});

	_.each(copies, function (current, index, arr) {
		var parent = _.find(arr, function (value) {
			return value.name === current.parent;
		});

		if (parent) {
			parent.children = parent.children || [];
			parent.children.push(current);
			parent.children = _.sortBy(parent.children, function (child) {
				return child.order || child.name;
			});
		}
	});

	if (root) {
		return _.find(copies, function (current) {
			return current.name == root;
		});
	}

	return copies;
}

exports.replaceLinks = function (text, data) {
	var replacer = function (match, content) {
		var parts = content.match(/^(\S+)\s(.*)/);
		var link = parts ? parts[1].replace('::', '.prototype.') : content;
		var description = parts && parts[2] ? parts[2] : link;

		if (data[link]) {
			return '' + description + '';
		}

		return match;
	};

	return text.replace(/[\[](.*?)\]/g, replacer);
}

exports.helpers = {
	activePage: function(current, expected) {
		return current == this.page ? 'active' : '';
	},

	url: function(url) {
		return path.join(this.root, url);
	},

	makeHref: function (name) {
		return exports.docsFilename(name);
	}
};
<|endoftext|>


<commit_before>var Promise = require('es6-promise').Promise;
var either  = require('./tools').either;

module.exports = function genericPromiseChain(methods, myPrototype) {

  function GenericPromiseChain (operand) {
    "use strict";

    var self = this;

    this._operand = operand;
    this._promise = typeof operand === 'function' ? operand() : operand;
  }

  GenericPromiseChain.prototype = Object.create(myPrototype);

  [ 'then', 'catch' ].forEach(function (name) {

    GenericPromiseChain.prototype[name] = function () {
      "use strict";
      this._promise = this._promise[name].apply(this._promise, arguments);
      return this;
    };

  });

  GenericPromiseChain.prototype.always = function (callback) {
    "use strict";

    return this.then(function (result) { callback(null, result) }, callback);
  };

  GenericPromiseChain.prototype.sleep = function (timeout) {
    "use strict";

    var self = this;
    return self.then(function () {
      return new Promise(function (resolve) {
        setTimeout(resolve, timeout);
      });
    });
  };

  GenericPromiseChain.prototype.expectError = function (callback) {
    "use strict";

    var self = this;
    return self.then(function () {
      throw new Error('exception was not thrown');
    }, callback);
  };

  GenericPromiseChain.prototype.noWait = function () {
    "use strict";

    return new GenericPromiseChain(this._operand);
  };

  GenericPromiseChain.prototype.yet = function (code, args) {
    "use strict";

    var args = Array.prototype.slice.call(arguments, 0);
    var self = this;
    //--------------------------------
    return self.catch(function (err) {
      return self.noWait().execute(code, args).then(function (errMessage) {
        throw new Error(err.message + ' ' + errMessage);
      });
    });
  };

  GenericPromiseChain.prototype.methods = methods.concat([
    '__custom__',
    'catch',
    'then',
    'always',
    'sleep',
    'expectError',
    'noWait',
    'yet',
  ]);

  GenericPromiseChain.prototype.__custom__ = function (action) {
    var self = this;
    self._promise = Promise.all([
      typeof self._operand === 'function' ? self._operand() : self._operand, self._promise
    ]).then(function (all) {
      return new Promise(function (resolve, reject) {
        var operand = all[0];
        if (!operand || typeof operand !== 'object') {
          reject(new Error('GenericPromiseChain: invalid operand'));
        }
        action(operand, either(cleanError(reject)).or(resolve));
      });
    });
    return self;
  };

  methods.forEach(function (name) {
    "use strict";

    /**
     * Update the current promise and return this to allow chaining.
     */
    GenericPromiseChain.prototype[name] = function () {
      var args = Array.prototype.slice.call(arguments, 0);
      var self = this;
      self._promise = Promise.all([
        typeof self._operand === 'function' ? self._operand() : self._operand, self._promise
      ]).then(function (all) {
        return new Promise(function (resolve, reject) {
          // TODO: think how we could use value returned by self._promise
          var operand = all[0];
          if (!operand || typeof operand !== 'object') {
            reject(new Error('GenericPromiseChain: invalid operand'));
          } else if (!operand[name]) {
            reject(new Error('GenericPromiseChain: operand does not implement method: ' + name));
          } else {
            args.push(either(cleanError(reject)).or(resolve));
            operand[name].apply(operand, args);
          }
        });
      });
      return self;
    };

  });

  return GenericPromiseChain;

}

function cleanError(reject) {
  return function (err) {
    if (err && !(err instanceof Error)) {
      err = new Error(err.message || err.toString());
    }
    reject(err);
  }
}
<commit_msg>Reuse the __custom__ method implementation<commit_after>var Promise = require('es6-promise').Promise;
var either  = require('./tools').either;

module.exports = function genericPromiseChain(methods, myPrototype) {

  function GenericPromiseChain (operand) {
    "use strict";

    var self = this;

    this._operand = operand;
    this._promise = typeof operand === 'function' ? operand() : operand;
  }

  GenericPromiseChain.prototype = Object.create(myPrototype);

  [ 'then', 'catch' ].forEach(function (name) {

    GenericPromiseChain.prototype[name] = function () {
      "use strict";
      this._promise = this._promise[name].apply(this._promise, arguments);
      return this;
    };

  });

  GenericPromiseChain.prototype.always = function (callback) {
    "use strict";

    return this.then(function (result) { callback(null, result) }, callback);
  };

  GenericPromiseChain.prototype.sleep = function (timeout) {
    "use strict";

    var self = this;
    return self.then(function () {
      return new Promise(function (resolve) {
        setTimeout(resolve, timeout);
      });
    });
  };

  GenericPromiseChain.prototype.expectError = function (callback) {
    "use strict";

    var self = this;
    return self.then(function () {
      throw new Error('exception was not thrown');
    }, callback);
  };

  GenericPromiseChain.prototype.noWait = function () {
    "use strict";

    return new GenericPromiseChain(this._operand);
  };

  GenericPromiseChain.prototype.yet = function (code, args) {
    "use strict";

    var args = Array.prototype.slice.call(arguments, 0);
    var self = this;
    //--------------------------------
    return self.catch(function (err) {
      return self.noWait().execute(code, args).then(function (errMessage) {
        throw new Error(err.message + ' ' + errMessage);
      });
    });
  };

  GenericPromiseChain.prototype.methods = methods.concat([
    '__custom__',
    'catch',
    'then',
    'always',
    'sleep',
    'expectError',
    'noWait',
    'yet',
  ]);

  GenericPromiseChain.prototype.__custom__ = function (action) {
    var self = this;
    self._promise = Promise.all([
      typeof self._operand === 'function' ? self._operand() : self._operand, self._promise
    ]).then(function (all) {
      return new Promise(function (resolve, reject) {
        var operand = all[0];
        if (!operand || typeof operand !== 'object') {
          reject(new Error('GenericPromiseChain: invalid operand'));
        }
        action(operand, either(cleanError(reject)).or(resolve));
      });
    });
    return self;
  };

  methods.forEach(function (name) {
    "use strict";

    /**
     * Update the current promise and return this to allow chaining.
     */
    GenericPromiseChain.prototype[name] = function () {
      var args = Array.prototype.slice.call(arguments, 0);
      return this.__custom__(function (operand) {
        if (!operand[name]) {
          reject(new Error('GenericPromiseChain: operand does not implement method: ' + name));
        } else {
          args.push(either(cleanError(reject)).or(resolve));
          operand[name].apply(operand, args);
        }
      });
    };

  });

  return GenericPromiseChain;

}

function cleanError(reject) {
  return function (err) {
    if (err && !(err instanceof Error)) {
      err = new Error(err.message || err.toString());
    }
    reject(err);
  }
}
<|endoftext|>