<commit_before>'use strict';

// Node.js
const childProcess = require('child_process');

// NPM
const flow = require('flow-bin');

// Flow linting methods
const methodCheckContents = require('./src/methods/check-contents.js');
const methodStatus        = require('./src/methods/status.js');

/**
 * Get the specified Flow linting method.
 *
 * @param  {string} methodName
 * @return {Function}
 */
function getLintingMethod(methodName) {

    switch (methodName) {
        case 'check-contents':
            return methodCheckContents;
        case 'status':
            return methodStatus;
        default:
            throw new Error('Invalid Flow linting method: ' + methodName);
    }

}

/**
 * @see brunch.io/docs/plugins#boilerplate-plugin
 * @see github.com/flowtype/flow-bin#api
 */
class FlowLinter {

    constructor(brunchConfig) {

        const cfg = (brunchConfig && brunchConfig.plugins && brunchConfig.plugins.flowtype) || {};

        this.lintingMethod  = (typeof cfg.method   === 'string' ) ? getLintingMethod(cfg.method) : methodStatus;
        this.warnOnly       = (typeof cfg.warnOnly === 'boolean') ? cfg.warnOnly : false;
        this.lintingOptions = {
            statusDelay: (typeof cfg.statusDelay === 'number') ? cfg.statusDelay : 250
        };

        try {
            // Start Flow server (if not already started).
            childProcess.execFileSync(flow, ['status'], { stdio: [
                'ignore',  // stdin  -- Attach to /dev/null
                'ignore',  // stdout -- Attach to /dev/null
                'inherit'  // stderr -- Attach to process.stderr so Flow server startup messages are displayed to user
            ]});
        } catch (e) {
            // Probably a linting error, just ignore it for now.
            // @todo Handle this error properly.
        }

    }

    lint(data, path) {

        const flowlinter = this;

        return new Promise(function (resolve, reject) {
            flowlinter.lintingMethod(data, path, flowlinter.lintingOptions, function (formattedErrors) {
                if (formattedErrors.length === 0) {
                    resolve();
                } else {
                    const errorSeparator = '\n\n' + ' '.repeat(4) + '-'.repeat(20) + '\n\n';
                    let output = 'Flow reported:\n\n' + formattedErrors.join(errorSeparator) + '\n';
                    if (flowlinter.warnOnly) {
                        output = 'warn: ' + output;  // github.com/brunch/brunch/blob/2.9.1/lib/fs_utils/pipeline.js#L21
                    }
                    reject(output);
                }
            });
        });

    }

}

FlowLinter.prototype.brunchPlugin = true;
FlowLinter.prototype.type         = 'javascript';
FlowLinter.prototype.pattern      = /\.jsx?$/;

module.exports = FlowLinter;
<commit_msg>index.js: only the Brunch master process needs to start Flow<commit_after>'use strict';

// Node.js
const childProcess = require('child_process');

// NPM
const flow = require('flow-bin');

// Flow linting methods
const methodCheckContents = require('./src/methods/check-contents.js');
const methodStatus        = require('./src/methods/status.js');

// Utilities
const utils = require('./src/utils.js');

/**
 * Get the specified Flow linting method.
 *
 * @param  {string} methodName
 * @return {Function}
 */
function getLintingMethod(methodName) {

    switch (methodName) {
        case 'check-contents':
            return methodCheckContents;
        case 'status':
            return methodStatus;
        default:
            throw new Error('Invalid Flow linting method: ' + methodName);
    }

}

/**
 * @see brunch.io/docs/plugins#boilerplate-plugin
 * @see github.com/flowtype/flow-bin#api
 */
class FlowLinter {

    constructor(brunchConfig) {

        const cfg = (brunchConfig && brunchConfig.plugins && brunchConfig.plugins.flowtype) || {};

        this.lintingMethod  = (typeof cfg.method   === 'string' ) ? getLintingMethod(cfg.method) : methodStatus;
        this.warnOnly       = (typeof cfg.warnOnly === 'boolean') ? cfg.warnOnly : false;
        this.lintingOptions = {
            statusDelay: (typeof cfg.statusDelay === 'number') ? cfg.statusDelay : 250
        };

        if (utils.isProcessBrunchMaster()) {
            // Only the Brunch master process needs to start the Flow server.
            try {
                // Start Flow server (if not already started).
                childProcess.execFileSync(flow, ['status'], { stdio: [
                    'ignore',  // stdin  -- Attach to /dev/null
                    'ignore',  // stdout -- Attach to /dev/null
                    'inherit'  // stderr -- Attach to process.stderr so Flow server startup messages are displayed to user
                ]});
            } catch (e) {
                // Probably a linting error, just ignore it for now.
                // @todo Handle this error properly.
            }
        }

    }

    lint(data, path) {

        const flowlinter = this;

        return new Promise(function (resolve, reject) {
            flowlinter.lintingMethod(data, path, flowlinter.lintingOptions, function (formattedErrors) {
                if (formattedErrors.length === 0) {
                    resolve();
                } else {
                    const errorSeparator = '\n\n' + ' '.repeat(4) + '-'.repeat(20) + '\n\n';
                    let output = 'Flow reported:\n\n' + formattedErrors.join(errorSeparator) + '\n';
                    if (flowlinter.warnOnly) {
                        output = 'warn: ' + output;  // github.com/brunch/brunch/blob/2.9.1/lib/fs_utils/pipeline.js#L21
                    }
                    reject(output);
                }
            });
        });

    }

}

FlowLinter.prototype.brunchPlugin = true;
FlowLinter.prototype.type         = 'javascript';
FlowLinter.prototype.pattern      = /\.jsx?$/;

module.exports = FlowLinter;
<|endoftext|>


<commit_before>'use strict';

var postcss = require('postcss');

var variablesPattern      = /\$\S+/g;
var parametersPattern     = variablesPattern;
var customPropertyPattern = /^[^${}: ]+ *: /;
var propertyKeyDelimiter  = ':';

// Adds a property definition to properties
var define = function (properties, rule) {
  var name = rule.selector.match(customPropertyPattern).shift().replace(':', '').trim();
  var parameters = rule.selector.match(parametersPattern);

  var property = {
    name: name,
    parameters: parameters,
    declarations: rule.nodes.map(function (node) {
      return {
        property: node.prop,
        value: node.value,
        // Parses variables that are also parameters. Ignores other variables for compatability with Sass variables.
        // We only need the index of each parameter
        variables: node.value.match(variablesPattern).filter(function (variable) {
          return node.value.includes(variable);
        }).map(function (variable) {
          return parameters.indexOf(variable);
        })
      };
    })
  };

  properties[property.name + propertyKeyDelimiter + parameters.length] = property;
  rule.removeSelf();
};

// Applies the custom property to the given declaration
var apply = function (customProperty, declaration) {
  customProperty.declarations.forEach(function (customDeclaration) {
    // No need to copy value here as replace will copy value
    var value = customDeclaration.value;

    // Replace parameter variables with user given values
    customDeclaration.variables.forEach(function (variable) {
      value = value.replace(customProperty.parameters[variable], declaration.values[variable]);
    });

    // Using cloneBefore to insert declaration provides sourcemap support
    declaration.cloneBefore({
      prop: customDeclaration.property,
      value: value
    });
  });

  declaration.removeSelf();
};

module.exports = postcss.plugin('postcss-properties-properties', function (options) {
  options = options || {};

  return function (css) {
    var properties = Object.create({});

    // Use eachInside instead of more specific API methods to maintain redefinition and usage ordering
    css.eachInside(function (node) {
      if (node.type === 'rule') {
        if (node.selector.match(customPropertyPattern)) {
          define(properties, node);
        }
      }
      else if (node.type === 'decl') {
        node.values = postcss.list.space(node.value);
        var property = node.prop + propertyKeyDelimiter + node.values.length;
        if (properties[property]) {
          apply(properties[property], node);
        }
      }
    });
  };
});
<commit_msg>Change .includes to .indexOf for node.js fix<commit_after>'use strict';

var postcss = require('postcss');

var variablesPattern      = /\$\S+/g;
var parametersPattern     = variablesPattern;
var customPropertyPattern = /^[^${}: ]+ *: /;
var propertyKeyDelimiter  = ':';

// Adds a property definition to properties
var define = function (properties, rule) {
  var name = rule.selector.match(customPropertyPattern).shift().replace(':', '').trim();
  var parameters = rule.selector.match(parametersPattern);

  var property = {
    name: name,
    parameters: parameters,
    declarations: rule.nodes.map(function (node) {
      return {
        property: node.prop,
        value: node.value,
        // Parses variables that are also parameters. Ignores other variables for compatability with Sass variables.
        // We only need the index of each parameter
        variables: node.value.match(variablesPattern).filter(function (variable) {
          return node.value.indexOf(variable) !== -1;
        }).map(function (variable) {
          return parameters.indexOf(variable);
        })
      };
    })
  };

  properties[property.name + propertyKeyDelimiter + parameters.length] = property;
  rule.removeSelf();
};

// Applies the custom property to the given declaration
var apply = function (customProperty, declaration) {
  customProperty.declarations.forEach(function (customDeclaration) {
    // No need to copy value here as replace will copy value
    var value = customDeclaration.value;

    // Replace parameter variables with user given values
    customDeclaration.variables.forEach(function (variable) {
      value = value.replace(customProperty.parameters[variable], declaration.values[variable]);
    });

    // Using cloneBefore to insert declaration provides sourcemap support
    declaration.cloneBefore({
      prop: customDeclaration.property,
      value: value
    });
  });

  declaration.removeSelf();
};

module.exports = postcss.plugin('postcss-properties-properties', function (options) {
  options = options || {};

  return function (css) {
    var properties = Object.create({});

    // Use eachInside instead of more specific API methods to maintain redefinition and usage ordering
    css.eachInside(function (node) {
      if (node.type === 'rule') {
        if (node.selector.match(customPropertyPattern)) {
          define(properties, node);
        }
      }
      else if (node.type === 'decl') {
        node.values = postcss.list.space(node.value);
        var property = node.prop + propertyKeyDelimiter + node.values.length;
        if (properties[property]) {
          apply(properties[property], node);
        }
      }
    });
  };
});
<|endoftext|>


