<commit_before>/* jshint node: true */
'use strict';

var VersionChecker = require('ember-cli-version-checker');
var clone     = require('clone');
var path      = require('path');
var resolve   = require('resolve');

module.exports = {
  name: 'ember-cli-babel',
  configKey: 'ember-cli-babel',

  init: function() {
    this._super.init && this._super.init.apply(this, arguments);

    var checker = new VersionChecker(this);
    var dep = checker.for('ember-cli', 'npm');

    this._shouldSetupRegistryInIncluded = !dep.satisfies('>=0.2.0');
  },

  setupPreprocessorRegistry: function(type, registry) {
    var addon = this;

    registry.add('js', {
      name: 'ember-cli-babel',
      ext: 'js',
      toTree: function(tree) {
        return require('broccoli-babel-transpiler')(tree, getBabelOptions(addon));
      }
    });
  },

  shouldIncludePolyfill: function() {
    var addonOptions = getAddonOptions(this);
    var babelOptions = addonOptions.babel;
    var customOptions = addonOptions['ember-cli-babel'];

    if (customOptions && 'includePolyfill' in customOptions) {
      return customOptions.includePolyfill === true;
    } else if (babelOptions && 'includePolyfill' in babelOptions) {
      return babelOptions.includePolyfill === true;
    } else {
      return false;
    }
  },

  importPolyfill: function(app) {
    if (this.import) {  // support for ember-cli >= 2.7
      this.import('vendor/browser-polyfill.js', { prepend: true });
    } else if (app.import) { // support ember-cli < 2.7
      app.import('vendor/browser-polyfill.js', { prepend: true });
    } else {
      console.warn('Please run: ember install ember-cli-import-polyfill')
    }
  },

  treeFor: function(name) {
    if (name !== 'vendor') { return; }
    if (!this.shouldIncludePolyfill()) { return; }

    // Find babel-core's browser polyfill and use its directory as our vendor tree
    var transpilerRoot = path.dirname(resolve.sync('broccoli-babel-transpiler'));
    var polyfillDir = path.dirname(resolve.sync('babel-core/browser-polyfill', { basedir: transpilerRoot }));
    var Funnel = require('broccoli-funnel');
    return new Funnel(polyfillDir, {
      files: ['browser-polyfill.js']
    });
  },

  included: function(app) {
    this._super.included.apply(this, arguments);
    this.app = app;

    if (this._shouldSetupRegistryInIncluded) {
      this.setupPreprocessorRegistry('parent', app.registry);
    }

    if (this.shouldIncludePolyfill()) {
      this.importPolyfill(app);
    }
  }
};

function getAddonOptions(addonContext) {
  return (addonContext.parent && addonContext.parent.options) || (addonContext.app && addonContext.app.options) || {};
}

function getBabelOptions(addonContext) {
  var addonOptions = getAddonOptions(addonContext);
  var options = clone(addonOptions.babel || {});
  var customOptions = addonOptions['ember-cli-babel'];

  var compileModules;
  if (customOptions && 'compileModules' in customOptions) {
    compileModules = customOptions.compileModules === true;
  } else if ('compileModules' in options) {
    compileModules = options.compileModules === true;
  } else {
    compileModules = false;
  }

  var ui = addonContext.ui;

  // pass a console object that wraps the addon's `UI` object
  options.console = {
    log: function(message) {
      // fallback needed for support of ember-cli < 2.2.0
      if (ui.writeInfoLine) {
        ui.writeInfoLine(message);
      } else {
        ui.writeLine(message, 'INFO');
      }
    },

    warn: function(message) {
      // fallback needed for support of ember-cli < 2.2.0
      if (ui.writeWarnLine) {
        ui.writeWarnLine(message);
      } else {
        ui.writeLine(message, 'WARN');
      }
    },

    error: function(message) {
      // fallback needed for support of ember-cli < 2.2.0
      if (ui.writeError) {
        ui.writeError(message);
      } else {
        ui.writeLine(message, 'ERROR');
      }
    }
  };

  // Ensure modules aren't compiled unless explicitly set to compile
  options.blacklist = options.blacklist || ['es6.modules'];

  // do not enable non-standard transforms
  if (!('nonStandard' in options)) {
    options.nonStandard = false;
  }

  // Remove custom options from `options` hash that is passed to Babel
  delete options.includePolyfill;
  delete options.compileModules;

  if (compileModules) {
    if (options.blacklist.indexOf('es6.modules') >= 0) {
      options.blacklist.splice(options.blacklist.indexOf('es6.modules'), 1);
    }
  } else {
    if (options.blacklist.indexOf('es6.modules') < 0) {
      options.blacklist.push('es6.modules');
    }
  }

  // Ember-CLI inserts its own 'use strict' directive
  options.blacklist.push('useStrict');
  options.highlightCode = false;

  return options;
}
<commit_msg>Move getAddonOptions/getBabelOptions() functions into the "class"<commit_after>/* jshint node: true */
'use strict';

var VersionChecker = require('ember-cli-version-checker');
var clone     = require('clone');
var path      = require('path');
var resolve   = require('resolve');

module.exports = {
  name: 'ember-cli-babel',
  configKey: 'ember-cli-babel',

  init: function() {
    this._super.init && this._super.init.apply(this, arguments);

    var checker = new VersionChecker(this);
    var dep = checker.for('ember-cli', 'npm');

    this._shouldSetupRegistryInIncluded = !dep.satisfies('>=0.2.0');
  },

  setupPreprocessorRegistry: function(type, registry) {
    var addon = this;

    registry.add('js', {
      name: 'ember-cli-babel',
      ext: 'js',
      toTree: function(tree) {
        return require('broccoli-babel-transpiler')(tree, addon._getBabelOptions());
      }
    });
  },

  shouldIncludePolyfill: function() {
    var addonOptions = this._getAddonOptions();
    var babelOptions = addonOptions.babel;
    var customOptions = addonOptions['ember-cli-babel'];

    if (customOptions && 'includePolyfill' in customOptions) {
      return customOptions.includePolyfill === true;
    } else if (babelOptions && 'includePolyfill' in babelOptions) {
      return babelOptions.includePolyfill === true;
    } else {
      return false;
    }
  },

  importPolyfill: function(app) {
    if (this.import) {  // support for ember-cli >= 2.7
      this.import('vendor/browser-polyfill.js', { prepend: true });
    } else if (app.import) { // support ember-cli < 2.7
      app.import('vendor/browser-polyfill.js', { prepend: true });
    } else {
      console.warn('Please run: ember install ember-cli-import-polyfill')
    }
  },

  treeFor: function(name) {
    if (name !== 'vendor') { return; }
    if (!this.shouldIncludePolyfill()) { return; }

    // Find babel-core's browser polyfill and use its directory as our vendor tree
    var transpilerRoot = path.dirname(resolve.sync('broccoli-babel-transpiler'));
    var polyfillDir = path.dirname(resolve.sync('babel-core/browser-polyfill', { basedir: transpilerRoot }));
    var Funnel = require('broccoli-funnel');
    return new Funnel(polyfillDir, {
      files: ['browser-polyfill.js']
    });
  },

  included: function(app) {
    this._super.included.apply(this, arguments);
    this.app = app;

    if (this._shouldSetupRegistryInIncluded) {
      this.setupPreprocessorRegistry('parent', app.registry);
    }

    if (this.shouldIncludePolyfill()) {
      this.importPolyfill(app);
    }
  },

  _getAddonOptions: function() {
    return (this.parent && this.parent.options) || (this.app && this.app.options) || {};
  },

  _getBabelOptions: function() {
    var addonOptions = this._getAddonOptions();
    var options = clone(addonOptions.babel || {});
    var customOptions = addonOptions['ember-cli-babel'];

    var compileModules;
    if (customOptions && 'compileModules' in customOptions) {
      compileModules = customOptions.compileModules === true;
    } else if ('compileModules' in options) {
      compileModules = options.compileModules === true;
    } else {
      compileModules = false;
    }

    var ui = this.ui;

    // pass a console object that wraps the addon's `UI` object
    options.console = {
      log: function(message) {
        // fallback needed for support of ember-cli < 2.2.0
        if (ui.writeInfoLine) {
          ui.writeInfoLine(message);
        } else {
          ui.writeLine(message, 'INFO');
        }
      },

      warn: function(message) {
        // fallback needed for support of ember-cli < 2.2.0
        if (ui.writeWarnLine) {
          ui.writeWarnLine(message);
        } else {
          ui.writeLine(message, 'WARN');
        }
      },

      error: function(message) {
        // fallback needed for support of ember-cli < 2.2.0
        if (ui.writeError) {
          ui.writeError(message);
        } else {
          ui.writeLine(message, 'ERROR');
        }
      }
    };

    // Ensure modules aren't compiled unless explicitly set to compile
    options.blacklist = options.blacklist || ['es6.modules'];

    // do not enable non-standard transforms
    if (!('nonStandard' in options)) {
      options.nonStandard = false;
    }

    // Remove custom options from `options` hash that is passed to Babel
    delete options.includePolyfill;
    delete options.compileModules;

    if (compileModules) {
      if (options.blacklist.indexOf('es6.modules') >= 0) {
        options.blacklist.splice(options.blacklist.indexOf('es6.modules'), 1);
      }
    } else {
      if (options.blacklist.indexOf('es6.modules') < 0) {
        options.blacklist.push('es6.modules');
      }
    }

    // Ember-CLI inserts its own 'use strict' directive
    options.blacklist.push('useStrict');
    options.highlightCode = false;

    return options;
  },
};
<|endoftext|>


<commit_before>/* jshint node: true */
'use strict';

module.exports = {
  name: 'ember-cli-content-for-demo',

  contentFor: function(type, config){
    if (type === 'head'){
      console.log('CONFIG = ' + config);
      return '<link href="http://cdnjs.head.css" rel="stylesheet" type="text/css" />';

    } else if (type === 'head-footer'){

      return '<link href="http://cdnjs.head-footer.css" rel="stylesheet" type="text/css" />';

    } else if (type === 'body'){

      return '
this is body content-for content';

    } else if (type === 'body-footer'){

      return 'footer content (such as copyright, etc) goes here';

    }
  }
};
<commit_msg>no msg nec<commit_after>/* jshint node: true */
'use strict';

module.exports = {
  name: 'ember-cli-content-for-demo',

  contentFor: function(type, config){
    debugger;
    if (type === 'head'){
      console.log('CONFIG = ' + config);

      return '<link href="http://cdnjs.head.css" rel="stylesheet" type="text/css" />';

    } else if (type === 'head-footer'){

      return '<link href="http://cdnjs.head-footer.css" rel="stylesheet" type="text/css" />';

    } else if (type === 'body'){

      return '
this is body content-for content';

    } else if (type === 'body-footer'){

      return 'footer content (such as copyright, etc) goes here';

    }
  }
};
<|endoftext|>


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

var fondue = require("fondue");
var crypto = require("crypto");

var cache = {}; // digest -> string

function mergeInto(options, defaultOptions) {
	for (var key in options) {
		if (options[key] !== undefined) {
			defaultOptions[key] = options[key];
		}
	}
	return defaultOptions;
}

function instrument(src, fondueOptions) {
	var md5 = crypto.createHash("md5");
	md5.update(JSON.stringify(fondueOptions) + "||" + src);
	var digest = md5.digest("hex");
	if (digest in cache) {
	    return cache[digest];
	} else {
		console.log("instrumenting", fondueOptions.path);
	    return cache[digest] = fondue.instrument(src, fondueOptions);
	}
}

function processJavaScript(src, fondueOptions) {
	return instrument(src, fondueOptions);
}

function processHTML(src, fondueOptions) {
	var scriptLocs = [];
	var scriptBeginRegexp = /<\s*script[^>]*>/ig;
	var scriptEndRegexp = /<\s*\/\s*script/i;
	var lastScriptEnd = 0;

	var match;
	while (match = scriptBeginRegexp.exec(src)) {
		var scriptBegin = match.index + match[0].length;
		if (scriptBegin < lastScriptEnd) {
			continue;
		}
		var endMatch = scriptEndRegexp.exec(src.slice(scriptBegin));
		if (endMatch) {
			var scriptEnd = scriptBegin + endMatch.index;
			scriptLocs.push({ start: scriptBegin, end: scriptEnd });
			lastScriptEnd = scriptEnd;
		}
	}

	// process the scripts in reverse order
	for (var i = scriptLocs.length - 1; i >= 0; i--) {
		var loc = scriptLocs[i];
		var script = src.slice(loc.start, loc.end);
		var prefix = src.slice(0, loc.start).replace(/[^\n]/g, " "); // padding it out so line numbers make sense
		src = src.slice(0, loc.start) + instrument(prefix + script, fondueOptions) + src.slice(loc.end);
	}

	src = "<script>\n" + fondue.instrumentationPrefix(fondueOptions) + "\n</script>\n" + src;

	return src;
}