<commit_before>/*global JSONPath, getJSON, exports*/
/*jslint vars:true, todo:true*/
(function (undef) {'use strict';

// Todo: utilize
function JSONTransformerEvaluator () {

}
JSONTransformerEvaluator.prototype.applyTemplates = function () {

};
JSONTransformerEvaluator.prototype.callTemplate = function () {

};
JSONTransformerEvaluator.prototype.forEach = function () {

};
JSONTransformerEvaluator.prototype.valueOf = function () {

};

/**
* @param {boolean} config.errorOnEqualPriority
*/
function JSONPathTransformer (config) {
    if (!(this instanceof JSONPathTransformer)) {
        return new JSONPathTransformer(config);
    }
    var that = this;
    var map = {};
    this.config = config;
    this.rootTemplates = [];
    this.templates.forEach(function (template, i, templates) {
        if (template.name && map[template.name]) {
            throw "Templates must all have different names.";
        }
        map[template.name] = true;
        if (template.path === '$') {
            that.rootTemplates.concat(templates.splice(i, 1));
        }
    });
    map = null;
    this.transform();
}
JSONPathTransformer.prototype.getDefaultPriority = function (path) {
    if (typeof path === 'string') {
        path = JSONPath.toPathArray(path);
    }
    // Todo: Path specificity
    // Let's also, unlike XSLT, give higher priority to absolute fixed paths over recursive descent and priority to longer paths and lower to wildcard terminal points

    // -.5 = *, @string() (etc.)
    // -.25 = Namespace (not relevant without Jamilih)
    // 0 = single name (i.e., $..someName or someName if allowing such relative paths)
    // .5 = ., .., [], [()], [(?)]

};
JSONPathTransformer.prototype.transform = function () {
    var config = this.config;
    var matched = this.templates.sort(function (a, b) {

        var aPriority = typeof a.priority === 'number' ? a.priority : this.getDefaultPriority(a.path);
        var bPriority = typeof b.priority === 'number' ? b.priority : this.getDefaultPriority(a.path);

        if (aPriority === bPriority && this.config.errorOnEqualPriority) {
            throw "You have configured JSONPathTransformer to throw errors on finding templates of equal priority and these have been found.";
        }

        return (aPriority > bPriority) ? -1 : 1; // We want equal conditions to go in favor of the later (b)
    }).some(function (templateObj) {
        var path = templateObj.path;
        var json = config.data;
        var values = JSONPath({json: json, path: path, resultType: 'value', wrap: false, callback: function (parent, property, value, path) {

        }});
        if (values) {
            templateObj.template(values, path, json);
        }
        return true;
    });

    if (!matched) { // Should not get here with default template rules in place
        throw "No template rules matched";
    }
};
JSONPathTransformer.DefaultTemplateRules = [
    // Todo: Apply default template rules
    /*
    / | *                                : apply-templates          (this.applyTemplates())
    / | * mode                           : apply-templates mode     (this.config.mode)
    text() | @*                          : value-of select="."      (this.valueOf({select: '.'}) or this.valueOf('.'))
    processing-instruction() | comment() : (nothing); optionally allow JSON equivalents or Jamilih
    (an XSLT processor is not to copy any part of the namespace node to the output); optionally allow JSON equivalents or Jamilih
    */
];

/**
* For templates/queries, one may choose among config.query, config.template, or config.templates, but one must be present and of valid type. For the source json, one must use either a valid config.ajaxData or config.data parameter.
* @param {function} config.success A callback supplied with a single argument that is the result of this instance's transform() method.
* @param {array} [config.templates] An array of template objects
* @param {object|function} [config.template] A function assumed to be a root template or a single, complete template object
* @param {function} [config.query] A function assumed to be a root template
* @param {object} [config.data] A JSON object
* @param {string} [config.ajaxData] URL of a JSON file to retrieve for evaluation
* @param {boolean} [config.errorOnEqualPriority=false]
* @param {boolean} [config.autostart=true] Whether to begin transform() immediately.
* @param {string} [config.mode=''] The mode in which to begin the transform.
* @param {function} [config.engine=JSONPathTransformer] Will be based the same config as passed to this instance. Defaults to a transforming function based on JSONPath and with its own set of priorities for processing templates.
* @returns {JTLT} A JTLT instance object
*/
function JTLT (config) {
    if (!(this instanceof JTLT)) {
        return new JTLT(config);
    }

    this.setDefaults(config);
    var that = this;
    if (this.config.ajaxData) {
        getJSON(this.config.ajaxData, function (json) {
            that.config.data = json;
            that._autoStart();
        });
        return this;
    }
    this._autoStart();
}
JTLT.prototype._autoStart = function () {
    if (this.config.autostart !== false || this.ready) {
        this.config.success(this.transform());
    }
};
JTLT.prototype.setDefaults = function (config) {
    var query = config.query || (typeof config.templates === 'function' ? config.templates : (typeof config.template === 'function' ? config.template : null));
    this.templates = query ? [{name: 'root', path: '$', template: query}] : (config.templates || [config.template]);
    this.config.errorOnEqualPriority = config.errorOnEqualPriority || false;
    this.config = config || {};
    this.config.engine = this.config.engine || JSONPathTransformer;
    return this;
};
/**
* @returns {any}
*/
JTLT.prototype.transform = function () {
    if (this.config.data === undef) {
        if (this.config.ajaxData) {
            this.ready = true;
            return;
        }
        throw "You must supply a 'data' or 'ajaxData' property";
    }
    if (typeof this.config.success !== 'function') {
        throw "You must supply a 'success' callback";
    }

    return this.config.engine({templates: this.templates, json: this.config.data});
};

if (typeof exports !== 'undefined') {
    exports.JTLT = JTLT;
    exports.JSONPathTransformer = JSONPathTransformer;
}
else {
    window.JTLT = JTLT;
    window.JSONPathTransformer = JSONPathTransformer;
}

}());<commit_msg>More root behavior<commit_after>/*global JSONPath, getJSON, exports*/
/*jslint vars:true, todo:true*/
(function (undef) {'use strict';

// Todo: utilize
function JSONTransformerEvaluator () {

}

JSONTransformerEvaluator.prototype.triggerEqualPriorityError = function () {
    if (this.config.errorOnEqualPriority) {
        throw "You have configured JSONPathTransformer to throw errors on finding templates of equal priority and these have been found.";
    }
};

JSONTransformerEvaluator.prototype.applyTemplates = function () {
    // Todo: adapt this code to only find (and apply) templates per context
    var config = this.config;
    var matched = this.templates.sort(function (a, b) {

        var aPriority = typeof a.priority === 'number' ? a.priority : this.getDefaultPriority(a.path);
        var bPriority = typeof b.priority === 'number' ? b.priority : this.getDefaultPriority(a.path);

        if (aPriority === bPriority) {
            this.triggerEqualPriorityError();
        }

        return (aPriority > bPriority) ? -1 : 1; // We want equal conditions to go in favor of the later (b)
    }).some(function (templateObj) {
        var path = templateObj.path;
        var json = config.data;
        var values = JSONPath({json: json, path: path, resultType: 'value', wrap: false, callback: function (parent, property, value, path) {

        }});
        if (values) {
            templateObj.template(values, path, json);
        }
        return true;
    });

    if (!matched) { // Should not get here with default template rules in place
        throw "No template rules matched";
    }
};
JSONTransformerEvaluator.prototype.callTemplate = function () {

};
JSONTransformerEvaluator.prototype.forEach = function () {

};
JSONTransformerEvaluator.prototype.valueOf = function () {

};

/**
* @param {boolean} config.errorOnEqualPriority
*/
function JSONPathTransformer (config) {
    if (!(this instanceof JSONPathTransformer)) {
        return new JSONPathTransformer(config);
    }
    var that = this;
    var map = {};
    this.config = config;
    this.rootTemplates = [];
    this.templates.forEach(function (template, i, templates) {
        if (template.name && map[template.name]) {
            throw "Templates must all have different names.";
        }
        map[template.name] = true;
        if (template.path === '$') {
            that.rootTemplates.concat(templates.splice(i, 1));
        }
    });
    this.rootTemplates.reverse();
    map = null;
    this.transform();
}
JSONPathTransformer.prototype.getDefaultPriority = function (path) {
    if (typeof path === 'string') {
        path = JSONPath.toPathArray(path);
    }
    // Todo: Path specificity
    // Let's also, unlike XSLT, give higher priority to absolute fixed paths over recursive descent and priority to longer paths and lower to wildcard terminal points

    // -.5 = *, @string() (etc.)
    // -.25 = Namespace (not relevant without Jamilih)
    // 0 = single name (i.e., $..someName or someName if allowing such relative paths)
    // .5 = ., .., [], [()], [(?)]

};

JSONPathTransformer.prototype.defaultRootTemplate = function () {
    return this.applyTemplates();
};

JSONPathTransformer.prototype.transform = function () {

    switch (this.rootTemplates.length) {
        case 0:
            return this.defaultRootTemplate();
        default:
            this.triggerEqualPriorityError();
            /* Fall-through */
        case 1:
            var templateObj = this.rootTemplates[0];
            var path = templateObj.path;
            var json = config.data;
            return templateObj.template(json, path, json);
    }

};

JSONPathTransformer.DefaultTemplateRules = [
    // Todo: Apply default template rules
    /*
    / | *                                : apply-templates          (this.applyTemplates())
    / | * mode                           : apply-templates mode     (this.config.mode)
    text() | @*                          : value-of select="."      (this.valueOf({select: '.'}) or this.valueOf('.'))
    processing-instruction() | comment() : (nothing); optionally allow JSON equivalents or Jamilih
    (an XSLT processor is not to copy any part of the namespace node to the output); optionally allow JSON equivalents or Jamilih
    */
];

/**
* For templates/queries, one may choose among config.query, config.template, or config.templates, but one must be present and of valid type. For the source json, one must use either a valid config.ajaxData or config.data parameter.
* @param {function} config.success A callback supplied with a single argument that is the result of this instance's transform() method.
* @param {array} [config.templates] An array of template objects
* @param {object|function} [config.template] A function assumed to be a root template or a single, complete template object
* @param {function} [config.query] A function assumed to be a root template
* @param {object} [config.data] A JSON object
* @param {string} [config.ajaxData] URL of a JSON file to retrieve for evaluation
* @param {boolean} [config.errorOnEqualPriority=false]
* @param {boolean} [config.autostart=true] Whether to begin transform() immediately.
* @param {string} [config.mode=''] The mode in which to begin the transform.
* @param {function} [config.engine=JSONPathTransformer] Will be based the same config as passed to this instance. Defaults to a transforming function based on JSONPath and with its own set of priorities for processing templates.
* @returns {JTLT} A JTLT instance object
*/
function JTLT (config) {
    if (!(this instanceof JTLT)) {
        return new JTLT(config);
    }

    this.setDefaults(config);
    var that = this;
    if (this.config.ajaxData) {
        getJSON(this.config.ajaxData, function (json) {
            that.config.data = json;
            that._autoStart();
        });
        return this;
    }
    this._autoStart();
}
JTLT.prototype._autoStart = function () {
    if (this.config.autostart !== false || this.ready) {
        this.config.success(this.transform());
    }
};
JTLT.prototype.setDefaults = function (config) {
    var query = config.query || (typeof config.templates === 'function' ? config.templates : (typeof config.template === 'function' ? config.template : null));
    this.templates = query ? [{name: 'root', path: '$', template: query}] : (config.templates || [config.template]);
    this.config.errorOnEqualPriority = config.errorOnEqualPriority || false;
    this.config = config || {};
    this.config.engine = this.config.engine || JSONPathTransformer;
    return this;
};
/**
* @returns {any}
*/
JTLT.prototype.transform = function () {
    if (this.config.data === undef) {
        if (this.config.ajaxData) {
            this.ready = true;
            return;
        }
        throw "You must supply a 'data' or 'ajaxData' property";
    }
    if (typeof this.config.success !== 'function') {
        throw "You must supply a 'success' callback";
    }

    return this.config.engine({templates: this.templates, json: this.config.data});
};

if (typeof exports !== 'undefined') {
    exports.JTLT = JTLT;
    exports.JSONPathTransformer = JSONPathTransformer;
}
else {
    window.JTLT = JTLT;
    window.JSONPathTransformer = JSONPathTransformer;
}

}());<|endoftext|>


<commit_before>"use strict";

var util = require('util');
var through = require('through');

function strictify(file, opts) {
  opts = opts || {};

  var stream = through(write, end);
  var applied = false;

  return stream;

  function write(buf) {
    if (!applied) {
      stream.queue('"use strict";\n');
      applied = true;
    }
    stream.queue(buf);
  }

  function end() {
    stream.queue(null);
  }
}

module.exports = strictify;
<commit_msg>Added the ability to define excluded extensions<commit_after>"use strict";

var util = require('util');
var through = require('through');

function strictify(file, opts) {
  opts = opts || {};

  var stream = through(write, end);
  var applied = false;

  return stream;

  function write(buf) {
    if (!applied && (opts.exclude || []).indexOf(
          path.extname(file).replace(".", "")) < 0) {
      stream.queue('"use strict";\n');
      applied = true;
    }
    stream.queue(buf);
  }

  function end() {
    stream.queue(null);
  }
}

module.exports = strictify;
<|endoftext|>


<commit_before>var EventEmitter = require('events');
var Module = require('module');
var CONF = require('config');

var logCallback = function() {
  console.log.apply(console, arguments);
};

function logConsole(method, module) {
  method = method.toUpperCase();

  var logLevel = CONF.log.customlevels;

  if (logLevel && (method in logLevel) && !logLevel[method]) {
    return;
  }

  var args = [(new Date()).toJSON(), method];
  var index = 1;

  if (module instanceof Module) {
    args.push(module.id);
    index = 2;
  }

  args.push.apply(args, Array.prototype.slice.call(arguments, index));

  logCallback.apply(null, args);
}

module.exports = function init(callback) {
  if (callback && typeof callback === 'function') {
    logCallback = callback;
  }

  ['debug', 'error', 'info', 'log', 'warn'].forEach(function(consoleMethod) {
    var event = 'app:' + consoleMethod;

    if (EventEmitter.listenerCount(process, event) < 1) {
      process.on(event, logConsole.bind(null, consoleMethod));
    }
  });
};
<commit_msg>add events to capture time like `console.time|timeEnd`<commit_after>var EventEmitter = require('events');
var Module = require('module');
var path = require('path');
var CONF = require('config');

var cache = new WeakMap;

var logCallback = function() {
  console.log.apply(console, arguments);
};

function logConsole(method, module) {
  method = method.toUpperCase();

  var logLevel = CONF.log ? CONF.log.customlevels : null;

  if (logLevel && (method in logLevel) && !logLevel[method]) {
    return;
  }

  var args = [(new Date()).toJSON(), method];
  var index = 1;

  if (module instanceof Module) {
    args.push(path.relative(process.cwd(),module.id));
    index = 2;
  }

  args.push.apply(args, Array.prototype.slice.call(arguments, index));

  logCallback.apply(null, args);
}

function timeEnd(module) {
  if (!cache.has(module)) {
    return;
  }

  var cached = cache.get(module);
  var time = (Date.now() - cached.start) + 'ms';

  logConsole('app:time', module, time);

  cache.delete(module);
}

function timeStart(module) {
  if (cache.has(module)) {
    return;
  }

  cache.set(module, {
    start : Date.now()
  });
}

module.exports = function init(callback) {
  if (callback && typeof callback === 'function') {
    logCallback = callback;
  }

  ['debug', 'error', 'info', 'log', 'warn'].forEach(function(consoleMethod) {
    var event = 'app:' + consoleMethod;

    if (EventEmitter.listenerCount(process, event) < 1) {
      process.on(event, logConsole.bind(null, consoleMethod));
    }
  });

  if (EventEmitter.listenerCount(process, 'app:time') < 1) {
    process.on('app:time', timeStart);
  }

  if (EventEmitter.listenerCount(process, 'app:timeend') < 1) {
    process.on('app:timeend', timeEnd);
  }
};
<|endoftext|>


<commit_before>const config = require('./config.js');
console.info(`Creating ${config.bots.length} bots`);

global.Olm = require('olm');
const sdk = require('matrix-js-sdk');
const fs = require('fs');
const makeMessageResponder = require('personality-helper');

const handleMessage = require('./app.js'); // Our 'routes'

config.bots.forEach((botConfig) => {
    console.info(`Starting PoliteAI Matrix Bot using [${botConfig.userId}]`);

    let messageLastReceived = 0;

    try {
        messageLastReceived = Number(fs.readFileSync('./message_received_dtg', 'utf8'));
    } catch (err) {
        const now = Date.now();
        fs.writeFileSync('./message_received_dtg', now, 'utf8');
        messageLastReceived = now;
    }

    if (isNaN(messageLastReceived)) {
        messageLastReceived = Date.now();
    }

    const client = sdk.createClient({ // Create a client with data from config.js
        baseUrl: botConfig.baseUrl,
        userId: botConfig.userId,
        accessToken: botConfig.accessToken
    });

    const messageResponder = makeMessageResponder(config.personalityServer, botConfig.language, botConfig.personality);

    client.startClient(); // Because apparently this is necessary?

    client.on("Room.timeline", async function (event, room, toStartOfTimeline) { // Listen to Room Timeline events
        if (toStartOfTimeline) {
            return; // don't print paginated results
        }
        if (event.getType() !== "m.room.message") {
            return; // only print messages
        }
        if (event.getSender() === botConfig.userId) {
            return;
        }
        if (event._date < messageLastReceived) { // Probably already processed
            return;
        }

        const messageBody = event.getContent().body;
        //handleMessage(messageBody, room, event, client, botConfig.language);

        const response = await messageResponder(messageBody, 'matrix', room.roomId, event.event.event_id, event.event.origin_server_ts);
        if (response && response.response) {
            client.sendTextMessage(room.roomId, `${event.getSender()}: ${response.response}`);
        } else if (response && response.error) {
            console.warn(`Got an error from server for message [${messageBody}]`, response.error);
        }
    });

    client.on("RoomMember.membership", function (event, member) {
        if (member.membership === "invite" && member.userId === botConfig.userId) {
            client.joinRoom(member.roomId).done(function () {
                log.log("Auto-joined %s", member.roomId);
                const room_key = require('crypto').createHash('sha256',salt)
                                    .update('matrix'+member.roomId)
                                    .digest('base64');
                client.sendTextMessage(member.roomId, 'Polite.AI bot has entered the building...\nTeach me more at http://api.polite.ai/admin/'+room_key);

            });
        }
    });

});

// const bodyParser = require('body-parser');
// const express = require('express');
// const apiServer = express();

// const pgp = require('pg-promise')();
// const db = pgp(config.postgres);

// apiServer.use(express.static('./client'));
// apiServer.use(bodyParser.json());

// apiServer.get('/admin/:roomKey', function (req, res) {
//     fs.createReadStream('./client/index.html').pipe(res);
// });

// apiServer.get('/getMessages/:roomKey', function (req, res) {
//     const roomKey = req.params.roomKey;

//     db.query(`SELECT * from messages WHERE room_id='${roomKey}'`)
//         .then(data => {
//             res.send(data);
//         });
// });

// apiServer.post('/sayHello/:eventId', function (req, res) {
//     const data = req.body;

//     console.info(data);

//     res.send('Hi');
// });

// apiServer.listen(8080);
<commit_msg>Fixed issue<commit_after>const config = require('./config.js');
console.info(`Creating ${config.bots.length} bots`);

global.Olm = require('olm');
const sdk = require('matrix-js-sdk');
const fs = require('fs');
const makeMessageResponder = require('personality-helper');

config.bots.forEach((botConfig) => {
    console.info(`Starting PoliteAI Matrix Bot using [${botConfig.userId}]`);

    let messageLastReceived = 0;

    try {
        messageLastReceived = Number(fs.readFileSync('./message_received_dtg', 'utf8'));
    } catch (err) {
        const now = Date.now();
        fs.writeFileSync('./message_received_dtg', now, 'utf8');
        messageLastReceived = now;
    }

    if (isNaN(messageLastReceived)) {
        messageLastReceived = Date.now();
    }

    const client = sdk.createClient({ // Create a client with data from config.js
        baseUrl: botConfig.baseUrl,
        userId: botConfig.userId,
        accessToken: botConfig.accessToken
    });

    const messageResponder = makeMessageResponder(config.personalityServer, botConfig.language, botConfig.personality);

    client.startClient(); // Because apparently this is necessary?

    client.on("Room.timeline", async function (event, room, toStartOfTimeline) { // Listen to Room Timeline events
        if (toStartOfTimeline) {
            return; // don't print paginated results
        }
        if (event.getType() !== "m.room.message") {
            return; // only print messages
        }
        if (event.getSender() === botConfig.userId) {
            return;
        }
        if (event._date < messageLastReceived) { // Probably already processed
            return;
        }

        const messageBody = event.getContent().body;
        //handleMessage(messageBody, room, event, client, botConfig.language);

        const response = await messageResponder(messageBody, 'matrix', room.roomId, event.event.event_id, event.event.origin_server_ts);
        if (response && response.response) {
            client.sendTextMessage(room.roomId, `${event.getSender()}: ${response.response}`);
        } else if (response && response.error) {
            console.warn(`Got an error from server for message [${messageBody}]`, response.error);
        }
    });

    client.on("RoomMember.membership", function (event, member) {
        if (member.membership === "invite" && member.userId === botConfig.userId) {
            client.joinRoom(member.roomId).done(function () {
                log.log("Auto-joined %s", member.roomId);
                const room_key = require('crypto').createHash('sha256',salt)
                                    .update('matrix'+member.roomId)
                                    .digest('base64');
                client.sendTextMessage(member.roomId, 'Polite.AI bot has entered the building...\nTeach me more at http://api.polite.ai/admin/'+room_key);

            });
        }
    });

});