module.exports = function (options) {
	options = options || {};

	return function(req, res, next){
		var written = [];
		var write = res.write, end = res.end;

		res.header("Cache-Control", "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0");

		res.write = function(chunk) {
			written.push(chunk);
		};

		res.end = function(chunk) {
			if (chunk) this.write.apply(this, arguments);

			var type = res.getHeader("Content-Type");
			var fondueOptions = mergeInto(options, { path: req.url, include_prefix: false });

			if (/application\/javascript/.test(type)) {
				var src = Buffer.concat(written).toString();
				src = processJavaScript(src, fondueOptions);
				written = [src];
				res.removeHeader("Content-Length");
			} else if (/text\/html/.test(type)) {
				var src = Buffer.concat(written).toString();
				src = processHTML(src, fondueOptions);
				written = [src];
				res.removeHeader("Content-Length");
			}

			written.forEach(function (c) {
				write.call(res, c)
			});

			return end.call(res);
		};

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

var fondue = require("fondue");
var crypto = require("crypto");

var cache = {}; // digest -> string

function mergeInto(options, defaultOptions) {
	for (var key in options) {
		if (options[key] !== undefined) {
			defaultOptions[key] = options[key];
		}
	}
	return defaultOptions;
}

function instrument(src, fondueOptions) {
	var md5 = crypto.createHash("md5");
	md5.update(JSON.stringify(fondueOptions) + "||" + src);
	var digest = md5.digest("hex");
	if (digest in cache) {
	    return cache[digest];
	} else {
		console.log("instrumenting", fondueOptions.path);
	    return cache[digest] = fondue.instrument(src, fondueOptions);
	}
}

function processJavaScript(src, fondueOptions) {
	return instrument(src, fondueOptions);
}

function processHTML(src, fondueOptions) {
	var scriptLocs = [];
	var scriptBeginRegexp = /<\s*script[^>]*>/ig;
	var scriptEndRegexp = /<\s*\/\s*script/i;
	var lastScriptEnd = 0;

	var match;
	while (match = scriptBeginRegexp.exec(src)) {
		var scriptBegin = match.index + match[0].length;
		if (scriptBegin < lastScriptEnd) {
			continue;
		}
		var endMatch = scriptEndRegexp.exec(src.slice(scriptBegin));
		if (endMatch) {
			var scriptEnd = scriptBegin + endMatch.index;
			scriptLocs.push({ start: scriptBegin, end: scriptEnd });
			lastScriptEnd = scriptEnd;
		}
	}

	// process the scripts in reverse order
	for (var i = scriptLocs.length - 1; i >= 0; i--) {
		var loc = scriptLocs[i];
		var script = src.slice(loc.start, loc.end);
		var prefix = src.slice(0, loc.start).replace(/[^\n]/g, " "); // padding it out so line numbers make sense
		src = src.slice(0, loc.start) + instrument(prefix + script, fondueOptions) + src.slice(loc.end);
	}

	src = "<script>\n" + fondue.instrumentationPrefix(fondueOptions) + "\n</script>\n" + src;

	return src;
}

module.exports = function (options) {
	options = options || {};

	return function(req, res, next){
		var written = [];
		var write = res.write, end = res.end;

		res.header("Cache-Control", "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0");

		res.write = function(chunk) {
			written.push(chunk);
		};

		res.end = function(chunk) {
			if (chunk) this.write.apply(this, arguments);

			var type = res.getHeader("Content-Type");
			var fondueOptions = mergeInto(options, { path: unescape(req.url), include_prefix: false });

			if (/application\/javascript/.test(type)) {
				var src = Buffer.concat(written).toString();
				src = processJavaScript(src, fondueOptions);
				written = [src];
				res.removeHeader("Content-Length");
			} else if (/text\/html/.test(type)) {
				var src = Buffer.concat(written).toString();
				src = processHTML(src, fondueOptions);
				written = [src];
				res.removeHeader("Content-Length");
			}

			written.forEach(function (c) {
				write.call(res, c)
			});

			return end.call(res);
		};

		next();
	};
};
<|endoftext|>


<commit_before>'use strict';

// 1. npm install body-parser express request
// 2. Download and install ngrok from https://ngrok.com/download
// 3. ./ngrok http 8445
// 4. WIT_TOKEN=your_access_token FB_PAGE_ID=your_page_id FB_PAGE_TOKEN=your_page_token FB_VERIFY_TOKEN=verify_token node examples/messenger.js
// 5. Subscribe your page to the Webhooks using verify_token and `https://<your_ngrok_io>/fb` as callback URL.
// 6. Talk to your bot on Messenger!

const bodyParser = require('body-parser');
const express = require('express');
const request = require('request');
const Wit = require('node-wit').Wit;
const _ = require('underscore');

// Webserver parameter
const PORT = process.env.PORT || 8445;

// Wit.ai parameters
const WIT_TOKEN = process.env.WIT_TOKEN;

// Messenger API parameters
const FB_PAGE_ID = process.env.FB_PAGE_ID;
if (!FB_PAGE_ID) {
  throw new Error('missing FB_PAGE_ID');
}
const FB_PAGE_TOKEN = process.env.FB_PAGE_TOKEN;
if (!FB_PAGE_TOKEN) {
  throw new Error('missing FB_PAGE_TOKEN');
}
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;

const FORECAST_TOKEN = process.env.FORECAST_TOKEN;

// Messenger API specific code

// See the Send API reference
// https://developers.facebook.com/docs/messenger-platform/send-api-reference
const fbReq = request.defaults({
  uri: 'https://graph.facebook.com/me/messages',
  method: 'POST',
  json: true,
  qs: { access_token: FB_PAGE_TOKEN },
  headers: {'Content-Type': 'application/json'},
});

const fbMessage = (recipientId, msg, cb) => {
  const opts = {
    form: {
      recipient: {
        id: recipientId,
      },
      message: {
        text: msg,
      },
    },
  };
  fbReq(opts, (err, resp, data) => {
    if (cb) {
      cb(err || data.error && data.error.message, data);
    }
  });
};

// See the Webhook reference
// https://developers.facebook.com/docs/messenger-platform/webhook-reference
const getFirstMessagingEntry = (body) => {
  const val = body.object == 'page' &&
    body.entry &&
    Array.isArray(body.entry) &&
    body.entry.length > 0 &&
    body.entry[0] &&
    body.entry[0].id === FB_PAGE_ID &&
    body.entry[0].messaging &&
    Array.isArray(body.entry[0].messaging) &&
    body.entry[0].messaging.length > 0 &&
    body.entry[0].messaging[0]
  ;
  return val || null;
};

// Wit.ai bot specific code

// This will contain all user sessions.
// Each session has an entry:
// sessionId -> {fbid: facebookUserId, context: sessionState}
const sessions = {};

const findOrCreateSession = (fbid) => {
  let sessionId;
  // Let's see if we already have a session for the user fbid
  Object.keys(sessions).forEach(k => {
    if (sessions[k].fbid === fbid) {
      // Yep, got it!
      sessionId = k;
    }
  });
  if (!sessionId) {
    // No session found for user fbid, let's create a new one
    sessionId = new Date().toISOString();
    sessions[sessionId] = {fbid: fbid, context: {}};
  }
  return sessionId;
};

const firstEntityValue = (entities, entity) => {
  const val = entities && entities[entity] &&
    Array.isArray(entities[entity]) &&
    entities[entity].length > 0 &&
    entities[entity][0].value
  ;
  if (!val) {
    return null;
  }
  return typeof val === 'object' ? val.value : val;
};

// Our bot actions
const actions = {
  say(sessionId, context, message, cb) {
    // Our bot has something to say!
    // Let's retrieve the Facebook user whose session belongs to
    const recipientId = sessions[sessionId].fbid;
    if (recipientId) {
      // Yay, we found our recipient!
      // Let's forward our bot response to her.
      if (message.length >= 320)
      {
        var first_msg = message.substring(0, 319);
        fbMessage(recipientId, first_msg, (err, data) => {
          if (err) {
            console.log(
              'Oops! An error occurred while forwarding the response to',
              recipientId,
              ':',
              err
            );
          }
          var rest_msg = message.substring(320);
          fbMessage(recipientId, rest_msg, (err, data) => {
            if (err) {
              console.log(
                'Oops! An error occurred while forwarding the response to',
                recipientId,
                ':',
                err
              );
            }

            // Let's give the wheel back to our bot
            cb();
          });
        });
      }
      else{
        fbMessage(recipientId, message, (err, data) => {
          if (err) {
            console.log(
              'Oops! An error occurred while forwarding the response to',
              recipientId,
              ':',
              err
            );
          }

          // Let's give the wheel back to our bot
          cb();
        });
      }
    } else {
      console.log('Oops! Couldn\'t find user for session:', sessionId);
      // Giving the wheel back to our bot
      cb();
    }
  },
  merge(sessionId, context, entities, message, cb) {
    // Retrieve the location entity and store it into a context field
    const beerStyle = firstEntityValue(entities, 'beer_style');
    if (beerStyle) {
      context.beerStyle = beerStyle;
    }

    const beerName = firstEntityValue(entities, 'beer_name');
    if (beerName) {
      context.beerName = beerName;
    }

    const loc = firstEntityValue(entities, 'location');
    if (loc) {
      context.loc = loc;
    }

    cb(context);
  },
  error(sessionId, context, error) {
    console.log(error.message);
  },
  ['getStyle'](sessionId, context, cb) {
    request('http://apis.mondorobot.com/beer-filters', function (error, response, body) {
      var attributeList = JSON.parse(body).beer_filters;
      var styleAndStyleType = {};
      _.map(attributeList, function(val, key) {
        _.each(val, function(hash) {
          styleAndStyleType[hash.name] = key;
        });
      });
      var styleType = styleAndStyleType[context.beerStyle];
      var queryString = styleType + "=" + context.beerStyle;

      request('http://apis.mondorobot.com/beers?' + queryString, function (error, response, body) {
        var parsedBody = JSON.parse(body);
        var beersArray = _.map(parsedBody.beers, function(beer) {
          return beer.name;
        });

        var beerNamesAndIds = {}
        _.each(parsedBody.beers, function(beer) {
          beerNamesAndIds[beer.name] = beer.id;
        });
        context.beerNamesAndIds = beerNamesAndIds;
        var beersString = beersArray.join(", ");
        context.beers = beersString;

        cb(context);
      });
    });
  },
  ['getBeerInfo'](sessionId, context, cb) {
    var queryString = context.beerNamesAndIds[context.beerName.replace("'", "\\'")];
    request('http://apis.mondorobot.com/beers/' + queryString, function (error, response, body) {
      console.log(context.beerName.replace("'", "\\'"));
      console.log(context.beerNamesAndIds);
      console.log(context.beerNamesAndIds[context.beerName]);
      var parsedBody = JSON.parse(body);
      console.log(parsedBody);
      context.description = parsedBody.beer.name + ' is a ' + parsedBody.beer.style + ' with '+ parsedBody.beer.abv + '% ABV';
      cb(context);
    });
  },
  ['getOnTap'](sessionId, context, cb) {
    request('http://apis.mondorobot.com/taproom/on-tap', function (error, response, body) {
      var parsedBody = JSON.parse(body);
      var beersArray = _.map(parsedBody.beer_list.beers, function(beer) {
        return beer.name;
      });
      var beersString = beersArray.join(", ");
      context.beers = beersString;

      cb(context);
    });
  },
  ['getWeather'](sessionId, context, cb) {
    request('https://api.forecast.io/forecast/'+FORECAST_TOKEN+'/40.0626984,-105.2047749', function (error, response, body) {
      var parsedBody = JSON.parse(body);
      context.forecast = parsedBody.minutely.summary;

      cb(context);
    });
  },
  ['getEvents'](sessionId, context, cb) {

  },
  ['beerFinder'](sessionId, context, cb) {

  }
};

// Setting up our bot
const wit = new Wit(WIT_TOKEN, actions);

// Starting our webserver and putting it all together
const app = express();
app.set('port', PORT);
app.listen(app.get('port'));
app.use(bodyParser.json());

// Webhook setup
app.get('/fb', (req, res) => {
  if (!FB_VERIFY_TOKEN) {
    throw new Error('missing FB_VERIFY_TOKEN');
  }
  if (req.query['hub.mode'] === 'subscribe' &&
    req.query['hub.verify_token'] === FB_VERIFY_TOKEN) {
    res.send(req.query['hub.challenge']);
  } else {
    res.sendStatus(400);
  }
});

// Message handler
app.post('/fb', (req, res) => {
  // Parsing the Messenger API response
  const messaging = getFirstMessagingEntry(req.body);
  if (messaging && messaging.message && messaging.recipient.id === FB_PAGE_ID) {
    // Yay! We got a new message!

    // We retrieve the Facebook user ID of the sender
    const sender = messaging.sender.id;

    // We retrieve the user's current session, or create one if it doesn't exist
    // This is needed for our bot to figure out the conversation history
    const sessionId = findOrCreateSession(sender);

    // We retrieve the message content
    const msg = messaging.message.text;
    const atts = messaging.message.attachments;

    if (atts) {
      // We received an attachment

      // Let's reply with an automatic message
      fbMessage(
        sender,
        'Sorry I can only process text messages for now.'
      );
    } else if (msg) {
      // We received a text message

      // Let's forward the message to the Wit.ai Bot Engine
      // This will run all actions until our bot has nothing left to do
      wit.runActions(
        sessionId, // the user's current session
        msg, // the user's message
        sessions[sessionId].context, // the user's current session state
        (error, context) => {
          if (error) {
            console.log('Oops! Got an error from Wit:', error);
          } else {
            // Our bot did everything it has to do.
            // Now it's waiting for further messages to proceed.
            console.log('Waiting for futher messages.');

            // Based on the session state, you might want to reset the session.
            // This depends heavily on the business logic of your bot.
            // Example:
            // if (context['done']) {
            //   delete sessions[sessionId];
            // }

            // Updating the user's current session state
            sessions[sessionId].context = context;
          }
        }
      );
    }
  }
  res.sendStatus(200);
});
<commit_msg>Progress on getEvents. To Do: sort by date and remove old ones, also post dates?<commit_after>'use strict';

// 1. npm install body-parser express request
// 2. Download and install ngrok from https://ngrok.com/download
// 3. ./ngrok http 8445
// 4. WIT_TOKEN=your_access_token FB_PAGE_ID=your_page_id FB_PAGE_TOKEN=your_page_token FB_VERIFY_TOKEN=verify_token node examples/messenger.js
// 5. Subscribe your page to the Webhooks using verify_token and `https://<your_ngrok_io>/fb` as callback URL.
// 6. Talk to your bot on Messenger!

const bodyParser = require('body-parser');
const express = require('express');
const request = require('request');
const Wit = require('node-wit').Wit;
const _ = require('underscore');

// Webserver parameter
const PORT = process.env.PORT || 8445;

// Wit.ai parameters
const WIT_TOKEN = process.env.WIT_TOKEN;

// Messenger API parameters
const FB_PAGE_ID = process.env.FB_PAGE_ID;
if (!FB_PAGE_ID) {
  throw new Error('missing FB_PAGE_ID');
}
const FB_PAGE_TOKEN = process.env.FB_PAGE_TOKEN;
if (!FB_PAGE_TOKEN) {
  throw new Error('missing FB_PAGE_TOKEN');
}
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;

const FORECAST_TOKEN = process.env.FORECAST_TOKEN;

// Messenger API specific code

// See the Send API reference
// https://developers.facebook.com/docs/messenger-platform/send-api-reference
const fbReq = request.defaults({
  uri: 'https://graph.facebook.com/me/messages',
  method: 'POST',
  json: true,
  qs: { access_token: FB_PAGE_TOKEN },
  headers: {'Content-Type': 'application/json'},
});

const fbMessage = (recipientId, msg, cb) => {
  const opts = {
    form: {
      recipient: {
        id: recipientId,
      },
      message: {
        text: msg,
      },
    },
  };
  fbReq(opts, (err, resp, data) => {
    if (cb) {
      cb(err || data.error && data.error.message, data);
    }
  });
};

// See the Webhook reference
// https://developers.facebook.com/docs/messenger-platform/webhook-reference
const getFirstMessagingEntry = (body) => {
  const val = body.object == 'page' &&
    body.entry &&
    Array.isArray(body.entry) &&
    body.entry.length > 0 &&
    body.entry[0] &&
    body.entry[0].id === FB_PAGE_ID &&
    body.entry[0].messaging &&
    Array.isArray(body.entry[0].messaging) &&
    body.entry[0].messaging.length > 0 &&
    body.entry[0].messaging[0]
  ;
  return val || null;
};

// Wit.ai bot specific code

// This will contain all user sessions.
// Each session has an entry:
// sessionId -> {fbid: facebookUserId, context: sessionState}
const sessions = {};

const findOrCreateSession = (fbid) => {
  let sessionId;
  // Let's see if we already have a session for the user fbid
  Object.keys(sessions).forEach(k => {
    if (sessions[k].fbid === fbid) {
      // Yep, got it!
      sessionId = k;
    }
  });
  if (!sessionId) {
    // No session found for user fbid, let's create a new one
    sessionId = new Date().toISOString();
    sessions[sessionId] = {fbid: fbid, context: {}};
  }
  return sessionId;
};

const firstEntityValue = (entities, entity) => {
  const val = entities && entities[entity] &&
    Array.isArray(entities[entity]) &&
    entities[entity].length > 0 &&
    entities[entity][0].value
  ;
  if (!val) {
    return null;
  }
  return typeof val === 'object' ? val.value : val;
};

// Our bot actions
const actions = {
  say(sessionId, context, message, cb) {
    // Our bot has something to say!
    // Let's retrieve the Facebook user whose session belongs to
    const recipientId = sessions[sessionId].fbid;
    if (recipientId) {
      // Yay, we found our recipient!
      // Let's forward our bot response to her.
      if (message.length >= 320)
      {
        var first_msg = message.substring(0, 319);
        fbMessage(recipientId, first_msg, (err, data) => {
          if (err) {
            console.log(
              'Oops! An error occurred while forwarding the response to',
              recipientId,
              ':',
              err
            );
          }
          var rest_msg = message.substring(320);
          fbMessage(recipientId, rest_msg, (err, data) => {
            if (err) {
              console.log(
                'Oops! An error occurred while forwarding the response to',
                recipientId,
                ':',
                err
              );
            }

            // Let's give the wheel back to our bot
            cb();
          });
        });
      }
      else{
        fbMessage(recipientId, message, (err, data) => {
          if (err) {
            console.log(
              'Oops! An error occurred while forwarding the response to',
              recipientId,
              ':',
              err
            );
          }

          // Let's give the wheel back to our bot
          cb();
        });
      }
    } else {
      console.log('Oops! Couldn\'t find user for session:', sessionId);
      // Giving the wheel back to our bot
      cb();
    }
  },
  merge(sessionId, context, entities, message, cb) {
    // Retrieve the location entity and store it into a context field
    const beerStyle = firstEntityValue(entities, 'beer_style');
    if (beerStyle) {
      context.beerStyle = beerStyle;
    }

    const beerName = firstEntityValue(entities, 'beer_name');
    if (beerName) {
      context.beerName = beerName;
    }

    const loc = firstEntityValue(entities, 'location');
    if (loc) {
      context.loc = loc;
    }

    cb(context);
  },
  error(sessionId, context, error) {
    console.log(error.message);
  },
  ['getStyle'](sessionId, context, cb) {
    request('http://apis.mondorobot.com/beer-filters', function (error, response, body) {
      var attributeList = JSON.parse(body).beer_filters;
      var styleAndStyleType = {};
      _.map(attributeList, function(val, key) {
        _.each(val, function(hash) {
          styleAndStyleType[hash.name] = key;
        });
      });
      var styleType = styleAndStyleType[context.beerStyle];
      var queryString = styleType + "=" + context.beerStyle;

      request('http://apis.mondorobot.com/beers?' + queryString, function (error, response, body) {
        var parsedBody = JSON.parse(body);
        var beersArray = _.map(parsedBody.beers, function(beer) {
          return beer.name;
        });

        var beerNamesAndIds = {}
        _.each(parsedBody.beers, function(beer) {
          beerNamesAndIds[beer.name] = beer.id;
        });
        context.beerNamesAndIds = beerNamesAndIds;
        var beersString = beersArray.join(", ");
        context.beers = beersString;

        cb(context);
      });
    });
  },
  ['getBeerInfo'](sessionId, context, cb) {
    var queryString = context.beerNamesAndIds[context.beerName.replace("'", "\\'")];
    request('http://apis.mondorobot.com/beers/' + queryString, function (error, response, body) {
      console.log(context.beerName.replace("'", "\\'"));
      console.log(context.beerNamesAndIds);
      console.log(context.beerNamesAndIds[context.beerName]);
      var parsedBody = JSON.parse(body);
      console.log(parsedBody);
      context.description = parsedBody.beer.name + ' is a ' + parsedBody.beer.style + ' with '+ parsedBody.beer.abv + '% ABV';
      cb(context);
    });
  },
  ['getOnTap'](sessionId, context, cb) {
    request('http://apis.mondorobot.com/taproom/on-tap', function (error, response, body) {
      var parsedBody = JSON.parse(body);
      var beersArray = _.map(parsedBody.beer_list.beers, function(beer) {
        return beer.name;
      });
      var beersString = beersArray.join(", ");
      context.beers = beersString;

      cb(context);
    });
  },
  ['getWeather'](sessionId, context, cb) {
    request('https://api.forecast.io/forecast/'+FORECAST_TOKEN+'/40.0626984,-105.2047749', function (error, response, body) {
      var parsedBody = JSON.parse(body);
      context.forecast = parsedBody.minutely.summary;

      cb(context);
    });
  },
  ['getEvents'](sessionId, context, cb) {
    request('http://apis.mondorobot.com/events', function (error, response, body) {
      var parsedBody = JSON.parse(body);
      console.log(parsedBody);
      var eventsArray = _.map(parsedBody.events, function(event) {
        return event.title.replace(/\\"/g, '"');;
      });
      var eventsString = eventsArray.join(", ");
      context.events = eventsString;

      cb(context);
    });
  },
  ['beerFinder'](sessionId, context, cb) {

  }
};

// Setting up our bot
const wit = new Wit(WIT_TOKEN, actions);

// Starting our webserver and putting it all together
const app = express();
app.set('port', PORT);
app.listen(app.get('port'));
app.use(bodyParser.json());

// Webhook setup
app.get('/fb', (req, res) => {
  if (!FB_VERIFY_TOKEN) {
    throw new Error('missing FB_VERIFY_TOKEN');
  }
  if (req.query['hub.mode'] === 'subscribe' &&
    req.query['hub.verify_token'] === FB_VERIFY_TOKEN) {
    res.send(req.query['hub.challenge']);
  } else {
    res.sendStatus(400);
  }
});

// Message handler
app.post('/fb', (req, res) => {
  // Parsing the Messenger API response
  const messaging = getFirstMessagingEntry(req.body);
  if (messaging && messaging.message && messaging.recipient.id === FB_PAGE_ID) {
    // Yay! We got a new message!

    // We retrieve the Facebook user ID of the sender
    const sender = messaging.sender.id;

    // We retrieve the user's current session, or create one if it doesn't exist
    // This is needed for our bot to figure out the conversation history
    const sessionId = findOrCreateSession(sender);

    // We retrieve the message content
    const msg = messaging.message.text;
    const atts = messaging.message.attachments;

    if (atts) {
      // We received an attachment

      // Let's reply with an automatic message
      fbMessage(
        sender,
        'Sorry I can only process text messages for now.'
      );
    } else if (msg) {
      // We received a text message

      // Let's forward the message to the Wit.ai Bot Engine
      // This will run all actions until our bot has nothing left to do
      wit.runActions(
        sessionId, // the user's current session
        msg, // the user's message
        sessions[sessionId].context, // the user's current session state
        (error, context) => {
          if (error) {
            console.log('Oops! Got an error from Wit:', error);
          } else {
            // Our bot did everything it has to do.
            // Now it's waiting for further messages to proceed.
            console.log('Waiting for futher messages.');

            // Based on the session state, you might want to reset the session.
            // This depends heavily on the business logic of your bot.
            // Example:
            // if (context['done']) {
            //   delete sessions[sessionId];
            // }

            // Updating the user's current session state
            sessions[sessionId].context = context;
          }
        }
      );
    }
  }
  res.sendStatus(200);
});
<|endoftext|>


<commit_before>"use strict";

const path = require('path');
const del = require('del');
const runSequence = require('run-sequence');
const streamqueue = require('streamqueue');
const remoteSrc = require('gulp-remote-src');
const concat = require('gulp-concat');
const URL = require('url');
const karmaServer = require('karma').Server;

class Erik {
  /**
   * @param {Object} options
   * @param {Object} options.gulp - The gulp instance with which to register Erik's tasks.
   * @param {Boolean} [options.watch] - When watch is set, Erik will watch for changes to your
   * bundled spec and re-run the test suite when changes occur.
   * @param {String[]} [options.taskDependencies] - Names of tasks to be run before any Erik
   * processing is done. Useful for registering your spec-building/processing tasks as dependencies
   * of Erik's testing task. These tasks will be run in serial as passed.
   * @param {String[]} [options.localDependencies] - Local dependencies to be bundled alongisde your
   * remote dependencies. Glob strings. Useful for including your bower-installed packages, for
   * example.
   * @param {String[]} [options.remoteDependencies] - URLs corresponding to remote dependencies.
   * @param {String} options.bundledSpecPath - Path to your bundled and processed test suite.
   * @param {Object} [options.karmaConfig]
   * @param {Number} [options.karmaConfig.port=9876] - Port on which to run the Karma server.
   * @param {String} [bundlePath] - Base bath to use for Erik's bundled files. A directory named
   * `erik` will be created here.
   */
  constructor(options) {
    this._gulp = options.gulp;
    this._watch = options.watch || false;
    this._taskDependencies = options.taskDependencies || [];
    this._localDependencies = options.localDependencies || [];
    this._remoteDependencies = options.remoteDependencies || [];
    this._bundledSpecPath = options.bundledSpecPath;
    this._port = (options.karmaConfig && options.karmaConfig.port) || 9876;
    this._bundlePath = options.bundlePath || '';

    this._assertValidOptions(options);

    this._erikPath = path.join(options.bundlePath, '.erik');

    this._registerTasks();
  }

  _assertValidOptions() {
    if (typeof this._gulp !== 'object') {
      throw new Error('`options.gulp` is of an invalid type.');
    }

    if (typeof this._watch !== 'boolean') {
      throw new Error('`options.watch` is of an invalid type.');
    }

    if (!Array.isArray(this._taskDependencies)) {
      throw new Error('`options.taskDependencies` is of an invalid type.');
    }

    if (!Array.isArray(this._localDependencies)) {
      throw new Error('`options.localDependencies` is of an invalid type.');
    }

    if (!Array.isArray(this._remoteDependencies)) {
      throw new Error('`options.remoteDependencies` is of an invalid type.');
    }

    if (typeof this._bundledSpecPath !== 'string') {
      throw new Error('`options.bundledSpecPath` is of an invalid type.');
    }

    if (typeof this._port !== 'number') {
      throw new Error('`options.karmaConfig.port` is of an invalid type.');
    }

    if (typeof this._bundlePath !== 'string') {
      throw new Error('`options.bundlePath` is of an invalid type.');
    }
   }

  _registerTasks() {
    this._registerFetchRemoteDeps();
    this._registerBundleDeps();
    this._registerRunSpec();
    this._registerErik();
  }

  _registerFetchRemoteDeps() {
    this._gulp.task('erik-fetch-remote-deps', () => {
      /**
       * `streamqueue` hangs and `gulp` exits if `_remoteDependencies` is empty and we don't return
       * early here.
       */
      if (this._remoteDependencies.length === 0) return;

      return streamqueue({
        objectMode: true
      }, ...this._remoteDependencies.map((urlStr) => {
        const url = URL.parse(urlStr);
        const base = `${url.protocol}//${url.host}`;
        const path = url.path;

        return remoteSrc([path], {
          base
        });
      }))
        .pipe(concat('remote-deps.js'))
        .pipe(this._gulp.dest(this._erikPath));
    });
  }

  _registerBundleDeps() {
    this._gulp.task('erik-bundle-deps', () => {
      return this._gulp.src([
        `${this._erikPath}/remote-deps.js`,
        ...this._localDependencies
      ])
        .pipe(concat('bundled-deps.js'))
        .pipe(this._gulp.dest(this._erikPath));
    });
  }

  _registerRunSpec() {
    this._gulp.task('erik-run-spec', (done) => {
      new karmaServer.start({
        frameworks: ['jasmine'],
        browsers: ['PhantomJS'],
        reporters: ['mocha'],

        /**
         * Pass an empty object for `preprocessors` in order to disable Karma's default processing
         * of coffescript files.
         */
        preprocessors: {
        },

        files: [
          `${this._erikPath}/bundled-deps.js`,
          this._bundledSpecPath,
        ],

        port: this._port,

        autoWatch: this._watch,
        singleRun: !this._watch
      }, function(exitCode) {
        /**
         * We must create our own Error object because the error Karma returns is not a proper Error
         * object per https://github.com/karma-runner/gulp-karma/issues/18#issuecomment-188413903.
         */
        let error;
        if (exitCode !== 0) {
          error = new Error(`Karma returned with the exit code: ${exitCode}`);
        }

        done(error);
      });
    });
  }

  _registerErik() {
    this._gulp.task('erik', (done) => {
      del(this._erikPath);

      const tasks = this._taskDependencies.concat([
        'erik-fetch-remote-deps',
        'erik-bundle-deps',
        'erik-run-spec',
        done
      ]);

      // Run everything serially.
      runSequence.use(this._gulp)(...tasks);
    });
  }
}

module.exports = Erik;
<commit_msg>Use `del.sync` to block until the directory has been removed<commit_after>"use strict";

const path = require('path');
const del = require('del');
const runSequence = require('run-sequence');
const streamqueue = require('streamqueue');
const remoteSrc = require('gulp-remote-src');
const concat = require('gulp-concat');
const URL = require('url');
const karmaServer = require('karma').Server;

class Erik {
  /**
   * @param {Object} options
   * @param {Object} options.gulp - The gulp instance with which to register Erik's tasks.
   * @param {Boolean} [options.watch] - When watch is set, Erik will watch for changes to your
   * bundled spec and re-run the test suite when changes occur.
   * @param {String[]} [options.taskDependencies] - Names of tasks to be run before any Erik
   * processing is done. Useful for registering your spec-building/processing tasks as dependencies
   * of Erik's testing task. These tasks will be run in serial as passed.
   * @param {String[]} [options.localDependencies] - Local dependencies to be bundled alongisde your
   * remote dependencies. Glob strings. Useful for including your bower-installed packages, for
   * example.
   * @param {String[]} [options.remoteDependencies] - URLs corresponding to remote dependencies.
   * @param {String} options.bundledSpecPath - Path to your bundled and processed test suite.
   * @param {Object} [options.karmaConfig]
   * @param {Number} [options.karmaConfig.port=9876] - Port on which to run the Karma server.
   * @param {String} [bundlePath] - Base bath to use for Erik's bundled files. A directory named
   * `erik` will be created here.
   */
  constructor(options) {
    this._gulp = options.gulp;
    this._watch = options.watch || false;
    this._taskDependencies = options.taskDependencies || [];
    this._localDependencies = options.localDependencies || [];
    this._remoteDependencies = options.remoteDependencies || [];
    this._bundledSpecPath = options.bundledSpecPath;
    this._port = (options.karmaConfig && options.karmaConfig.port) || 9876;
    this._bundlePath = options.bundlePath || '';

    this._assertValidOptions(options);

    this._erikPath = path.join(options.bundlePath, '.erik');

    this._registerTasks();
  }

  _assertValidOptions() {
    if (typeof this._gulp !== 'object') {
      throw new Error('`options.gulp` is of an invalid type.');
    }

    if (typeof this._watch !== 'boolean') {
      throw new Error('`options.watch` is of an invalid type.');
    }

    if (!Array.isArray(this._taskDependencies)) {
      throw new Error('`options.taskDependencies` is of an invalid type.');
    }

    if (!Array.isArray(this._localDependencies)) {
      throw new Error('`options.localDependencies` is of an invalid type.');
    }

    if (!Array.isArray(this._remoteDependencies)) {
      throw new Error('`options.remoteDependencies` is of an invalid type.');
    }

    if (typeof this._bundledSpecPath !== 'string') {
      throw new Error('`options.bundledSpecPath` is of an invalid type.');
    }

    if (typeof this._port !== 'number') {
      throw new Error('`options.karmaConfig.port` is of an invalid type.');
    }

    if (typeof this._bundlePath !== 'string') {
      throw new Error('`options.bundlePath` is of an invalid type.');
    }
   }

  _registerTasks() {
    this._registerFetchRemoteDeps();
    this._registerBundleDeps();
    this._registerRunSpec();
    this._registerErik();
  }

  _registerFetchRemoteDeps() {
    this._gulp.task('erik-fetch-remote-deps', () => {
      /**
       * `streamqueue` hangs and `gulp` exits if `_remoteDependencies` is empty and we don't return
       * early here.
       */
      if (this._remoteDependencies.length === 0) return;

      return streamqueue({
        objectMode: true
      }, ...this._remoteDependencies.map((urlStr) => {
        const url = URL.parse(urlStr);
        const base = `${url.protocol}//${url.host}`;
        const path = url.path;

        return remoteSrc([path], {
          base
        });
      }))
        .pipe(concat('remote-deps.js'))
        .pipe(this._gulp.dest(this._erikPath));
    });
  }

  _registerBundleDeps() {
    this._gulp.task('erik-bundle-deps', () => {
      return this._gulp.src([
        `${this._erikPath}/remote-deps.js`,
        ...this._localDependencies
      ])
        .pipe(concat('bundled-deps.js'))
        .pipe(this._gulp.dest(this._erikPath));
    });
  }

  _registerRunSpec() {
    this._gulp.task('erik-run-spec', (done) => {
      new karmaServer.start({
        frameworks: ['jasmine'],
        browsers: ['PhantomJS'],
        reporters: ['mocha'],

        /**
         * Pass an empty object for `preprocessors` in order to disable Karma's default processing
         * of coffescript files.
         */
        preprocessors: {
        },

        files: [
          `${this._erikPath}/bundled-deps.js`,
          this._bundledSpecPath,
        ],

        port: this._port,

        autoWatch: this._watch,
        singleRun: !this._watch
      }, function(exitCode) {
        /**
         * We must create our own Error object because the error Karma returns is not a proper Error
         * object per https://github.com/karma-runner/gulp-karma/issues/18#issuecomment-188413903.
         */
        let error;
        if (exitCode !== 0) {
          error = new Error(`Karma returned with the exit code: ${exitCode}`);
        }

        done(error);
      });
    });
  }

  _registerErik() {
    this._gulp.task('erik', (done) => {
      del.sync(this._erikPath);

      const tasks = this._taskDependencies.concat([
        'erik-fetch-remote-deps',
        'erik-bundle-deps',
        'erik-run-spec',
        done
      ]);

      // Run everything serially.
      runSequence.use(this._gulp)(...tasks);
    });
  }
}

module.exports = Erik;
<|endoftext|>


<commit_before>module.exports = {
  random: random,
  randomIterator: randomIterator
};

/**
 * Creates seeded PRNG with two methods:
 *   next() and nextDouble()
 */
function random(inputSeed) {
  var seed = typeof inputSeed === 'number' ? inputSeed : (+ new Date());
  var randomFunc = function() {
      // Robert Jenkins' 32 bit integer hash function.
      seed = ((seed + 0x7ed55d16) + (seed << 12))  & 0xffffffff;
      seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff;
      seed = ((seed + 0x165667b1) + (seed << 5))   & 0xffffffff;
      seed = ((seed + 0xd3a2646c) ^ (seed << 9))   & 0xffffffff;
      seed = ((seed + 0xfd7046c5) + (seed << 3))   & 0xffffffff;
      seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff;
      return (seed & 0xfffffff) / 0x10000000;
  };

  return {
      /**
       * Generates random integer number in the range from 0 (inclusive) to maxValue (exclusive)
       *
       * @param maxValue Number REQUIRED. Omitting this number will result in NaN values from PRNG.
       */
      next : function (maxValue) {
          return Math.floor(randomFunc() * maxValue);
      },

      /**
       * Generates random double number in the range from 0 (inclusive) to 1 (exclusive)
       * This function is the same as Math.random() (except that it could be seeded)
       */
      nextDouble : function () {
          return randomFunc();
      }
  };
}

/*
 * Creates iterator over array, which returns items of array in random order
 * Time complexity is guaranteed to be O(n);
 */
function randomIterator(array, customRandom) {
    var localRandom = customRandom || random();
    if (typeof localRandom.next !== 'function') {
      throw new Error('customRandom does not match expected API: next() function is missing');
    }

    return {
        forEach : function (callback) {
            var i, j, t;
            for (i = array.length - 1; i > 0; --i) {
                j = localRandom.next(i + 1); // i inclusive
                t = array[j];
                array[j] = array[i];
                array[i] = t;

                callback(t);
            }

            if (array.length) {
                callback(array[0]);
            }
        },

        /**
         * Shuffles array randomly, in place.
         */
        shuffle : function () {
            var i, j, t;
            for (i = array.length - 1; i > 0; --i) {
                j = localRandom.next(i + 1); // i inclusive
                t = array[j];
                array[j] = array[i];
                array[i] = t;
            }

            return array;
        }
    };
}
<commit_msg>Removed anonymous functions<commit_after>module.exports = {
  random: random,
  randomIterator: randomIterator
};

/**
 * Creates seeded PRNG with two methods:
 *   next() and nextDouble()
 */
function random(inputSeed) {
  var seed = typeof inputSeed === 'number' ? inputSeed : (+new Date());

  return {
    /**
     * Generates random integer number in the range from 0 (inclusive) to maxValue (exclusive)
     *
     * @param maxValue Number REQUIRED. Omitting this number will result in NaN values from PRNG.
     */
    next: next,

    /**
     * Generates random double number in the range from 0 (inclusive) to 1 (exclusive)
     * This function is the same as Math.random() (except that it could be seeded)
     */
    nextDouble: nextDouble
  };

  function nextDouble() {
    return randomFunc();
  }

  function next(maxValue) {
    return Math.floor(randomFunc() * maxValue);
  }

  function randomFunc() {
    // Robert Jenkins' 32 bit integer hash function.
    seed = ((seed + 0x7ed55d16) + (seed << 12)) & 0xffffffff;
    seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff;
    seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffffffff;
    seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff;
    seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffffffff;
    seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff;
    return (seed & 0xfffffff) / 0x10000000;
  }
}

/*
 * Creates iterator over array, which returns items of array in random order
 * Time complexity is guaranteed to be O(n);
 */
function randomIterator(array, customRandom) {
  var localRandom = customRandom || random();
  if (typeof localRandom.next !== 'function') {
    throw new Error('customRandom does not match expected API: next() function is missing');
  }

  return {
    forEach: forEach,

    /**
     * Shuffles array randomly, in place.
     */
    shuffle: shuffle
  };

  function shuffle() {
    var i, j, t;
    for (i = array.length - 1; i > 0; --i) {
      j = localRandom.next(i + 1); // i inclusive
      t = array[j];
      array[j] = array[i];
      array[i] = t;
    }

    return array;
  }

  function forEach(callback) {
    var i, j, t;
    for (i = array.length - 1; i > 0; --i) {
      j = localRandom.next(i + 1); // i inclusive
      t = array[j];
      array[j] = array[i];
      array[i] = t;

      callback(t);
    }

    if (array.length) {
      callback(array[0]);
    }
  }
}
<|endoftext|>


<commit_before>#!/usr/bin/env electron
const path = require('path')
const minimist = require('minimist')
const electron = require('electron')
const isDev = require('electron-is-dev')
const contextMenu = require('electron-context-menu')
const debug = require('electron-debug')
const mkdirp = require('mkdirp')
const series = require('run-series')
const styles = require('mapeo-styles')
const rabbit = require('electron-rabbit')
const chmod = require('chela').mod

const app = electron.app
const BrowserWindow = electron.BrowserWindow

const updater = require('./src/main/auto-updater')
const userConfig = require('./src/main/user-config')
const Worker = require('./src/worker')
const logger = require('./src/logger')
const electronIpc = require('./src/main/ipc')
const createMenu = require('./src/main/menu')
const windowStateKeeper = require('./src/main/window-state')

// Path to `userData`, operating system specific, see
// https://github.com/atom/electron/blob/master/docs/api/app.md#appgetpathname
var userDataPath = app.getPath('userData')
var worker = new Worker(userDataPath)

// HACK: enable GPU graphics acceleration on some older laptops
app.commandLine.appendSwitch('ignore-gpu-blacklist', 'true')
app.commandLine.appendSwitch('ignore-certificate-errors')

// Setup some handy dev tools shortcuts (only activates in dev mode)
// See https://github.com/sindresorhus/electron-debug
debug({ showDevTools: false })

// Handle uncaught errors
// XXX(KM): why aren't we enabling this?
// catchErrors({ onError: handleError })
//
var exiting = false

// Before we do anything, let's make sure we're ready to gracefully shut down
const onExit = require('capture-exit')
const signalExit = require('signal-exit')
onExit.captureExit()
onExit.onExit(beforeQuit)
signalExit(beforeQuit, { alwaysLast: true })

var win = null
var splash = null
var bg = null
var mainWindowState = null
var ipc = new rabbit.Client()

var gotTheLock = app.requestSingleInstanceLock()

if (!gotTheLock) {
  // Didn't get a lock, because another instance is open, so we quit
  process.exit(0)
} else {
  app.on('second-instance', () => {
    // Someone tried to run a second instance, we should focus our window.
    if (win) {
      if (win.isMinimized()) win.restore()
      win.focus()
    }
  })
}

if (!logger.configured) {
  logger.configure({
    label: 'main',
    userDataPath,
    isDev
  })
}

var argv = minimist(process.argv.slice(2), {
  default: {
    port: 5000,
    datadir: path.join(userDataPath, 'kappa.db'),
    tileport: 5005
  },
  boolean: ['headless', 'debug'],
  alias: {
    p: 'port',
    t: 'tileport',
    d: 'debug'
  }
})

var _socketName

rabbit.findOpenSocket('mapeo').then((socketName) => {
  logger.debug('got socket', socketName)
  _socketName = socketName
  if (argv.headless) startSequence()
  else app.once('ready', openWindow)
}).catch((err) => {
  logger.error(err)
  throw new Error('No socket found!', err)
})

app.on('before-quit', (e) => {
  // Cancel quit and wait for server to close
  if (e) e.preventDefault()
  beforeQuit()
})
app.on('window-all-closed', function () {
  app.quit()
})

function openWindow () {
  ipc.on('error', function (err) {
    logger.error('ipc', err)
    electron.dialog.showErrorBox('Error', err)
  })
  ipc.connect(_socketName)

  if (!win) {
    win = createWindow(_socketName)
    splash = createSplashWindow()
  }

  if (isDev) {
    // for updater to work correctly
    process.env.APPIMAGE = path.join(__dirname, 'dist', `Installar_Mapeo_v${app.getVersion()}_linux.AppImage`)
    try {
      var {
        default: installExtension,
        REACT_DEVELOPER_TOOLS
      } = require('electron-devtools-installer')
    } catch (e) {}
    installExtension(REACT_DEVELOPER_TOOLS)
      .then(name => logger.debug(`Added Extension:  ${name}`))
      .catch(err => logger.error('Failed to add extension', err))
  }
  bg = createBgWindow(_socketName)
  createMenu(ipc)

  // Emitted when the window is closed.
  win.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    win = null
    splash = null
    bg = null
    app.quit()
  })

  startSequence()
}

function startupMsg (txt) {
  return function (done) {
    logger.debug('[STARTUP] ' + txt)
    done()
  }
}

function startSequence () {
  // The app startup sequence
  series(
    [
      initDirectories,
      startupMsg('Initialized directories'),

      createServers,
      startupMsg('Started node-ipc servers'),

      notifyReady,
      startupMsg('Notified the frontend that backend is ready')
    ],
    function (err) {
      if (err) logger.error('STARTUP FAILED', err)
      else logger.debug('STARTUP success!')
    }
  )
}

function initDirectories (done) {
  startupMsg('Unpacking Styles')
  // This is necessary to make sure that the directories
  // are writable by the user
  mkdirp.sync(path.join(userDataPath, 'styles'))
  mkdirp.sync(path.join(userDataPath, 'presets'))
  mkdirp.sync(argv.datadir)

  styles.unpackIfNew(userDataPath, function (err, newSettings) {
    if (err) logger.error('[ERROR] while unpacking styles:', err)
    var fallbackSettingsLocation = path.join(userDataPath, 'presets', styles.FALLBACK_DIR_NAME)
    if (newSettings) userConfig.copyFallbackSettings(fallbackSettingsLocation, cleanupPermissions)
    else cleanupPermissions()
  })

  function cleanupPermissions () {
    chmod(path.join(userDataPath, 'presets'), '0700', (err) => {
      if (err) logger.error('Failed to execute chmod on presets', err)
      chmod(path.join(userDataPath, 'styles'), '0700', (err) => {
        if (err) logger.error('Failed to execute chmod on styles', err)
        done()
      })
    })
  }
}

function createServers (done) {
  function ipcSend (...args) {
    try {
      if (win && win.webContents) win.webContents.send.apply(win.webContents, args)
    } catch (e) {
      logger.error('exception win.webContents.send', args, e.stack)
    }
  }

  electronIpc(ipcSend)

  logger.info('initializing mapeo', userDataPath, argv.port)
  var opts = {
    userDataPath,
    datadir: argv.datadir,
    port: argv.port,
    tileport: argv.tileport
  }

  ipc.send('listen', opts, function (err, port) {
    if (err) throw new Error('fatal: could not get port', err)
    global.osmServerHost = '127.0.0.1:' + port
    logger.info('Server listening:', global.osmServerHost)
    done()
  })
}

function notifyReady (done) {
  logger.info('Server ready, checking front-end is loaded')
  // If the window is still loading, wait for it to finish before continuing
  // win.webContents.isLoading() does not seem to work here on Windows
  if (!win._didFinishLoad) {
    logger.info('Front-end still loading, check again once loaded')
    win.webContents.once('did-finish-load', () => {
      win._didFinishLoad = true
      notifyReady(done)
    })
    return
  }
  logger.info('Front-end loaded, close loading screen and open main window')
  var IS_TEST = process.env.NODE_ENV === 'test'
  if (IS_TEST) win.setSize(1000, 800, false)
  if (argv.debug) win.webContents.openDevTools()
  // notify renderer that server is ready
  // TODO: Send host and port here too, rather than via global
  win.webContents.send('back-end-ready')
  win.maximize()
  splash.destroy()
  win.show()
  updater.periodicUpdates()
  done()
}

function createWindow (socketName) {
  var APP_NAME = app.getName()
  var INDEX = 'file://' + path.join(__dirname, './static/main.html')
  mainWindowState = windowStateKeeper({
    defaultWidth: 1000,
    defaultHeight: 800
  })
  var mainWindow = new BrowserWindow({
    x: mainWindowState.x,
    y: mainWindowState.y,
    width: mainWindowState.width,
    height: mainWindowState.height,
    title: APP_NAME,
    show: false,
    alwaysOnTop: false,
    titleBarStyle: 'hidden',
    icon: path.resolve(__dirname, 'static', 'mapeo_256x256.png'),
    webPreferences: {
      nodeIntegration: true,
      preload: path.resolve(__dirname, 'src', 'renderer', 'index-preload.js')
    }
  })
  mainWindowState.manage(mainWindow)

  mainWindow.webContents.on('did-finish-load', () => {
    logger.info('Front-end has finished loading')
    mainWindow._didFinishLoad = true
    if (process.env.NODE_ENV === 'test') mainWindow.setSize(1000, 800, false)
    if (argv.debug) mainWindow.webContents.openDevTools()
    mainWindow.webContents.send('set-socket', { name: socketName })
    // 'did-finish-load' can fire before the backend server is ready, or when
    // the user refreshes the main window. On window refresh the notifyReady()
    // function will not run, so we use `global.osmServerHost` to check whether
    // the server is ready, and notify the front-end if it is
    if (global.osmServerHost) {
      logger.info('Server is ready, inform front-end')
      mainWindow.webContents.send('back-end-ready')
    } else {
      logger.info('Server is not ready, front-end will be informed later')
    }
  })
  mainWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription, validatedURL, isMainFrame) => {
    if (errorDescription === 'ERR_INTERNET_DISCONNECTED' || errorDescription === 'ERR_PROXY_CONNECTION_FAILED') {
      logger.log(errorDescription)
    }
    logger.error(errorDescription)
  })
  mainWindow.loadURL(INDEX)
  return mainWindow
}

// Create a hidden background window
function createBgWindow (socketName) {
  logger.debug('loading electron background window')
  var bgWindow = new BrowserWindow({
    x: 0,
    y: 0,
    width: 700,
    height: 700,
    show: argv.debug,
    webPreferences: {
      nodeIntegration: true
    }
  })
  var BG = 'file://' + path.join(__dirname, './src/background/background.html')
  bgWindow.loadURL(BG)
  bgWindow.webContents.on('did-finish-load', () => {
    if (argv.debug) bg.webContents.openDevTools()
    if (bgWindow && bgWindow.webContents) {
      bgWindow.webContents.send('configure', {
        socketName,
        userDataPath,
        isDev
      })
    }
  })
  bgWindow.on('closed', () => {
    logger.info('Background window closed')
    app.quit()
  })
  return bgWindow
}

function createSplashWindow () {
  var SPLASH = 'file://' + path.join(__dirname, './static/splash.html')
  var splash = new BrowserWindow({
    width: 450,
    height: 410,
    center: true,
    transparent: true,
    resizable: false,
    frame: false
  })
  splash.loadURL(SPLASH)
  return splash
}

contextMenu({
  showLookUpSelection: false,
  showCopyImage: true,
  showSaveImageAs: true,
  showInspectElement: isDev
})