// const bodyParser = require('body-parser');
// const express = require('express');
// const apiServer = express();

// const pgp = require('pg-promise')();
// const db = pgp(config.postgres);

// apiServer.use(express.static('./client'));
// apiServer.use(bodyParser.json());

// apiServer.get('/admin/:roomKey', function (req, res) {
//     fs.createReadStream('./client/index.html').pipe(res);
// });

// apiServer.get('/getMessages/:roomKey', function (req, res) {
//     const roomKey = req.params.roomKey;

//     db.query(`SELECT * from messages WHERE room_id='${roomKey}'`)
//         .then(data => {
//             res.send(data);
//         });
// });

// apiServer.post('/sayHello/:eventId', function (req, res) {
//     const data = req.body;

//     console.info(data);

//     res.send('Hi');
// });

// apiServer.listen(8080);
<|endoftext|>


<commit_before>const deasync = require('deasync');

function warn(warning) {
  warning = Boolean(warning);
  if (warning) {
    console.warn('load config from consul ignored.');
  }
}

function loadConsulConfig(opts) {
  var config = opts.config;
  const path = opts.path;
  const warning = opts.warning === undefined ? true : opts.warning;

  if (!config || !path) {
    warn(warning);
    return;
  }
  if (!config.consul) {
    warn(warning);
    return;
  }

  const promisify = config.consul.promisify;
  config.consul.promisify = false;

  const consul = require('consul')(config.consul);
  config.consul.promisify = promisify;

  function bindConsulConfig(path, cb) {
    consul.kv.get(path, function(err, data) {
      if (err) {
        warn(warning);
        console.error('get consul config error:', err);
      }

      if (data && data.Value) {
        try {
          const value = JSON.parse(data.Value);
          config = config.util.extendDeep(config, value);
        } catch (e) {
          warn(warning);
          console.error(`parse consul config failed: error: ${e}, orginalData: ${JSON.stringify(data)}`);
        }
      }

      return cb(null);
    });
  }
  const bindIt = deasync(bindConsulConfig);
  bindIt.call(this, path);
}

module.exports = loadConsulConfig;
<commit_msg>fix: error should be throwed<commit_after>const deasync = require('deasync');

function warn(warning) {
  warning = Boolean(warning);
  if (warning) {
    console.warn('load config from consul ignored.');
  }
}

function loadConsulConfig(opts) {
  var config = opts.config;
  const path = opts.path;
  const warning = opts.warning === undefined ? true : opts.warning;

  if (!config || !path) {
    warn(warning);
    return;
  }
  if (!config.consul) {
    warn(warning);
    return;
  }

  const promisify = config.consul.promisify;
  config.consul.promisify = false;

  const consul = require('consul')(config.consul);
  config.consul.promisify = promisify;

  function bindConsulConfig(path, cb) {
    consul.kv.get(path, function(err, data) {
      if (err) {
        warn(warning);
        console.error('get consul config error:', err);
        return cb(err);
      }

      if (data && data.Value) {
        try {
          const value = JSON.parse(data.Value);
          config = config.util.extendDeep(config, value);
        } catch (e) {
          warn(warning);
          console.error(`parse consul config failed: error: ${e}, orginalData: ${JSON.stringify(data)}`);
          return cb(e);
        }
      }

      return cb(null);
    });
  }
  const bindIt = deasync(bindConsulConfig);
  bindIt.call(this, path);
}

module.exports = loadConsulConfig;
<|endoftext|>


<commit_before>const chalk = require('chalk');
const { typeOf, log } = require('./lib/utils');
const jsonDiff = require('./lib/jsonDiff');
const printDiff = require('./lib/printDiff');

function compareJson(source, target, isOutLog = true) {
  const typeSource = typeOf(source);
  const typeTarget = typeOf(target);
  let flag = true;
  if (typeSource !== 'object' || typeSource !== typeTarget) {
    const error = chalk.red('Type Error: The type of source, target  must be same, and must be json object!');
    log(error);
  } else {
    const data = jsonDiff(source, target);
    flag = data.flag || true;
    const diffData = printDiff(data.diff);
    if (isOutLog) {
      if (flag) {
        log(chalk.yellow('JSON diff result: \n'), diffData);
      } else {
        log(chalk.yellow('There is no difference between source and target'));
      }
    }
  }
  // if there is a difference between source and target, returning true
  return flag;
}

module.exports = compareJson;
<commit_msg>fix the bug of return value always is true<commit_after>const chalk = require('chalk');
const { typeOf, log } = require('./lib/utils');
const jsonDiff = require('./lib/jsonDiff');
const printDiff = require('./lib/printDiff');

function compareJson(source, target, isOutLog = true) {
  const typeSource = typeOf(source);
  const typeTarget = typeOf(target);
  let flag = true;
  if (typeSource !== 'object' || typeSource !== typeTarget) {
    const error = chalk.red('Type Error: The type of source, target  must be same, and must be json object!');
    log(error);
  } else {
    const data = jsonDiff(source, target);
    flag = data.flag !== undefined ? data.flag : true;
    const diffData = printDiff(data.diff);
    if (isOutLog) {
      if (flag) {
        log(chalk.yellow('JSON diff result: \n'), diffData);
      } else {
        log(chalk.yellow('There is no difference between source and target'));
      }
    }
  }
  // if there is a difference between source and target, returning true
  return flag;
}

module.exports = compareJson;
<|endoftext|>


<commit_before>var path = require('path');
var through = require('through2');
var convert = require('convert-source-map');
var sm = require('source-map');
var crypto = require('crypto');
var fs = require('fs');
var _ = require('lodash');
var RSVP = require('rsvp');

function has(object, propName) {
  return Object.prototype.hasOwnProperty.call(object, propName);
}

function hash(str) {
  var hasher = crypto.createHash('sha256');
  hasher.update(str);
  return hasher.digest('base64').slice(0, 20);
}

var readManagerTemplate = _.once(function() {
  return new RSVP.Promise(function(resolve, reject) {
    fs.readFile(path.join(__dirname, 'hmr-manager-template.js'), 'utf8', function(err, data) {
      if (err)
        reject(err);
      else
        resolve(data);
    });
  });
});

var validUpdateModes = ['xhr', 'fs'];
var updateModesNeedingUrl = ['xhr'];

module.exports = function(bundle, opts) {
  if (!opts) opts = {};
  var updateMode = opts.mode||opts.m||'xhr';
  var updateUrl = opts.url||opts.u||null;
  var updateCacheBust = Boolean(has(opts, 'cacheBust') ? opts.cacheBust : has(opts, 'b') ? opts.b : true);

  if (!_.includes(validUpdateModes, updateMode)) {
    throw new Error("Invalid mode "+updateMode);
  }
  if (!updateUrl && _.includes(updateModesNeedingUrl, updateMode)) {
    throw new Error("url option must be specified for "+updateMode+" mode");
  }

  var hmrManagerFilename = path.join(__dirname, '__hmr_manager.js');

  function setupPipelineMods() {
    var originalEntries = [];
    bundle.pipeline.get('record').push(through.obj(function(row, enc, next) {
      if (row.entry) {
        originalEntries.push(row.file);
        next(null);
      } else {
        next(null, row);
      }
    }, function(next) {
      var source = originalEntries.map(function(name) {
        return 'require('+JSON.stringify(name)+');\n';
      }).join('');
      this.push({
        entry: true,
        expose: false,
        basedir: undefined,
        file: hmrManagerFilename,
        id: hmrManagerFilename,
        source: source,
        order: 0
      });
      next();
    }));

    var moduleMeta = {};

    function makeModuleMetaEntry(name) {
      if (!has(moduleMeta, name)) {
        moduleMeta[name] = {
          index: null,
          hash: null,
          parents: []
        };
      }
    }

    bundle.pipeline.get('deps').push(through.obj(function(row, enc, next) {
      if (row.file !== hmrManagerFilename) {
        makeModuleMetaEntry(row.file);
        _.forOwn(row.deps, function(name, ref) {
          // dependencies that aren't included in the bundle have the name false
          if (name) {
            makeModuleMetaEntry(name);
            moduleMeta[name].parents.push(row.file);
          }
        });
      }
      next(null, row);
    }));

    bundle.pipeline.get('syntax').push(through.obj(function(row, enc, next) {
      if (row.file === hmrManagerFilename) {
        next(null, row);
      } else {
        var header = '_hmr.initModule('+JSON.stringify(row.file)+', module);\n(function(){\n';
        var footer = '\n}).call(this, arguments);\n';

        var inputMapConsumer;
        var inputMap = convert.fromSource(row.source);
        if (inputMap) {
          inputMapConsumer = new sm.SourceMapConsumer(inputMap.toObject());
          row.source = convert.removeComments(row.source);
        }
        var outputMapGenerator = new sm.SourceMapGenerator({
          file: row.file
        });
        var lines = row.source.split('\n').length;
        for (var i=1; i<=lines; i++) {
          outputMapGenerator.addMapping({
            generated: {line:i+2,column:0},
            original: {line:i,column:0},
            source: row.file
          });
        }
        outputMapGenerator.setSourceContent(row.file, row.source);
        if (inputMapConsumer) {
          outputMapGenerator.applySourceMap(inputMapConsumer);
        }
        var mergedMap = outputMapGenerator.toJSON();
        if (inputMap) {
          mergedMap.sources = inputMap.sources || [inputMap.file ? inputMap.file : row.file];
          mergedMap.file = inputMap.file;
        }
        row.source = header + row.source + footer +
          '\n' + convert.fromObject(mergedMap).toComment();
        next(null, row);
      }
    }));

    var labelRows = [];
    var managerRow = null;
    bundle.pipeline.get('label').push(through.obj(function(row, enc, next) {
      if (row.file !== hmrManagerFilename) {
        moduleMeta[row.file].index = row.index;
        moduleMeta[row.file].hash = hash(row.source);
        labelRows.push(row);
      } else {
        managerRow = row;
      }
      next(null);
    }, function(done) {
      var self = this;
      readManagerTemplate().then(function(mgrTemplate) {
        managerRow.source = mgrTemplate
          .replace('null/*!^^moduleMeta*/', JSON.stringify(moduleMeta))
          .replace('null/*!^^originalEntries*/', JSON.stringify(originalEntries))
          .replace('null/*!^^updateUrl*/', JSON.stringify(updateUrl))
          .replace('null/*!^^updateMode*/', JSON.stringify(updateMode))
          .replace('null/*!^^updateCacheBust*/', JSON.stringify(updateCacheBust));
        self.push(managerRow);
        labelRows.forEach(function(row) {
          self.push(row);
        });
      }).then(done, done);
    }));
  }
  setupPipelineMods();

  bundle.on('reset', setupPipelineMods);
};
<commit_msg>fix hmr entry to not be in node_modules/ which causes weirdness in transforms like babelify. See https://github.com/babel/babelify/issues/85<commit_after>var path = require('path');
var through = require('through2');
var convert = require('convert-source-map');
var sm = require('source-map');
var crypto = require('crypto');
var fs = require('fs');
var _ = require('lodash');
var RSVP = require('rsvp');