function showClosingWindow () {
  var CLOSING = 'file://' + path.join(__dirname, './closing.html')
  var closingWin = new BrowserWindow({
    width: 600,
    height: 400,
    frame: false,
    show: false,
    alwaysOnTop: false
  })

  closingWin.loadURL(CLOSING)
  var closingTimeoutId = setTimeout(() => {
    closingWin.show()
  }, 300)
  return () => {
    clearTimeout(closingTimeoutId)
    try { closingWin.close() } catch (e) {}
    closingWin = null
  }
}

function beforeQuit () {
  if (exiting) return
  exiting = true
  // 'close' event will gracefully close databases and wait for pending sync
  logger.debug('Closing IPC')

  ipc.send('get-replicating-peers', null, (err, length) => {
    if (err) logger.error('get-replicating-peers on close', err)

    let closeClosingWindow = () => {}
    if (length) closeClosingWindow = showClosingWindow()

    ipc.send('close', null, () => {
      logger.debug('IPC closed')

      worker.cleanup((err) => {
        if (err) !isDev ? logger.error('Failed to clean up a child process', err) : logger.debug('Nothing to clean up')
        logger.debug('Successfully removed any stale processes')

        closeClosingWindow()
        app.exit()
      })
    })
  })
}
<commit_msg>fix: Ensure any stale processes are cleaned up before starting ipc workers<commit_after>#!/usr/bin/env electron
const path = require('path')
const minimist = require('minimist')
const electron = require('electron')
const isDev = require('electron-is-dev')
const contextMenu = require('electron-context-menu')
const debug = require('electron-debug')
const mkdirp = require('mkdirp')
const series = require('run-series')
const styles = require('mapeo-styles')
const rabbit = require('electron-rabbit')
const chmod = require('chela').mod