function has(object, propName) {
  return Object.prototype.hasOwnProperty.call(object, propName);
}

function hash(str) {
  var hasher = crypto.createHash('sha256');
  hasher.update(str);
  return hasher.digest('base64').slice(0, 20);
}

var readManagerTemplate = _.once(function() {
  return new RSVP.Promise(function(resolve, reject) {
    fs.readFile(path.join(__dirname, 'hmr-manager-template.js'), 'utf8', function(err, data) {
      if (err)
        reject(err);
      else
        resolve(data);
    });
  });
});

var validUpdateModes = ['xhr', 'fs'];
var updateModesNeedingUrl = ['xhr'];

module.exports = function(bundle, opts) {
  if (!opts) opts = {};
  var updateMode = opts.mode||opts.m||'xhr';
  var updateUrl = opts.url||opts.u||null;
  var updateCacheBust = Boolean(has(opts, 'cacheBust') ? opts.cacheBust : has(opts, 'b') ? opts.b : true);

  if (!_.includes(validUpdateModes, updateMode)) {
    throw new Error("Invalid mode "+updateMode);
  }
  if (!updateUrl && _.includes(updateModesNeedingUrl, updateMode)) {
    throw new Error("url option must be specified for "+updateMode+" mode");
  }

  var hmrManagerFilename;

  function setupPipelineMods() {
    var originalEntries = [];
    bundle.pipeline.get('record').push(through.obj(function(row, enc, next) {
      if (row.entry) {
        originalEntries.push(row.file);
        next(null);
      } else {
        next(null, row);
      }
    }, function(next) {
      var source = originalEntries.map(function(name) {
        return 'require('+JSON.stringify(name)+');\n';
      }).join('');

      // Put the hmr file name in the same directory as an entry file in order
      // to prevent this: https://github.com/babel/babelify/issues/85
      hmrManagerFilename = path.join(path.dirname(originalEntries[0]), '__hmr_manager.js');
      this.push({
        entry: true,
        expose: false,
        basedir: undefined,
        file: hmrManagerFilename,
        id: hmrManagerFilename,
        source: source,
        order: 0
      });
      next();
    }));

    var moduleMeta = {};

    function makeModuleMetaEntry(name) {
      if (!has(moduleMeta, name)) {
        moduleMeta[name] = {
          index: null,
          hash: null,
          parents: []
        };
      }
    }

    bundle.pipeline.get('deps').push(through.obj(function(row, enc, next) {
      if (row.file !== hmrManagerFilename) {
        makeModuleMetaEntry(row.file);
        _.forOwn(row.deps, function(name, ref) {
          // dependencies that aren't included in the bundle have the name false
          if (name) {
            makeModuleMetaEntry(name);
            moduleMeta[name].parents.push(row.file);
          }
        });
      }
      next(null, row);
    }));

    bundle.pipeline.get('syntax').push(through.obj(function(row, enc, next) {
      if (row.file === hmrManagerFilename) {
        next(null, row);
      } else {
        var header = '_hmr.initModule('+JSON.stringify(row.file)+', module);\n(function(){\n';
        var footer = '\n}).call(this, arguments);\n';

        var inputMapConsumer;
        var inputMap = convert.fromSource(row.source);
        if (inputMap) {
          inputMapConsumer = new sm.SourceMapConsumer(inputMap.toObject());
          row.source = convert.removeComments(row.source);
        }
        var outputMapGenerator = new sm.SourceMapGenerator({
          file: row.file
        });
        var lines = row.source.split('\n').length;
        for (var i=1; i<=lines; i++) {
          outputMapGenerator.addMapping({
            generated: {line:i+2,column:0},
            original: {line:i,column:0},
            source: row.file
          });
        }
        outputMapGenerator.setSourceContent(row.file, row.source);
        if (inputMapConsumer) {
          outputMapGenerator.applySourceMap(inputMapConsumer);
        }
        var mergedMap = outputMapGenerator.toJSON();
        if (inputMap) {
          mergedMap.sources = inputMap.sources || [inputMap.file ? inputMap.file : row.file];
          mergedMap.file = inputMap.file;
        }
        row.source = header + row.source + footer +
          '\n' + convert.fromObject(mergedMap).toComment();
        next(null, row);
      }
    }));

    var labelRows = [];
    var managerRow = null;
    bundle.pipeline.get('label').push(through.obj(function(row, enc, next) {
      if (row.file !== hmrManagerFilename) {
        moduleMeta[row.file].index = row.index;
        moduleMeta[row.file].hash = hash(row.source);
        labelRows.push(row);
      } else {
        managerRow = row;
      }
      next(null);
    }, function(done) {
      var self = this;
      readManagerTemplate().then(function(mgrTemplate) {
        managerRow.source = mgrTemplate
          .replace('null/*!^^moduleMeta*/', JSON.stringify(moduleMeta))
          .replace('null/*!^^originalEntries*/', JSON.stringify(originalEntries))
          .replace('null/*!^^updateUrl*/', JSON.stringify(updateUrl))
          .replace('null/*!^^updateMode*/', JSON.stringify(updateMode))
          .replace('null/*!^^updateCacheBust*/', JSON.stringify(updateCacheBust));
        self.push(managerRow);
        labelRows.forEach(function(row) {
          self.push(row);
        });
      }).then(done, done);
    }));
  }
  setupPipelineMods();

  bundle.on('reset', setupPipelineMods);
};
<|endoftext|>


<commit_before>var assert = require('assert'), crypto = require('crypto');
var DataReader = require('seccamp2015-data-reader').DataReader;

function incSeq(buf){
  var i;
  for(i=buf.length-1; i >= 0;i--){
    if(buf[i] < 0xff){
      buf[i]++;
      break;
    }
    buf[i] = 0x00;
  }
}

var type = {
  changecipherspec: 0x14,
  alert: 0x15,
  handshake: 0x16,
  application: 0x17
};

var handshake_type = {
  clienthello: 0x01,
  clientkeyexchange: 0x10,
  finished: 0x14
};

function writeVector(data, floor, ceiling) {
  assert(data.length >= floor);
  assert(ceiling >= data.length);
  var vector_length = Math.ceil(ceiling.toString(2).length/8);
  var length = new Buffer(vector_length);
  length.writeUIntBE(data.length, 0, vector_length);
  return Buffer.concat([length, data]);
}

function checkRecordHeader(reader) {
  if (5 > reader.bytesRemaining())
    return null;

  var length = reader.peekBytes(0, 5).readUIntBE(3, 2);
  if (length > reader.bytesRemaining())
    return null;

  return true;
}

function createRecord(type, data) {
  var header = new Buffer(5);
  header[0] = type;
  header[1] = 0x03;
  header[2] = 0x03;
  header.writeUIntBE(data.length, 3, 2);
  return Buffer.concat([header, data]);
}

function parseRecordHeader(reader) {
  assert(reader.bytesRemaining() >= 5);
  var type = reader.readBytes(1).readUInt8(0);
  var version = reader.readBytes(2);
  var length = reader.readBytes(2).readUIntBE(0, 2);
  return {type: type, version: version, length: length};
}

function createHandshake(type, data) {
  var header = new Buffer(4);
  header[0] = type;
  header.writeUIntBE(data.length, 1, 3);
  return Buffer.concat([header, data]);
}

exports.createClientHello = createClientHello;
function createClientHello(json, state) {
  state.handshake.clienthello_json = json;
  var version = json.version;
  var random = json.random;
  var session_id = writeVector(json.session_id, 0, 32);
  var cipher_suites = writeVector(Buffer.concat(json.cipher_suites), 2, 1 << 16 - 2);
  var compression = writeVector(json.compression, 0, 1 << 8 -1);
  var handshake = createHandshake(handshake_type.clienthello, Buffer.concat([version, random, session_id, cipher_suites, compression]));
  return createRecord(type.handshake, handshake);
}

exports.parseServerHello = parseServerHello;
function parseServerHello(reader, state) {
  if (!checkRecordHeader(reader))
    return null;

  var record_header = parseRecordHeader(reader);
  var handshake_msg_buf = reader.peekBytes(0, record_header.length);
  state.handshake_message_list.push(handshake_msg_buf);

  var type = reader.readBytes(1).readUInt8(0);
  var length = reader.readBytes(3).readUIntBE(0, 3);
  var version = reader.readBytes(2);
  var random = reader.readBytes(32);
  var session_id = reader.readVector(0, 32);
  var cipher = reader.readBytes(2);
  var compression = reader.readBytes(1);

  state.handshake.serverhello_json = {
    record_header: record_header,
    type: type,
    length: length,
    version: version,
    random: random,
    session_id: session_id,
    cipher: cipher,
    compression: compression
  };
  return true;
}

exports.parseCertificate = parseCertificate;
function parseCertificate(reader, state) {
  if (!checkRecordHeader(reader))
    return null;

  var record_header = parseRecordHeader(reader);
  var handshake_msg_buf = reader.peekBytes(0, record_header.length);
  state.handshake_message_list.push(handshake_msg_buf);

  var type = reader.readBytes(1).readUInt8(0);
  var length = reader.readBytes(3).readUIntBE(0, 3);
  var cert_reader = new DataReader(reader.readBytes(length));
  var certlist = [];
  while(cert_reader.bytesRemaining() > 0) {
    var cert = cert_reader.readVector(0, 1 << 24 - 1);
    certlist.push(cert);
  }

  state.handshake.certificate_json = {
    record_header: record_header,
    type: type,
    length: length,
    certlist: certlist
  };
  return true;
}

exports.parseServerHelloDone = parseServerHelloDone;
function parseServerHelloDone(reader, state) {
  if (!checkRecordHeader(reader))
    return null;

  var record_header = parseRecordHeader(reader);
  var handshake_msg_buf = reader.peekBytes(0, record_header.length);
  state.handshake_message_list.push(handshake_msg_buf);

  var type = reader.readBytes(1).readUInt8(0);
  var length = reader.readBytes(3).readUIntBE(0, 3);

  state.handshake.serverhellodone_json = {
    record_header: record_header,
    type: type,
    length: length,
    buf: handshake_msg_buf
  };
  return true;
}