const app = electron.app
const BrowserWindow = electron.BrowserWindow

const updater = require('./src/main/auto-updater')
const userConfig = require('./src/main/user-config')
const Worker = require('./src/worker')
const logger = require('./src/logger')
const electronIpc = require('./src/main/ipc')
const createMenu = require('./src/main/menu')
const windowStateKeeper = require('./src/main/window-state')

// Path to `userData`, operating system specific, see
// https://github.com/atom/electron/blob/master/docs/api/app.md#appgetpathname
var userDataPath = app.getPath('userData')
var worker = new Worker(userDataPath)

// HACK: enable GPU graphics acceleration on some older laptops
app.commandLine.appendSwitch('ignore-gpu-blacklist', 'true')
app.commandLine.appendSwitch('ignore-certificate-errors')

// Setup some handy dev tools shortcuts (only activates in dev mode)
// See https://github.com/sindresorhus/electron-debug
debug({ showDevTools: false })

// Handle uncaught errors
// XXX(KM): why aren't we enabling this?
// catchErrors({ onError: handleError })
//
var exiting = false

// Before we do anything, let's make sure we're ready to gracefully shut down
const onExit = require('capture-exit')
const signalExit = require('signal-exit')
onExit.captureExit()
onExit.onExit(beforeQuit)
signalExit(beforeQuit, { alwaysLast: true })