exports.parseServerFinished = parseServerFinished;
function parseServerFinished(reader, state) {
  if (!checkRecordHeader(reader))
    return null;

  var record_header = parseRecordHeader(reader);
  var handshake_msg_buf = reader.peekBytes(0, record_header.length);
  var type = reader.readBytes(1).readUInt8(0);
  var length = reader.readBytes(3).readUIntBE(0, 3);
  var verify_data = reader.readBytes(length);

  var shasum = crypto.createHash('sha256');
  shasum.update(Buffer.concat(state.handshake_message_list));
  var message_hash = shasum.digest();

  state.handshake_message_list.push(handshake_msg_buf);

  var master_secret = state.keyblock_json.master_secret;
  var r = PRF12(master_secret, "server finished", message_hash, 12);

  assert(r.equals(verify_data));

  state.handshake.serverfinished_json = {
    record_header: record_header,
    type: type,
    length: length,
    verify_data: verify_data
  };
  return true;
}

exports.parseApplicationData = parseApplicationData;
function parseApplicationData(reader) {
  if (!checkRecordHeader(reader))
    return null;

  var record_header = parseRecordHeader(reader);
  var data = reader.readBytes(record_header.length);
  return {
    record_header: record_header,
    data: data
  };
}

function P_hash(algo, secret, seed, size) {
  var result = (new Buffer(size)).fill(0);
  var hmac = crypto.createHmac(algo, secret);
  hmac.update(seed);
  var a = hmac.digest(); // A(1)
  var j = 0;
  while(j < size) {
    hmac = crypto.createHmac(algo, secret);
    hmac.update(a);
    hmac.update(seed);
    var b = hmac.digest();
    var todo = b.length;
    if (j + todo > size) {
      todo = size -j;
    }
    b.copy(result, j, 0, todo);
    j += todo;

    hmac = crypto.createHmac(algo, secret);
    hmac.update(a);
    a = hmac.digest(); // A(i+1)
  }

  return result;
}

function PRF12(secret, label, seed, size) {
  var newSeed = Buffer.concat([new Buffer(label), seed]);
  return P_hash('sha256', secret, newSeed, size);
}

function KDF(pre_master_secret, clienthello_json, serverhello_json) {
  var client_random = clienthello_json.random;
  var server_random = serverhello_json.random;
  var master_secret = PRF12(pre_master_secret, "master secret", Buffer.concat([client_random, server_random]), 48);
  var key_block_reader = new DataReader(   // 40bytes key_block for AES-128-GCM
    PRF12(master_secret, "key expansion", Buffer.concat([server_random, client_random]), 40));

  return {
    master_secret: master_secret,
    client_write_MAC_key: null,
    server_write_MAC_key: null,
    client_write_key: key_block_reader.readBytes(16),
    server_write_key: key_block_reader.readBytes(16),
    client_write_IV: key_block_reader.readBytes(4),
    server_write_IV: key_block_reader.readBytes(4)
  };
}

exports.createClientKeyExchange = createClientKeyExchange;
function createClientKeyExchange(json, state) {
  state.handshake.clientkeyexchange_json = json;
  var public_key = json.pubkey;
  var pre_master_secret = json.pre_master_secret;
  var encrypted = crypto.publicEncrypt({
    key: public_key,
    padding: require('constants').RSA_PKCS1_PADDING
  }, pre_master_secret);
  var encrypted_pre_master_secret = writeVector(encrypted, 0, 1 << 16 - 1);
  var handshake = createHandshake(handshake_type.clientkeyexchange, encrypted_pre_master_secret);
  return createRecord(type.handshake, handshake);
};

exports.createChangeCipherSpec = createChangeCipherSpec;
function createChangeCipherSpec() {
  return new Buffer('140303000101', 'hex');
};

exports.createClientFinished = createClientFinished;
function createClientFinished(json, state) {
  state.handshake.clientfinished_json = json;
  var shasum = crypto.createHash('sha256');
  shasum.update(Buffer.concat(json.handshake_message_list));
  var message_hash = shasum.digest();
  var r = PRF12(json.master_secret, "client finished", message_hash, 12);
  var handshake = createHandshake(handshake_type.finished, r);
  return createRecord(type.handshake, handshake);
}

exports.createApplicationData = createApplicationData;
function createApplicationData(data) {
  return createRecord(type.application, data);
}

exports.DecryptAEAD = DecryptAEAD;
function DecryptAEAD(reader, state) {
  if (!checkRecordHeader(reader))
    return null;

  var write_key = state.keyblock_json.server_write_key;
  var write_iv = state.keyblock_json.server_write_IV;

  var record_header_type_version = reader.peekBytes(0, 3);
  var record_header = parseRecordHeader(reader);
  var frame = reader.readBytes(record_header.length);
  var nonce_explicit = frame.slice(0, 8);
  var enc_data = frame.slice(8, frame.length - 16);
  var record_header_length = new Buffer(2);
  record_header_length.writeUInt16BE(enc_data.length);
  var record_header_buf = Buffer.concat([record_header_type_version, record_header_length]);
  var tag = frame.slice(-16);
  var iv = Buffer.concat([write_iv.slice(0,4), nonce_explicit]);
  var bob = crypto.createDecipheriv('aes-128-gcm', write_key, iv);
  bob.setAuthTag(tag);
  var aad = Buffer.concat([state.read_seq, record_header_buf]);
  bob.setAAD(aad);
  var clear = bob.update(enc_data);
  var length = new Buffer(2);
  length.writeUIntBE(clear.length, 0, 2);
  bob.final();
  incSeq(state.read_seq);
  var buf = reader.readBytes(reader.bytesRemaining());
  return new DataReader(Buffer.concat([record_header_type_version, length, clear, buf]));
}

exports.createPreMasterSecretRSAKeyExchange = createPreMasterSecretRSAKeyExchange;
function createPreMasterSecretRSAKeyExchange(state) {
  var pre_master_secret = Buffer.concat([state.handshake.clienthello_json.version, crypto.randomBytes(46)]);
  return pre_master_secret;
}

exports.createKeyBlock = createKeyBlock;
function createKeyBlock(pre_master_secret, state) {
  var keyblock_json = KDF(pre_master_secret, state.handshake.clienthello_json, state.handshake.serverhello_json);
  return keyblock_json;
}

exports.sendClientKeyExchange = sendClientKeyExchange;
function sendClientKeyExchange(state) {
  var pre_master_secret = createPreMasterSecretRSAKeyExchange(state);
  state.keyblock_json = createKeyBlock(pre_master_secret, state);
  var clientkeyexchange_json = {
    pre_master_secret: pre_master_secret,
    pubkey: require('fs').readFileSync(__dirname + '/pubkey.pem')
  };
  var clientkeyexchange = createClientKeyExchange(clientkeyexchange_json, state);
  sendTLSFrame(clientkeyexchange, state);
}

exports.sendChangeCipherSpec = sendChangeCipherSpec;
function sendChangeCipherSpec(state) {
  var changecipherspec = createChangeCipherSpec();
  sendTLSFrame(changecipherspec, state);
  state.send_encrypted = true;
}

exports.sendClientFinished = sendClientFinished;
function sendClientFinished(state) {
  var clientfinished_json = {
    master_secret: state.keyblock_json.master_secret,
    handshake_message_list: state.handshake_message_list
  };
  var clientfinished = createClientFinished(clientfinished_json, state);
  sendTLSFrame(clientfinished, state);
}

exports.sendClientFrame = sendClientFrame;
function sendClientFrame(state) {
  sendClientKeyExchange(state);
  sendChangeCipherSpec(state);
  state.send_encrypted = true;
  sendClientFinished(state);
}

exports.sendTLSFrame = sendTLSFrame;
function sendTLSFrame(frame, state) {
  if (frame[0] === type.handshake)
    state.handshake_message_list.push(frame.slice(5));

  if (state.send_encrypted)
    frame = EncryptAEAD(frame, state);

  state.socket.write(frame);
}

exports.EncryptAEAD = EncryptAEAD;
function EncryptAEAD(frame, state) {
  var iv = Buffer.concat([state.keyblock_json.client_write_IV.slice(0,4), state.nonce_explicit]);
  var bob = crypto.createCipheriv('aes-128-gcm', state.keyblock_json.client_write_key, iv);
  var record_header = frame.slice(0, 5);
  var aad = Buffer.concat([state.write_seq, record_header]);
  bob.setAAD(aad);
  var encrypted1 = bob.update(frame.slice(5));
  var encrypted2 = bob.final();
  var encrypted = Buffer.concat([encrypted1, encrypted2]);
  var tag = bob.getAuthTag(tag);
  incSeq(state.write_seq);
  record_header.writeUIntBE(state.nonce_explicit.length + encrypted.length + tag.length, 3, 2);
  return Buffer.concat([record_header, state.nonce_explicit, encrypted, tag]);
}
<commit_msg>export checkRecordHeader<commit_after>var assert = require('assert'), crypto = require('crypto');
var DataReader = require('seccamp2015-data-reader').DataReader;

function incSeq(buf){
  var i;
  for(i=buf.length-1; i >= 0;i--){
    if(buf[i] < 0xff){
      buf[i]++;
      break;
    }
    buf[i] = 0x00;
  }
}

var type = {
  changecipherspec: 0x14,
  alert: 0x15,
  handshake: 0x16,
  application: 0x17
};

var handshake_type = {
  clienthello: 0x01,
  clientkeyexchange: 0x10,
  finished: 0x14
};

function writeVector(data, floor, ceiling) {
  assert(data.length >= floor);
  assert(ceiling >= data.length);
  var vector_length = Math.ceil(ceiling.toString(2).length/8);
  var length = new Buffer(vector_length);
  length.writeUIntBE(data.length, 0, vector_length);
  return Buffer.concat([length, data]);
}

exports.checkRecordHeader = checkRecordHeader;
function checkRecordHeader(reader) {
  if (5 > reader.bytesRemaining())
    return null;

  var length = reader.peekBytes(0, 5).readUIntBE(3, 2);
  if (length > reader.bytesRemaining())
    return null;

  return true;
}

function createRecord(type, data) {
  var header = new Buffer(5);
  header[0] = type;
  header[1] = 0x03;
  header[2] = 0x03;
  header.writeUIntBE(data.length, 3, 2);
  return Buffer.concat([header, data]);
}

function parseRecordHeader(reader) {
  assert(reader.bytesRemaining() >= 5);
  var type = reader.readBytes(1).readUInt8(0);
  var version = reader.readBytes(2);
  var length = reader.readBytes(2).readUIntBE(0, 2);
  return {type: type, version: version, length: length};
}

function createHandshake(type, data) {
  var header = new Buffer(4);
  header[0] = type;
  header.writeUIntBE(data.length, 1, 3);
  return Buffer.concat([header, data]);
}

exports.createClientHello = createClientHello;
function createClientHello(json, state) {
  state.handshake.clienthello_json = json;
  var version = json.version;
  var random = json.random;
  var session_id = writeVector(json.session_id, 0, 32);
  var cipher_suites = writeVector(Buffer.concat(json.cipher_suites), 2, 1 << 16 - 2);
  var compression = writeVector(json.compression, 0, 1 << 8 -1);
  var handshake = createHandshake(handshake_type.clienthello, Buffer.concat([version, random, session_id, cipher_suites, compression]));
  return createRecord(type.handshake, handshake);
}

exports.parseServerHello = parseServerHello;
function parseServerHello(reader, state) {
  if (!checkRecordHeader(reader))
    return null;

  var record_header = parseRecordHeader(reader);
  var handshake_msg_buf = reader.peekBytes(0, record_header.length);
  state.handshake_message_list.push(handshake_msg_buf);

  var type = reader.readBytes(1).readUInt8(0);
  var length = reader.readBytes(3).readUIntBE(0, 3);
  var version = reader.readBytes(2);
  var random = reader.readBytes(32);
  var session_id = reader.readVector(0, 32);
  var cipher = reader.readBytes(2);
  var compression = reader.readBytes(1);

  state.handshake.serverhello_json = {
    record_header: record_header,
    type: type,
    length: length,
    version: version,
    random: random,
    session_id: session_id,
    cipher: cipher,
    compression: compression
  };
  return true;
}

exports.parseCertificate = parseCertificate;
function parseCertificate(reader, state) {
  if (!checkRecordHeader(reader))
    return null;

  var record_header = parseRecordHeader(reader);
  var handshake_msg_buf = reader.peekBytes(0, record_header.length);
  state.handshake_message_list.push(handshake_msg_buf);

  var type = reader.readBytes(1).readUInt8(0);
  var length = reader.readBytes(3).readUIntBE(0, 3);
  var cert_reader = new DataReader(reader.readBytes(length));
  var certlist = [];
  while(cert_reader.bytesRemaining() > 0) {
    var cert = cert_reader.readVector(0, 1 << 24 - 1);
    certlist.push(cert);
  }

  state.handshake.certificate_json = {
    record_header: record_header,
    type: type,
    length: length,
    certlist: certlist
  };
  return true;
}

exports.parseServerHelloDone = parseServerHelloDone;
function parseServerHelloDone(reader, state) {
  if (!checkRecordHeader(reader))
    return null;

  var record_header = parseRecordHeader(reader);
  var handshake_msg_buf = reader.peekBytes(0, record_header.length);
  state.handshake_message_list.push(handshake_msg_buf);

  var type = reader.readBytes(1).readUInt8(0);
  var length = reader.readBytes(3).readUIntBE(0, 3);

  state.handshake.serverhellodone_json = {
    record_header: record_header,
    type: type,
    length: length,
    buf: handshake_msg_buf
  };
  return true;
}

exports.parseServerFinished = parseServerFinished;
function parseServerFinished(reader, state) {
  if (!checkRecordHeader(reader))
    return null;

  var record_header = parseRecordHeader(reader);
  var handshake_msg_buf = reader.peekBytes(0, record_header.length);
  var type = reader.readBytes(1).readUInt8(0);
  var length = reader.readBytes(3).readUIntBE(0, 3);
  var verify_data = reader.readBytes(length);

  var shasum = crypto.createHash('sha256');
  shasum.update(Buffer.concat(state.handshake_message_list));
  var message_hash = shasum.digest();

  state.handshake_message_list.push(handshake_msg_buf);

  var master_secret = state.keyblock_json.master_secret;
  var r = PRF12(master_secret, "server finished", message_hash, 12);

  assert(r.equals(verify_data));

  state.handshake.serverfinished_json = {
    record_header: record_header,
    type: type,
    length: length,
    verify_data: verify_data
  };
  return true;
}

exports.parseApplicationData = parseApplicationData;
function parseApplicationData(reader) {
  if (!checkRecordHeader(reader))
    return null;

  var record_header = parseRecordHeader(reader);
  var data = reader.readBytes(record_header.length);
  return {
    record_header: record_header,
    data: data
  };
}

function P_hash(algo, secret, seed, size) {
  var result = (new Buffer(size)).fill(0);
  var hmac = crypto.createHmac(algo, secret);
  hmac.update(seed);
  var a = hmac.digest(); // A(1)
  var j = 0;
  while(j < size) {
    hmac = crypto.createHmac(algo, secret);
    hmac.update(a);
    hmac.update(seed);
    var b = hmac.digest();
    var todo = b.length;
    if (j + todo > size) {
      todo = size -j;
    }
    b.copy(result, j, 0, todo);
    j += todo;

    hmac = crypto.createHmac(algo, secret);
    hmac.update(a);
    a = hmac.digest(); // A(i+1)
  }

  return result;
}

function PRF12(secret, label, seed, size) {
  var newSeed = Buffer.concat([new Buffer(label), seed]);
  return P_hash('sha256', secret, newSeed, size);
}

function KDF(pre_master_secret, clienthello_json, serverhello_json) {
  var client_random = clienthello_json.random;
  var server_random = serverhello_json.random;
  var master_secret = PRF12(pre_master_secret, "master secret", Buffer.concat([client_random, server_random]), 48);
  var key_block_reader = new DataReader(   // 40bytes key_block for AES-128-GCM
    PRF12(master_secret, "key expansion", Buffer.concat([server_random, client_random]), 40));

  return {
    master_secret: master_secret,
    client_write_MAC_key: null,
    server_write_MAC_key: null,
    client_write_key: key_block_reader.readBytes(16),
    server_write_key: key_block_reader.readBytes(16),
    client_write_IV: key_block_reader.readBytes(4),
    server_write_IV: key_block_reader.readBytes(4)
  };
}

exports.createClientKeyExchange = createClientKeyExchange;
function createClientKeyExchange(json, state) {
  state.handshake.clientkeyexchange_json = json;
  var public_key = json.pubkey;
  var pre_master_secret = json.pre_master_secret;
  var encrypted = crypto.publicEncrypt({
    key: public_key,
    padding: require('constants').RSA_PKCS1_PADDING
  }, pre_master_secret);
  var encrypted_pre_master_secret = writeVector(encrypted, 0, 1 << 16 - 1);
  var handshake = createHandshake(handshake_type.clientkeyexchange, encrypted_pre_master_secret);
  return createRecord(type.handshake, handshake);
};

exports.createChangeCipherSpec = createChangeCipherSpec;
function createChangeCipherSpec() {
  return new Buffer('140303000101', 'hex');
};

exports.createClientFinished = createClientFinished;
function createClientFinished(json, state) {
  state.handshake.clientfinished_json = json;
  var shasum = crypto.createHash('sha256');
  shasum.update(Buffer.concat(json.handshake_message_list));
  var message_hash = shasum.digest();
  var r = PRF12(json.master_secret, "client finished", message_hash, 12);
  var handshake = createHandshake(handshake_type.finished, r);
  return createRecord(type.handshake, handshake);
}

exports.createApplicationData = createApplicationData;
function createApplicationData(data) {
  return createRecord(type.application, data);
}

exports.DecryptAEAD = DecryptAEAD;
function DecryptAEAD(reader, state) {
  if (!checkRecordHeader(reader))
    return null;

  var write_key = state.keyblock_json.server_write_key;
  var write_iv = state.keyblock_json.server_write_IV;

  var record_header_type_version = reader.peekBytes(0, 3);
  var record_header = parseRecordHeader(reader);
  var frame = reader.readBytes(record_header.length);
  var nonce_explicit = frame.slice(0, 8);
  var enc_data = frame.slice(8, frame.length - 16);
  var record_header_length = new Buffer(2);
  record_header_length.writeUInt16BE(enc_data.length);
  var record_header_buf = Buffer.concat([record_header_type_version, record_header_length]);
  var tag = frame.slice(-16);
  var iv = Buffer.concat([write_iv.slice(0,4), nonce_explicit]);
  var bob = crypto.createDecipheriv('aes-128-gcm', write_key, iv);
  bob.setAuthTag(tag);
  var aad = Buffer.concat([state.read_seq, record_header_buf]);
  bob.setAAD(aad);
  var clear = bob.update(enc_data);
  var length = new Buffer(2);
  length.writeUIntBE(clear.length, 0, 2);
  bob.final();
  incSeq(state.read_seq);
  var buf = reader.readBytes(reader.bytesRemaining());
  return new DataReader(Buffer.concat([record_header_type_version, length, clear, buf]));
}

exports.createPreMasterSecretRSAKeyExchange = createPreMasterSecretRSAKeyExchange;
function createPreMasterSecretRSAKeyExchange(state) {
  var pre_master_secret = Buffer.concat([state.handshake.clienthello_json.version, crypto.randomBytes(46)]);
  return pre_master_secret;
}

exports.createKeyBlock = createKeyBlock;
function createKeyBlock(pre_master_secret, state) {
  var keyblock_json = KDF(pre_master_secret, state.handshake.clienthello_json, state.handshake.serverhello_json);
  return keyblock_json;
}

exports.sendClientKeyExchange = sendClientKeyExchange;
function sendClientKeyExchange(state) {
  var pre_master_secret = createPreMasterSecretRSAKeyExchange(state);
  state.keyblock_json = createKeyBlock(pre_master_secret, state);
  var clientkeyexchange_json = {
    pre_master_secret: pre_master_secret,
    pubkey: require('fs').readFileSync(__dirname + '/pubkey.pem')
  };
  var clientkeyexchange = createClientKeyExchange(clientkeyexchange_json, state);
  sendTLSFrame(clientkeyexchange, state);
}

exports.sendChangeCipherSpec = sendChangeCipherSpec;
function sendChangeCipherSpec(state) {
  var changecipherspec = createChangeCipherSpec();
  sendTLSFrame(changecipherspec, state);
  state.send_encrypted = true;
}

exports.sendClientFinished = sendClientFinished;
function sendClientFinished(state) {
  var clientfinished_json = {
    master_secret: state.keyblock_json.master_secret,
    handshake_message_list: state.handshake_message_list
  };
  var clientfinished = createClientFinished(clientfinished_json, state);
  sendTLSFrame(clientfinished, state);
}

exports.sendClientFrame = sendClientFrame;
function sendClientFrame(state) {
  sendClientKeyExchange(state);
  sendChangeCipherSpec(state);
  state.send_encrypted = true;
  sendClientFinished(state);
}

exports.sendTLSFrame = sendTLSFrame;
function sendTLSFrame(frame, state) {
  if (frame[0] === type.handshake)
    state.handshake_message_list.push(frame.slice(5));

  if (state.send_encrypted)
    frame = EncryptAEAD(frame, state);

  state.socket.write(frame);
}