var win = null
var splash = null
var bg = null
var mainWindowState = null
var ipc = new rabbit.Client()

var gotTheLock = app.requestSingleInstanceLock()

if (!gotTheLock) {
  // Didn't get a lock, because another instance is open, so we quit
  process.exit(0)
} else {
  app.on('second-instance', () => {
    // Someone tried to run a second instance, we should focus our window.
    if (win) {
      if (win.isMinimized()) win.restore()
      win.focus()
    }
  })
}

if (!logger.configured) {
  logger.configure({
    label: 'main',
    userDataPath,
    isDev
  })
}

var argv = minimist(process.argv.slice(2), {
  default: {
    port: 5000,
    datadir: path.join(userDataPath, 'kappa.db'),
    tileport: 5005
  },
  boolean: ['headless', 'debug'],
  alias: {
    p: 'port',
    t: 'tileport',
    d: 'debug'
  }
})

var _socketName

rabbit.findOpenSocket('mapeo').then((socketName) => {
  logger.debug('got socket', socketName)
  _socketName = socketName
  if (argv.headless) startSequence()
  else app.once('ready', openWindow)
}).catch((err) => {
  logger.error(err)
  throw new Error('No socket found!', err)
})

app.on('before-quit', (e) => {
  // Cancel quit and wait for server to close
  if (e) e.preventDefault()
  beforeQuit()
})
app.on('window-all-closed', function () {
  app.quit()
})

function openWindow () {
  ipc.on('error', function (err) {
    logger.error('ipc', err)
    electron.dialog.showErrorBox('Error', err)
  })
  ipc.connect(_socketName)

  if (!win) {
    win = createWindow(_socketName)
    splash = createSplashWindow()
  }

  if (isDev) {
    // for updater to work correctly
    process.env.APPIMAGE = path.join(__dirname, 'dist', `Installar_Mapeo_v${app.getVersion()}_linux.AppImage`)
    try {
      var {
        default: installExtension,
        REACT_DEVELOPER_TOOLS
      } = require('electron-devtools-installer')
    } catch (e) {}
    installExtension(REACT_DEVELOPER_TOOLS)
      .then(name => logger.debug(`Added Extension:  ${name}`))
      .catch(err => logger.error('Failed to add extension', err))
  }
  bg = createBgWindow(_socketName)
  createMenu(ipc)

  // Emitted when the window is closed.
  win.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    win = null
    splash = null
    bg = null
    app.quit()
  })

  startSequence()
}

function startupMsg (txt) {
  return function (done) {
    logger.debug('[STARTUP] ' + txt)
    done()
  }
}

function startSequence () {
  // The app startup sequence
  series(
    [
      initDirectories,
      startupMsg('Initialized directories'),

      createServers,
      startupMsg('Started node-ipc servers'),

      notifyReady,
      startupMsg('Notified the frontend that backend is ready')
    ],
    function (err) {
      if (err) logger.error('STARTUP FAILED', err)
      else logger.debug('STARTUP success!')
    }
  )
}

function initDirectories (done) {
  startupMsg('Unpacking Styles')
  // This is necessary to make sure that the directories
  // are writable by the user
  mkdirp.sync(path.join(userDataPath, 'styles'))
  mkdirp.sync(path.join(userDataPath, 'presets'))
  mkdirp.sync(argv.datadir)

  styles.unpackIfNew(userDataPath, function (err, newSettings) {
    if (err) logger.error('[ERROR] while unpacking styles:', err)
    var fallbackSettingsLocation = path.join(userDataPath, 'presets', styles.FALLBACK_DIR_NAME)
    if (newSettings) userConfig.copyFallbackSettings(fallbackSettingsLocation, cleanupPermissions)
    else cleanupPermissions()
  })

  function cleanupPermissions () {
    chmod(path.join(userDataPath, 'presets'), '0700', (err) => {
      if (err) logger.error('Failed to execute chmod on presets', err)
      chmod(path.join(userDataPath, 'styles'), '0700', (err) => {
        if (err) logger.error('Failed to execute chmod on styles', err)
        done()
      })
    })
  }
}

function createServers (done) {
  function ipcSend (...args) {
    try {
      if (win && win.webContents) win.webContents.send.apply(win.webContents, args)
    } catch (e) {
      logger.error('exception win.webContents.send', args, e.stack)
    }
  }

  electronIpc(ipcSend)

  logger.info('initializing mapeo', userDataPath, argv.port)
  var opts = {
    userDataPath,
    datadir: argv.datadir,
    port: argv.port,
    tileport: argv.tileport
  }

  worker.cleanup((err) => {
    if (err) logger.debug('No stale processes to clean up')
    else logger.debug('Successfully removed any stale processes')

    ipc.send('listen', opts, function (err, port) {
      if (err) throw new Error('fatal: could not get port', err)
      global.osmServerHost = '127.0.0.1:' + port
      logger.info('Server listening:', global.osmServerHost)
      done()
    })
  })
}

function notifyReady (done) {
  logger.info('Server ready, checking front-end is loaded')
  // If the window is still loading, wait for it to finish before continuing
  // win.webContents.isLoading() does not seem to work here on Windows
  if (!win._didFinishLoad) {
    logger.info('Front-end still loading, check again once loaded')
    win.webContents.once('did-finish-load', () => {
      win._didFinishLoad = true
      notifyReady(done)
    })
    return
  }
  logger.info('Front-end loaded, close loading screen and open main window')
  var IS_TEST = process.env.NODE_ENV === 'test'
  if (IS_TEST) win.setSize(1000, 800, false)
  if (argv.debug) win.webContents.openDevTools()
  // notify renderer that server is ready
  // TODO: Send host and port here too, rather than via global
  win.webContents.send('back-end-ready')
  win.maximize()
  splash.destroy()
  win.show()
  updater.periodicUpdates()
  done()
}

function createWindow (socketName) {
  var APP_NAME = app.getName()
  var INDEX = 'file://' + path.join(__dirname, './static/main.html')
  mainWindowState = windowStateKeeper({
    defaultWidth: 1000,
    defaultHeight: 800
  })
  var mainWindow = new BrowserWindow({
    x: mainWindowState.x,
    y: mainWindowState.y,
    width: mainWindowState.width,
    height: mainWindowState.height,
    title: APP_NAME,
    show: false,
    alwaysOnTop: false,
    titleBarStyle: 'hidden',
    icon: path.resolve(__dirname, 'static', 'mapeo_256x256.png'),
    webPreferences: {
      nodeIntegration: true,
      preload: path.resolve(__dirname, 'src', 'renderer', 'index-preload.js')
    }
  })
  mainWindowState.manage(mainWindow)

  mainWindow.webContents.on('did-finish-load', () => {
    logger.info('Front-end has finished loading')
    mainWindow._didFinishLoad = true
    if (process.env.NODE_ENV === 'test') mainWindow.setSize(1000, 800, false)
    if (argv.debug) mainWindow.webContents.openDevTools()
    mainWindow.webContents.send('set-socket', { name: socketName })
    // 'did-finish-load' can fire before the backend server is ready, or when
    // the user refreshes the main window. On window refresh the notifyReady()
    // function will not run, so we use `global.osmServerHost` to check whether
    // the server is ready, and notify the front-end if it is
    if (global.osmServerHost) {
      logger.info('Server is ready, inform front-end')
      mainWindow.webContents.send('back-end-ready')
    } else {
      logger.info('Server is not ready, front-end will be informed later')
    }
  })
  mainWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription, validatedURL, isMainFrame) => {
    if (errorDescription === 'ERR_INTERNET_DISCONNECTED' || errorDescription === 'ERR_PROXY_CONNECTION_FAILED') {
      logger.log(errorDescription)
    }
    logger.error(errorDescription)
  })
  mainWindow.loadURL(INDEX)
  return mainWindow
}

// Create a hidden background window
function createBgWindow (socketName) {
  logger.debug('loading electron background window')
  var bgWindow = new BrowserWindow({
    x: 0,
    y: 0,
    width: 700,
    height: 700,
    show: argv.debug,
    webPreferences: {
      nodeIntegration: true
    }
  })
  var BG = 'file://' + path.join(__dirname, './src/background/background.html')
  bgWindow.loadURL(BG)
  bgWindow.webContents.on('did-finish-load', () => {
    if (argv.debug) bg.webContents.openDevTools()
    if (bgWindow && bgWindow.webContents) {
      bgWindow.webContents.send('configure', {
        socketName,
        userDataPath,
        isDev
      })
    }
  })
  bgWindow.on('closed', () => {
    logger.info('Background window closed')
    app.quit()
  })
  return bgWindow
}

function createSplashWindow () {
  var SPLASH = 'file://' + path.join(__dirname, './static/splash.html')
  var splash = new BrowserWindow({
    width: 450,
    height: 410,
    center: true,
    transparent: true,
    resizable: false,
    frame: false
  })
  splash.loadURL(SPLASH)
  return splash
}

contextMenu({
  showLookUpSelection: false,
  showCopyImage: true,
  showSaveImageAs: true,
  showInspectElement: isDev
})