exports.EncryptAEAD = EncryptAEAD;
function EncryptAEAD(frame, state) {
  var iv = Buffer.concat([state.keyblock_json.client_write_IV.slice(0,4), state.nonce_explicit]);
  var bob = crypto.createCipheriv('aes-128-gcm', state.keyblock_json.client_write_key, iv);
  var record_header = frame.slice(0, 5);
  var aad = Buffer.concat([state.write_seq, record_header]);
  bob.setAAD(aad);
  var encrypted1 = bob.update(frame.slice(5));
  var encrypted2 = bob.final();
  var encrypted = Buffer.concat([encrypted1, encrypted2]);
  var tag = bob.getAuthTag(tag);
  incSeq(state.write_seq);
  record_header.writeUIntBE(state.nonce_explicit.length + encrypted.length + tag.length, 3, 2);
  return Buffer.concat([record_header, state.nonce_explicit, encrypted, tag]);
}
<|endoftext|>


<commit_before>var urbanpotato = function(value) {
  var Nothing = {
    bind: function(fn) {
      return this;
    },
    isNothing: function() {
      return true;
    },
    val: function() {
      throw new Error("cannot call val() nothing");
    },
    maybe: function(def, fn) {
      return def;
    }
  };

  var Something = function(value) {
    return {
      bind: function(fn) {
        return Maybe(fn.call(this, value));
      },
      isNothing: function() {
        return false;
      },
      val: function() {
        return value;
      },
      maybe: function(def, fn) {
        return fn.call(this, value);
      }
    };
  };

  if (typeof value === 'undefined' ||
      value === null ||
      (typeof value.isNothing !== 'undefined' && value.isNothing()))
  {
    return Nothing;
  }

  return Something(value);
};

var isNothing = function() {
  var self = this;
  return self.length == 0;
};

//@todo check if this method is added in Node Array Property
if (!Array.prototype.isNothing)
   Object.defineProperty(Array.prototype, 'isNothing', { value: isNothing });

module.exports = urbanpotato;
<commit_msg>update methodanme<commit_after>var urbanpotato = function(value) {
  var Nothing = {
    bind: function(fn) {
      return this;
    },
    isNothing: function() {
      return true;
    },
    val: function() {
      throw new Error("cannot call val() nothing");
    },
    maybe: function(def, fn) {
      return def;
    }
  };

  var Something = function(value) {
    return {
      bind: function(fn) {
        return urbanpotato(fn.call(this, value));
      },
      isNothing: function() {
        return false;
      },
      val: function() {
        return value;
      },
      maybe: function(def, fn) {
        return fn.call(this, value);
      }
    };
  };

  if (typeof value === 'undefined' ||
      value === null ||
      (typeof value.isNothing !== 'undefined' && value.isNothing()))
  {
    return Nothing;
  }

  return Something(value);
};

var isNothing = function() {
  var self = this;
  return self.length == 0;
};

//@todo check if this method is added in Node Array Property
if (!Array.prototype.isNothing)
   Object.defineProperty(Array.prototype, 'isNothing', { value: isNothing });

module.exports = urbanpotato;
<|endoftext|>


<commit_before>const r = require('rethinkdb');
const io = require('socket.io')();
const fetch = require('node-fetch');

function subscribeToClassroomLessonSession({
  connection,
  client,
  classroomLessonSessionId
}) {
  r.table('classroom_lesson_sessions')
  .get(classroomLessonSessionId)
  .run(connection)
  .then((classroomLessonSession) => {
    client.emit(`classroomLessonSession:${classroomLessonSessionId}`,classroomLessonSession);
  });
}

function createPreviewSession({ connection, previewSessionData }) {
  r.table('classroom_lesson_sessions')
  .insert(previewSessionData)
  .run(connection)
}

function subscribeToCurrentSlide({
  connection,
  client,
  classroomActivityId
}) {
  r.table('classroom_lesson_sessions')
  .get(classroomActivityId)
  .getField('current_slide')
  .run(connection)
  .then((currentSlide) => {
    client.emit(`currentSlide:${classroomActivityId}`, currentSlide)
  });
}

function updateClassroomLessonSession({ connection, session }) {
  r.table('classroom_lesson_sessions')
  .insert(session, { conflict: 'update' })
  .run(connection);
}

function createOrUpdateClassroomLessonSession({
  connection,
  classroomActivityId
}) {
  const url = process.env.EMPIRICAL_BASE_URL +
    '/api/v1/classroom_activities/' +
    classroomActivityId +
    '/classroom_teacher_and_coteacher_ids'

  r.table('classroom_lesson_sessions')
  .get(classroomActivityId)
  .run(connection)
  .then((session) => {
    fetch(url, {
      method: "GET",
      mode: "cors",
      credentials: 'include',
    }).then(response => {
      if (!response.ok) {
        console.log(response.statusText)
      } else {
        return response.json()
      }
    }).then(response => {
      response ? session.teacher_ids = response.teacher_ids : undefined;
      session.current_slide = session && session.current_slide ? session.current_slide : 0;
      session.startTime = session && session.startTime ? session.startTime : new Date();
      session.id = session && session.id ? session.id : classroomActivityId;

      r.table('classroom_lesson_sessions')
      .insert(session, { conflict: 'replace' })
      .run(connection)
    });
  });
}

r.connect({
  host: 'localhost',
  port: 28015,
  db: 'quill_lessons'
}).then((connection) => {
  io.on('connection', (client) => {
    client.on('teacherConnect', (classroomActivityId) => {

    });

    client.on('disconnect', )

    client.on('subscribeToClassroomLessonSession', (classroomLessonSessionId) => {
      subscribeToClassroomLessonSession({
        connection,
        client,
        classroomLessonSessionId,
      });
    });

    client.on('createPreviewSession', (previewSessionData) => {
      createPreviewSession({
        connection,
        previewSessionData
      });
    });

    client.on('subscribeToCurrentSlide', (classroomActivityId) => {
      subscribeToCurrentSlide({
        connection,
        client,
        classroomActivityId
      });
    });

    client.on('updateClassroomLessonSession', (session) => {
      updateClassroomLessonSession({
        session,
        connection
      });
    });

    client.on('createOrUpdateClassroomLessonSession', (classroomActivityId) => {
      createOrUpdateClassroomLessonSession({
        connection,
        classroomActivityId
      });
    });
  });
});

io.listen(8000);
console.log('listening on port ', 8000);
<commit_msg>Persist teacher connection status in realtime db<commit_after>const r = require('rethinkdb');
const io = require('socket.io')();
const fetch = require('node-fetch');

let currentConnections = {};

function subscribeToClassroomLessonSession({
  connection,
  client,
  classroomLessonSessionId
}) {
  r.table('classroom_lesson_sessions')
  .get(classroomLessonSessionId)
  .run(connection)
  .then((classroomLessonSession) => {
    client.emit(`classroomLessonSession:${classroomLessonSessionId}`,classroomLessonSession);
  });
}

function createPreviewSession({ connection, previewSessionData }) {
  r.table('classroom_lesson_sessions')
  .insert(previewSessionData)
  .run(connection)
}

function subscribeToCurrentSlide({
  connection,
  client,
  classroomActivityId
}) {
  r.table('classroom_lesson_sessions')
  .get(classroomActivityId)
  .getField('current_slide')
  .run(connection)
  .then((currentSlide) => {
    client.emit(`currentSlide:${classroomActivityId}`, currentSlide)
  });
}

function updateClassroomLessonSession({ connection, session }) {
  r.table('classroom_lesson_sessions')
  .insert(session, { conflict: 'update' })
  .run(connection);
}

function createOrUpdateClassroomLessonSession({
  connection,
  classroomActivityId
}) {
  const url = process.env.EMPIRICAL_BASE_URL +
    '/api/v1/classroom_activities/' +
    classroomActivityId +
    '/classroom_teacher_and_coteacher_ids'

  r.table('classroom_lesson_sessions')
  .get(classroomActivityId)
  .run(connection)
  .then((session) => {
    fetch(url, {
      method: "GET",
      mode: "cors",
      credentials: 'include',
    }).then(response => {
      if (!response.ok) {
        console.log(response.statusText)
      } else {
        return response.json()
      }
    }).then(response => {
      response ? session.teacher_ids = response.teacher_ids : undefined;
      session.current_slide = session && session.current_slide ? session.current_slide : 0;
      session.startTime = session && session.startTime ? session.startTime : new Date();
      session.id = session && session.id ? session.id : classroomActivityId;

      r.table('classroom_lesson_sessions')
      .insert(session, { conflict: 'replace' })
      .run(connection)
    });
  });
}

function teacherConnected({
  classroomActivityId,
  connection,
  client,
}) {
  let session = { id: classroomActivityId, absentTeacherState: false };
  currentConnections[client.id].role = 'teacher';
  currentConnections[client.id].classroomActivityId = classroomActivityId;

  updateClassroomLessonSession({
    connection,
    session,
  });
}

function disconnect({
  client,
  connection,
}) {
  if (currentConnections[client.id].role === 'teacher') {
    let session = {
      id: currentConnections[client.id].classroomActivityId,
      absentTeacherState: true
    };

    updateClassroomLessonSession({
      connection,
      session,
    });
  }
  delete currentConnections[client.id];
}

r.connect({
  host: 'localhost',
  port: 28015,
  db: 'quill_lessons'
}).then((connection) => {
  io.on('connection', (client) => {
    currentConnections[client.id] = { socket: client, role: null };

    client.on('teacherConnected', (classroomActivityId) => {
      teacherConnected({
        connection,
        classroomActivityId,
        client,
      })
    });

    client.on('disconnect', () => {
      disconnect({
        client,
        connection,
      })
    });

    client.on('subscribeToClassroomLessonSession', (classroomLessonSessionId) => {
      subscribeToClassroomLessonSession({
        connection,
        client,
        classroomLessonSessionId,
      });
    });

    client.on('createPreviewSession', (previewSessionData) => {
      createPreviewSession({
        connection,
        previewSessionData
      });
    });

    client.on('subscribeToCurrentSlide', (classroomActivityId) => {
      subscribeToCurrentSlide({
        connection,
        client,
        classroomActivityId
      });
    });

    client.on('updateClassroomLessonSession', (session) => {
      updateClassroomLessonSession({
        session,
        connection
      });
    });

    client.on('createOrUpdateClassroomLessonSession', (classroomActivityId) => {
      createOrUpdateClassroomLessonSession({
        connection,
        classroomActivityId
      });
    });
  });
});

io.listen(8000);
console.log('listening on port ', 8000);
<|endoftext|>