function showClosingWindow () {
  var CLOSING = 'file://' + path.join(__dirname, './closing.html')
  var closingWin = new BrowserWindow({
    width: 600,
    height: 400,
    frame: false,
    show: false,
    alwaysOnTop: false
  })

  closingWin.loadURL(CLOSING)
  var closingTimeoutId = setTimeout(() => {
    closingWin.show()
  }, 300)
  return () => {
    clearTimeout(closingTimeoutId)
    try { closingWin.close() } catch (e) {}
    closingWin = null
  }
}

function beforeQuit () {
  if (exiting) return
  exiting = true
  // 'close' event will gracefully close databases and wait for pending sync
  logger.debug('Closing IPC')

  ipc.send('get-replicating-peers', null, (err, length) => {
    if (err) logger.error('get-replicating-peers on close', err)

    let closeClosingWindow = () => {}
    if (length) closeClosingWindow = showClosingWindow()

    ipc.send('close', null, () => {
      logger.debug('IPC closed')

      worker.cleanup((err) => {
        if (err) !isDev ? logger.error('Failed to clean up a child process', err) : logger.debug('Nothing to clean up')
        logger.debug('Successfully removed any stale processes')

        closeClosingWindow()
        app.exit()
      })
    })
  })
}
<|endoftext|>


<commit_before>var chalk = require('chalk');
var gutil = require('gulp-util');
var toposort = require('toposort');

module.exports = preprocessTopoMerger;

/**
 * Merges preprocess options through complementing with a default config file and sorts dependencies.
 * This function adds a new property called `preprocessFeatures` holding an array first level preprocess option keys.
 *
 * **Note:** Dependencies are read from `preprocessDependencies` property.
 *
 * @param {Object} config - The new config to be merged with defaultConfig.
 * @param {Object} defaultConfig - The default config used to complement the new config.
 */
function preprocessTopoMerger(config, defaultConfig) {
    var toposort = new Toposort();
    var preprocess = config.preprocess;
    var preprocessDefault = defaultConfig.preprocess;
    var dependencies = defaultConfig.preprocessDependencies;
    var features;
    var edges = hashToEdges(dependencies);
    var edge;
    var node;
    var dep;
    var i, l;
    var resolved = [];

    // resolve dependant properties
    for(i=0, l=edges.length; i<l; i++) {
        edge = edges[i];
        node = edge[0];
        dep = edge[1];

        if(preprocess[node] && !preprocess[dep]) {
            preprocess[dep] = preprocessDefault[dep];

            resolved.push(dep);

            edges.slice(i, 1);
            l--;
            i=-1;
        }
    }

    // set features
    edges = hashToEdges(dependencies);
    features = Object.keys(preprocess);
    features = toposort.array(features, edges).reverse();

    config.preprocessFeatures = features;

    gutil.log(chalk.green('Resolved ') + chalk.yellow(resolved.length) + chalk.green(' Dependencies: ') + chalk.yellow(resolved.join(chalk.green(', '))));
}

function hashToEdges(hash) {
    var keys = Object.keys(hash);
    var edges = [];
    var key;
    var deps;
    var i, l, j, k;

    for(i=0, l=keys.length; i<l; i++) {
        key = keys[i];
        deps = hash[key];

        for(j=0, k=deps.length; j<k; j++) {
            edges.push([key, deps[j]]);
        }
    }

    return edges;
}<commit_msg>fixed unnecessary instanciation of Toposort<commit_after>var chalk = require('chalk');
var gutil = require('gulp-util');
var toposort = require('toposort');

module.exports = preprocessTopoMerger;

/**
 * Merges preprocess options through complementing with a default config file and sorts dependencies.
 * This function adds a new property called `preprocessFeatures` holding an array first level preprocess option keys.
 *
 * **Note:** Dependencies are read from `preprocessDependencies` property.
 *
 * @param {Object} config - The new config to be merged with defaultConfig.
 * @param {Object} defaultConfig - The default config used to complement the new config.
 */
function preprocessTopoMerger(config, defaultConfig) {
    var preprocess = config.preprocess;
    var preprocessDefault = defaultConfig.preprocess;
    var dependencies = defaultConfig.preprocessDependencies;
    var features;
    var edges = hashToEdges(dependencies);
    var edge;
    var node;
    var dep;
    var i, l;
    var resolved = [];

    // resolve dependant properties
    for(i=0, l=edges.length; i<l; i++) {
        edge = edges[i];
        node = edge[0];
        dep = edge[1];

        if(preprocess[node] && !preprocess[dep]) {
            preprocess[dep] = preprocessDefault[dep];

            resolved.push(dep);

            edges.slice(i, 1);
            l--;
            i=-1;
        }
    }

    // set features
    edges = hashToEdges(dependencies);
    features = Object.keys(preprocess);
    features = toposort.array(features, edges).reverse();

    config.preprocessFeatures = features;

    gutil.log(chalk.green('Resolved ') + chalk.yellow(resolved.length) + chalk.green(' Dependencies: ') + chalk.yellow(resolved.join(chalk.green(', '))));
}

function hashToEdges(hash) {
    var keys = Object.keys(hash);
    var edges = [];
    var key;
    var deps;
    var i, l, j, k;

    for(i=0, l=keys.length; i<l; i++) {
        key = keys[i];
        deps = hash[key];

        for(j=0, k=deps.length; j<k; j++) {
            edges.push([key, deps[j]]);
        }
    }

    return edges;
}<|endoftext|>


<commit_before>var Module = require('module')
var babel = require('babel')
var path = require('path')
var fs = require('fs')
var vm = require('vm')

module.exports = es6Require

function es6Require (rootModule, _options, _root) {
  var ES6Module = Object.create(Module)
  ES6Module._extensions = Object.create(Module._extensions)

  var options = _options || {}
  var es6Extensions = options.extensions || ['.es6', '.jsx']
  var extensions = Object.keys(Module._extensions).concat(es6Extensions)
  var root = _root || path.dirname(rootModule.filename)

  options.babel = options.babel || {}

  if (options.babel.retainLines === undefined) options.babel.retainLines = true

  for (var i = 0; i < extensions.length; ++i) {
    ES6Module._extensions[extensions[i]] = compile
  }

  return makeRequire(rootModule, options)

  function makeRequire (original) {
    require.main = process.mainModule
    require.cache = Module._cache
    require.resolve = resolve
    return require

    function resolve (req) {
      var prev = Module._extensions
      Module._extensions = ES6Module._extensions
      try {
        return ES6Module._resolveFilename(req, original)
      } finally {
        Module._extensions = prev
      }
    }

    function require (req) {
      if (!req || typeof req !== 'string') return original.require(req)
      try {
        var filename = resolve(req)
      } catch (err) {
        return original.require(req)
      }

      var relative = path.relative(root, filename)
      if (filename[0] !== '/') return original.require(req)
      if (relative[0] === '.' || relative[0] === '/') return original.require(req)
      if (relative.indexOf('node_modules') !== -1) return original.require(req)

      var cachedModule = Module._cache[filename]
      if (cachedModule) return cachedModule.exports
      var module = new Module(filename, original)
      Module._cache[filename] = module
      module.filename = filename
      module.paths = Module._nodeModulePaths(path.dirname(filename))

      var hadException = true
      try {
        compile(module, filename)
        hadException = false
      } finally {
        if (hadException) delete Module._cache[filename]
      }

      module.loaded = true
      return module.exports
    }
  }

  function compile (module, filename) {
    var require = makeRequire(module)
    var dirname = path.dirname(filename)
    var content = fs.readFileSync(filename, 'utf8')
    var ext = path.extname(filename)
    var code

    if (es6Extensions.indexOf(ext) !== -1) {
      code = babel.transform(content, options.babel).code
    } else {
      code = content
    }

    var wrapper = wrap(code)
    var compiled = vm.runInThisContext(wrapper, {filename: filename})
    return compiled.call(module.exports, module.exports, require, module, filename, dirname)
  }
}

function wrap (code) {
  return '0 || ' + new Function(
    'exports, require, module, __filename, __dirname',
    code
  ).toString()
}
<commit_msg>don't modify options<commit_after>var Module = require('module')
var babel = require('babel')
var path = require('path')
var util = require('util')
var fs = require('fs')
var vm = require('vm')

module.exports = es6Require

function es6Require (rootModule, _options, _root) {
  var ES6Module = Object.create(Module)
  ES6Module._extensions = Object.create(Module._extensions)

  var options = util._extend({}, _options || {})
  var es6Extensions = options.extensions || ['.es6', '.jsx']
  var extensions = Object.keys(Module._extensions).concat(es6Extensions)
  var root = _root || path.dirname(rootModule.filename)

  options.babel = util._extend({}, options.babel || {})

  if (options.babel.retainLines === undefined) options.babel.retainLines = true

  for (var i = 0; i < extensions.length; ++i) {
    ES6Module._extensions[extensions[i]] = compile
  }

  return makeRequire(rootModule, options)

  function makeRequire (original) {
    require.main = process.mainModule
    require.cache = Module._cache
    require.resolve = resolve
    return require

    function resolve (req) {
      var prev = Module._extensions
      Module._extensions = ES6Module._extensions
      try {
        return ES6Module._resolveFilename(req, original)
      } finally {
        Module._extensions = prev
      }
    }

    function require (req) {
      if (!req || typeof req !== 'string') return original.require(req)
      try {
        var filename = resolve(req)
      } catch (err) {
        return original.require(req)
      }

      var relative = path.relative(root, filename)
      if (filename[0] !== '/') return original.require(req)
      if (relative[0] === '.' || relative[0] === '/') return original.require(req)
      if (relative.indexOf('node_modules') !== -1) return original.require(req)

      var cachedModule = Module._cache[filename]
      if (cachedModule) return cachedModule.exports
      var module = new Module(filename, original)
      Module._cache[filename] = module
      module.filename = filename
      module.paths = Module._nodeModulePaths(path.dirname(filename))

      var hadException = true
      try {
        compile(module, filename)
        hadException = false
      } finally {
        if (hadException) delete Module._cache[filename]
      }

      module.loaded = true
      return module.exports
    }
  }

  function compile (module, filename) {
    var require = makeRequire(module)
    var dirname = path.dirname(filename)
    var content = fs.readFileSync(filename, 'utf8')
    var ext = path.extname(filename)
    var code

    if (es6Extensions.indexOf(ext) !== -1) {
      code = babel.transform(content, options.babel).code
    } else {
      code = content
    }

    var wrapper = wrap(code)
    var compiled = vm.runInThisContext(wrapper, {filename: filename})
    return compiled.call(module.exports, module.exports, require, module, filename, dirname)
  }
}

function wrap (code) {
  return '0 || ' + new Function(
    'exports, require, module, __filename, __dirname',
    code
  ).toString()
}
<|endoftext|>