<commit_before>
var primitives = require('./primitives');
var Symbol = primitives.Symbol, HashSymbol = primitives.HashSymbol;

var Reader = require('./reader').Reader;
var Stream = require('./stream').Stream;

// utils

Object.prototype.toArray = function () {
    return Array.prototype.slice.call(this);
};

// compiler

function compileAll (forms, all, comma) {
    var separator = ';\n';
    if (comma) {
	separator = ', ';
    }
    var result = forms.map(compile).join(separator);
    if (all && forms.length == 1) {
	result += (separator + '\n');
    }
    return result;
}

function compile (form) {
    if (form instanceof Array) {
	var head = form[0];
	var rest = form.slice(1);
	if (macros.hasOwnProperty(head.name)) {
	    return macros[head.name].apply(this, rest);
	} else if (infix.hasOwnProperty(head.name)) {
	    return rest.map(compile).join(' ' + infix[head.name] + ' ');
	} else {
	    return compile(head) + '(' + rest.map(compile).join(', ') + ')';
	}
    } else if (typeof form == "string") {
	return '"' + form + '"';
    } else if (form instanceof Symbol
	       && symbolMacros.hasOwnProperty(form.name)) {
	return symbolMacros[form.name]();
    } else
	return form;
}

// TODO: precedence?

var infix = {
    'and': '&&',
    'or': '||',
    'js:+': '+',
    'js:-': '-',
    'js:>': '>',
    'js:<': '<',
    'js:>=': '>=',
    'js:<=': '<=',
    'js:==': '==',
    'js:===': '==='
}

function restDeclaration (name, requiredArguments) {
    return 'var ' + name
	+ ' = Array.prototype.slice.call(arguments, '
	+ requiredArguments + ');\n';
}

function argumentNames (args) {
    return args.map(function (arg) {
	if (arg instanceof Array) {
	    return arg[0];
	} else
	    return arg;
    });
}

function requiredArguments (args) {
    function position (hashSymbol) {
	var result = args.indexOf(hashSymbol);
	if (result == -1) {
	    result = args.length;
	}
	return result;
    }
    var hashSymbolPositions =
	[HashSymbol.key, HashSymbol.rest, HashSymbol.values].map(position);
    var end = Math.min.apply(null, [args.length].concat(hashSymbolPositions));
    return args.slice(0, end);

}

function addReturn (forms) {
    // TODO: values
    // var firstValue = ... , restValues = ... ;
    // if (arguments.callee.caller.acceptsMultipleValues)
    //   arguments.callee.caller.multipleValues = restValues;
    // return firstValue;
    var last = forms.length - 1;
    forms[last] = [new Symbol('js:return'), forms[last]];
    return forms;
}

function functionDeclaration (name, args, body) {
    var documentation = "";
    if (typeof body[0] == 'string' && body.length > 1) {
	documentation = '/** \n';
	body.shift().split('\n').forEach(function (line) {
	    documentation += ' * ' + line + '\n';
	});
	documentation += ' */\n';
    }
    var rest = "";
    var restPosition = args.indexOf(HashSymbol.rest);
    if (restPosition >= 0) {
	rest = restDeclaration(args[restPosition + 1],
			       requiredArguments(args).length);
    }

    // TODO: keyword arguments, use reduce
    return (documentation +
	    'function ' + (name ? name + ' ' : '')
	    + '(' + argumentNames(requiredArguments(args)).join(', ') + ') '
	    + '{\n' + rest + compileAll(addReturn(body)) + ';\n}');
}

var macros = {
    // TODO: should be property of current module,
    //       and accessible as function
    'define-function': function (name, args) {
	var body = arguments.toArray().slice(2);
	if (!(name instanceof Symbol))
	    throw new Error('function\'s name should be a symbol: '
			    + JSON.stringify(name));
	return functionDeclaration(name, args, body);
    },
    'method': function (args) {
	var body = arguments.toArray().slice(1);
	return '(' + functionDeclaration("", args, body) + ')';
    },
    'list': function () {
	return '[' + arguments.toArray().map(compile).join(', ') + ']';
    },
    'js:call': function (name) {
	var args = arguments.toArray().slice(1);
	return name + '(' + args.map(compile).join(', ') + ')';
    },
    'js:new': function (name) {
	var args = arguments.toArray().slice(1);
	return 'new ' + name + '(' + args.map(compile).join(', ') + ')';
    },
    'define': function (name, value) {
	return "var " + name + " = " + compile(value);
    },
    'js:return': function (body) {
	return 'return ' + compile(body);
    },
    // TODO: bind multiple values
    // e.g. (bind ((foo bar baz (values 1 2 3)))
    // arguments.callee.acceptsMultipleValues = true;
    // (...) ? arguments.callee.MultipleValues :
    //         new Array([foo, bar, baz].length)
    // TODO: test multiple value bind with nested functions
    'bind': function (bindings) {
	var body = arguments.toArray().slice(1);
	var declarations = bindings.map(function (binding) {
	    return ([new Symbol('define')].concat(binding));
	});
	return ('(function () {\n' + compileAll(declarations, true)
		+ compileAll(addReturn(body)) + ';\n})()');
    },
    'js:get-property': function () {
	var elements = arguments.toArray();
	var object = elements[0];
	if (!(object instanceof Symbol || typeof object == "string")) {
	    object = compile(object);
	}
	return object +
	    elements.slice(1)
	    .map(function (element) {
		if (typeof element == 'string' &&
		    /^[a-zA-Z_]+$/.exec(element))
		{
		    return '.' + element;
		} else
		    return '[' + compile(element) + ']';
	    }).join('');
    },
    'begin': function () {
	return '(' + compileAll(arguments.toArray(), false, true) + ')';
    },
    'if': function (test, then, _else) {
	return '(' + compile(test) + ' ? '
	    + compile(then) + ' : ' + compile(_else) + ')';
    },
    'when': function (test, then) {
	return compile([new Symbol('if'), test, then, new Symbol('#f')]);
    },
    'js:defined': function (expression) {
	return '(typeof (' + compile(expression) + ') != "undefined")';
    },
    // FIXME
    'cond': function () {
	var cases = arguments.toArray();
	var _case = _case;
	if (_case[0].name == 'else:')
	    return compile(_case.splice(1));
	else if (cases.length == 1)
	    return compile(new Symbol('#f'));
	else
	    return compile([new Symbol('if'), _case[0],
			    _case.splice(1),
			    [new Symbol('cond')].concat(cases.splice(1))]);
    },
    'js:negative': function (object) {
	return '(- ' + object + ')';
    },
    'not': function (expression) {
	return '!' + compile(expression);
    },
    'js:identifier': function (name) {
	return ('' + name);
    },
    // statement!
    'js:for-in': function (variableAndExpression) {
	var body = arguments.toArray().slice(1);
	var variable = variableAndExpression[0];
	var expression = variableAndExpression[1];
	return 'for (var ' + variable + ' in ' + compile(expression) + ') {\n'
	    + compileAll(body, true) + '}';
    },
    // TODO:
    'handler-case': function (expression) {
	return compile([[new Symbol('method'), []]]);
    },
    // TODO: expand to (bind ((name (method (..
    'bind-methods': function () {
    },
    // TODO: define-method
}

var symbolMacros = {
    'js:null': function () { return 'null'; },
    '#f': function () { return 'false'; },
    '#t': function () { return 'true'; }
}

// interface

exports.compile = function (code) {
    var stream = new Stream("(\n" + code + "\n)");
    var reader = new Reader(stream);
    var forms = reader.read();
    return compileAll(forms);
}<commit_msg>refactored 'bind'<commit_after>
var primitives = require('./primitives');
var Symbol = primitives.Symbol, HashSymbol = primitives.HashSymbol;

var Reader = require('./reader').Reader;
var Stream = require('./stream').Stream;

// utils

Object.prototype.toArray = function () {
    return Array.prototype.slice.call(this);
};

// compiler

function compileAll (forms, all, comma) {
    var separator = ';\n';
    if (comma) {
	separator = ', ';
    }
    var result = forms.map(compile).join(separator);
    if (all && forms.length == 1) {
	result += (separator + '\n');
    }
    return result;
}

function compile (form) {
    if (form instanceof Array) {
	var head = form[0];
	var rest = form.slice(1);
	if (macros.hasOwnProperty(head.name)) {
	    return macros[head.name].apply(this, rest);
	} else if (infix.hasOwnProperty(head.name)) {
	    return rest.map(compile).join(' ' + infix[head.name] + ' ');
	} else {
	    return compile(head) + '(' + rest.map(compile).join(', ') + ')';
	}
    } else if (typeof form == "string") {
	return '"' + form + '"';
    } else if (form instanceof Symbol
	       && symbolMacros.hasOwnProperty(form.name)) {
	return symbolMacros[form.name]();
    } else
	return form;
}

// TODO: precedence?

var infix = {
    'and': '&&',
    'or': '||',
    'js:+': '+',
    'js:-': '-',
    'js:>': '>',
    'js:<': '<',
    'js:>=': '>=',
    'js:<=': '<=',
    'js:==': '==',
    'js:===': '==='
}

function restDeclaration (name, requiredArguments) {
    return 'var ' + name
	+ ' = Array.prototype.slice.call(arguments, '
	+ requiredArguments + ');\n';
}

function argumentNames (args) {
    return args.map(function (arg) {
	if (arg instanceof Array) {
	    return arg[0];
	} else
	    return arg;
    });
}

function requiredArguments (args) {
    function position (hashSymbol) {
	var result = args.indexOf(hashSymbol);
	if (result == -1) {
	    result = args.length;
	}
	return result;
    }
    var hashSymbolPositions =
	[HashSymbol.key, HashSymbol.rest, HashSymbol.values].map(position);
    var end = Math.min.apply(null, [args.length].concat(hashSymbolPositions));
    return args.slice(0, end);

}

function addReturn (forms) {
    // TODO: values
    // var firstValue = ... , restValues = ... ;
    // if (arguments.callee.caller.acceptsMultipleValues)
    //   arguments.callee.caller.multipleValues = restValues;
    // return firstValue;
    var last = forms.length - 1;
    forms[last] = [new Symbol('js:return'), forms[last]];
    return forms;
}

function functionDeclaration (name, args, body) {
    var documentation = "";
    if (typeof body[0] == 'string' && body.length > 1) {
	documentation = '/** \n';
	body.shift().split('\n').forEach(function (line) {
	    documentation += ' * ' + line + '\n';
	});
	documentation += ' */\n';
    }
    var rest = "";
    var restPosition = args.indexOf(HashSymbol.rest);
    if (restPosition >= 0) {
	rest = restDeclaration(args[restPosition + 1],
			       requiredArguments(args).length);
    }

    // TODO: keyword arguments, use reduce
    return (documentation +
	    'function ' + (name ? name + ' ' : '')
	    + '(' + argumentNames(requiredArguments(args)).join(', ') + ') '
	    + '{\n' + rest + compileAll(addReturn(body)) + ';\n}');
}

var macros = {
    // TODO: should be property of current module,
    //       and accessible as function
    'define-function': function (name, args) {
	var body = arguments.toArray().slice(2);
	if (!(name instanceof Symbol))
	    throw new Error('function\'s name should be a symbol: '
			    + JSON.stringify(name));
	return functionDeclaration(name, args, body);
    },
    'method': function (args) {
	var body = arguments.toArray().slice(1);
	return '(' + functionDeclaration("", args, body) + ')';
    },
    'list': function () {
	return '[' + arguments.toArray().map(compile).join(', ') + ']';
    },
    'js:call': function (name) {
	var args = arguments.toArray().slice(1);
	return name + '(' + args.map(compile).join(', ') + ')';
    },
    'js:new': function (name) {
	var args = arguments.toArray().slice(1);
	return 'new ' + name + '(' + args.map(compile).join(', ') + ')';
    },
    'define': function (name, value) {
	return "var " + name + " = " + compile(value);
    },
    'js:return': function (body) {
	return 'return ' + compile(body);
    },
    // TODO: bind multiple values
    // e.g. (bind ((foo bar baz (values 1 2 3)))
    // arguments.callee.acceptsMultipleValues = true;
    // (...) ? arguments.callee.MultipleValues :
    //         new Array([foo, bar, baz].length)
    // TODO: test multiple value bind with nested functions
    'bind': function (bindings) {
	var body = arguments.toArray().slice(1);
	var declarations = bindings.map(function (binding) {
	    return ([new Symbol('define')].concat(binding));
	});
	return compile([[new Symbol('method'), []]
			.concat(declarations)
			.concat(body)]);
    },
    'js:get-property': function () {
	var elements = arguments.toArray();
	var object = elements[0];
	if (!(object instanceof Symbol || typeof object == "string")) {
	    object = compile(object);
	}
	return object +
	    elements.slice(1)
	    .map(function (element) {
		if (typeof element == 'string' &&
		    /^[a-zA-Z_]+$/.exec(element))
		{
		    return '.' + element;
		} else
		    return '[' + compile(element) + ']';
	    }).join('');
    },
    'begin': function () {
	return '(' + compileAll(arguments.toArray(), false, true) + ')';
    },
    'if': function (test, then, _else) {
	return '(' + compile(test) + ' ? '
	    + compile(then) + ' : ' + compile(_else) + ')';
    },
    'when': function (test, then) {
	return compile([new Symbol('if'), test, then, new Symbol('#f')]);
    },
    'js:defined': function (expression) {
	return '(typeof (' + compile(expression) + ') != "undefined")';
    },
    // FIXME
    'cond': function () {
	var cases = arguments.toArray();
	var _case = _case;
	if (_case[0].name == 'else:')
	    return compile(_case.splice(1));
	else if (cases.length == 1)
	    return compile(new Symbol('#f'));
	else
	    return compile([new Symbol('if'), _case[0],
			    _case.splice(1),
			    [new Symbol('cond')].concat(cases.splice(1))]);
    },
    'js:negative': function (object) {
	return '(- ' + object + ')';
    },
    'not': function (expression) {
	return '!' + compile(expression);
    },
    'js:identifier': function (name) {
	return ('' + name);
    },
    // statement!
    'js:for-in': function (variableAndExpression) {
	var body = arguments.toArray().slice(1);
	var variable = variableAndExpression[0];
	var expression = variableAndExpression[1];
	return 'for (var ' + variable + ' in ' + compile(expression) + ') {\n'
	    + compileAll(body, true) + '}';
    },
    // TODO:
    'handler-case': function (expression) {
	return compile([[new Symbol('method'), []]]);
    },
    // TODO: expand to (bind ((name (method (..
    'bind-methods': function () {
    },
    // TODO: define-method
}

var symbolMacros = {
    'js:null': function () { return 'null'; },
    '#f': function () { return 'false'; },
    '#t': function () { return 'true'; }
}

// interface

exports.compile = function (code) {
    var stream = new Stream("(\n" + code + "\n)");
    var reader = new Reader(stream);
    var forms = reader.read();
    return compileAll(forms);
}<|endoftext|>


<commit_before>(function(global, factory) {
  // AMD. Register as an anonymous module.
  if (typeof define === 'function' && define.amd) {
    define(factory);
  }
  // Expose a global instead
  else {
    global.Localized = factory();
  }
}(this, function() {

  var _strings,
      _readyCallbacks = [],
      _requestedStrings = false;

  function fireReadyCallbacks() {
    // Fire all ready callbacks we have queued up.
    while(_readyCallbacks.length) {
      (_readyCallbacks.pop())();
    }
  }

  function ready(data) {
    function domReady() {
      // If the DOM isn't ready yet, repeat when it is
      if ( document.readyState !== "complete" ) {
        document.onreadystatechange = domReady;
        return;
      }
      document.onreadystatechange = null;
      _strings = data;

      fireReadyCallbacks();
    }

    domReady();
  }

  // Get the current lang from the document's HTML element, which the
  // server set when the page was first rendered. This saves us having
  // to pass extra locale info around on the URL.
  function getCurrentLang() {
    var html = document.querySelector( "html" );
    return html && html.lang ? html.lang : "en-US";
  }

  return {
    /**
     * gets the localized string for a given key
     */
    get: function(key) {
      if ( !_strings ) {
        console.error( "[goggles.webmaker.org] Error: string catalog not found." );
        return "";
      }
      return ( _strings[ key ] || "" );
    },

    /**
     * gets the current lang used for the given page, or en-US by default.
     */
    getCurrentLang: getCurrentLang,

    /**
     * initializes the strings locally (i.e., downloads if not already downloaded) and
     * queues a callback to be fired when the DOM + strings are ready. It is safe to
     * call ready() multiple times. For cache busting, pass noCache=true on the options arg.
     */
    ready: function(callback, options) {
      var noCache = !!options.noCache,
          url = options.url || '/strings/' + getCurrentLang();
      url = url + (noCache ? '?bust=' + Date.now() : '');

      if (!_requestedStrings) {
        _requestedStrings = true;
        _readyCallbacks.push(calback);

        var xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.onreadystatechange = function(){
          if (this.readyState !== 4) {
            return;
          }

          if (xhr.status !== 200) {
            console.error("Localized Error: HTTP error " + xhr.status);
            return;
          }

          try {
            ready(JSON.parse(this.responseText));
          } catch (err) {
            console.error("Localized Error: " + err);
          }
        };
        xhr.send(null);
      }

      if (this.isReady()) {
        fireReadyCallbacks();
      }
    },

    /**
     * returns true if the localized strings have been loaded and can be used.
     */
    isReady: function() {
      return !!_strings;
    }
  };
}));
<commit_msg>Make sure leading and trailing /s work right on URL arg<commit_after>(function(global, factory) {
  // AMD. Register as an anonymous module.
  if (typeof define === 'function' && define.amd) {
    define(factory);
  }
  // Expose a global instead
  else {
    global.Localized = factory();
  }
}(this, function() {

  var _strings,
      _readyCallbacks = [],
      _requestedStrings = false;

  function fireReadyCallbacks() {
    // Fire all ready callbacks we have queued up.
    while(_readyCallbacks.length) {
      (_readyCallbacks.pop())();
    }
  }

  function ready(data) {
    function domReady() {
      // If the DOM isn't ready yet, repeat when it is
      if ( document.readyState !== "complete" ) {
        document.onreadystatechange = domReady;
        return;
      }
      document.onreadystatechange = null;
      _strings = data;

      fireReadyCallbacks();
    }

    domReady();
  }

  // Get the current lang from the document's HTML element, which the
  // server set when the page was first rendered. This saves us having
  // to pass extra locale info around on the URL.
  function getCurrentLang() {
    var html = document.querySelector( "html" );
    return html && html.lang ? html.lang : "en-US";
  }

  return {
    /**
     * gets the localized string for a given key
     */
    get: function(key) {
      if ( !_strings ) {
        console.error( "[goggles.webmaker.org] Error: string catalog not found." );
        return "";
      }
      return ( _strings[ key ] || "" );
    },

    /**
     * gets the current lang used for the given page, or en-US by default.
     */
    getCurrentLang: getCurrentLang,

    /**
     * initializes the strings locally (i.e., downloads if not already downloaded) and
     * queues a callback to be fired when the DOM + strings are ready. It is safe to
     * call ready() multiple times. For cache busting, pass noCache=true on the options arg.
     */
    ready: function(callback, options) {
      var noCache = !!options.noCache,
          url = options.url || '/strings/';
      url = url.replace(/^\/?/, '/').replace(/\/?$/, '/');
      url = url + getCurrentLang();
      url = url + (noCache ? '?bust=' + Date.now() : '');

      if (!_requestedStrings) {
        _requestedStrings = true;
        _readyCallbacks.push(calback);

        var xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.onreadystatechange = function(){
          if (this.readyState !== 4) {
            return;
          }

          if (xhr.status !== 200) {
            console.error("Localized Error: HTTP error " + xhr.status);
            return;
          }

          try {
            ready(JSON.parse(this.responseText));
          } catch (err) {
            console.error("Localized Error: " + err);
          }
        };
        xhr.send(null);
      }

      if (this.isReady()) {
        fireReadyCallbacks();
      }
    },

    /**
     * returns true if the localized strings have been loaded and can be used.
     */
    isReady: function() {
      return !!_strings;
    }
  };
}));
<|endoftext|>


<commit_before>const Message = require('./../../orm/Message');
const m2e = require('./../lib/message2embed');
const bot = require('./../bot');
/**
 * This method should return the response directly to the channel
 * @param {*string array} params
 * @param {*message} message
 */
async function command(params, message) {
    if (params.length < 1)
        return message.reply("incorrect usage\nSyntax: ~quote <messageID>");
    let m = await Message.where('messageID', params[0]).fetch();
    if (m) {
        console.log(m);
        const ch = bot.channels.get(m.attributes.channel);
        m = ch.fetchMessage(m.attributes.messageID);
        ch.sendEmbed(m2e(m));
    }
}
/**
 * description of the command
 */
const description = "quotes a message via id";
/**
 * Define Exports
 */
module.exports = {
    execute: command,
    description: description
};
<commit_msg>Update quote.js<commit_after>const Message = require('./../../orm/Message');
const m2e = require('./../lib/message2embed');
const bot = require('./../bot');
/**
 * This method should return the response directly to the channel
 * @param {*string array} params
 * @param {*message} message
 */
async function command(params, message) {
    if (params.length < 1)
        return message.reply("incorrect usage\nSyntax: ~quote <messageID>");
    let m = await Message.where('messageID', params[0]).fetch();
    if (m) {
        console.log(m);
        const ch = bot.channels.get(m.attributes.channel);
        m = await ch.fetchMessage(m.attributes.messageID);
        console.log("fetching : "+m.id);
        ch.sendEmbed(m2e(m));
    }
}
/**
 * description of the command
 */
const description = "quotes a message via id";
/**
 * Define Exports
 */
module.exports = {
    execute: command,
    description: description
};
<|endoftext|>


<commit_before>/* 1. the modules needed to turn this into a STUDY */
const xutils = require("shield-studies-addon-utils");
const addonPrefs = require("sdk/simple-prefs").prefs;

/* 2. configuration / setup constants for the study.
 *  These are only ones needed, or supported
 */
const {quickCodes, modes} = require("./experiment-modes");

let variations = {};

Object.keys(quickCodes).forEach(function(v){
  variations[v] = function(){addonPrefs["shield.variation"] = v};
});

let variationsMod = {
  variations: variations,
  isEligible: function () {return true},
  cleanup: function () {}
};

const forSetup = {
  name: require("sdk/self").id, // unique for Telemetry
  choices: Object.keys(variationsMod.variations), // names of branches.
  duration: 30,   // in days,
  /* Get surveyUrl from Strategy + Insights */
  surveyUrl: "https://qsurvey.mozilla.com/s3/Shield-Study-Example-Survey"
};

// 3. Study Object (module singleton);
var ourConfig = xutils.xsetup(forSetup);
// branch is now chosen; change the url
let mode = modes[quickCodes[ourConfig.variation]];

ourConfig.surveyUrl = "https://qsurvey.mozilla.com/s3/cfr-end-of-study?"
         + [
            "coeff=" + mode.coeff,
            "moment=" + mode.moment,
            "rate_limit=" + mode.rateLimit
            ].join("&");

let thisStudy = new xutils.Study(ourConfig, variationsMod);

// 3a (optional). Watch for changes and reporting
xutils.Reporter.on("report",(d)=>console.log("telemetry", d));
thisStudy.on("change",(newState)=>console.log("newState:", newState));

/* 4. usual bootstrap / jetpack main function */
function main (options, callback) {
  xutils.generateTelemetryIdIfNeeded().then(function () {
    xutils.handleStartup(options, thisStudy);
  })
  // addon specific load code should go here, if there is additional.
  console.debug(`special addon loading code: ${options.loadReason}`)
  console.debug(JSON.stringify(addonPrefs, null, 2))
}

function onUnload (reason) {
  console.debug(`special addon unloading code: ${reason}`)
  xutils.handleOnUnload(reason, thisStudy);

  // special unload code, specific to addon if any.
  console.debug(`special addon unloading code: ${reason}`)
  console.debug(JSON.stringify(addonPrefs, null, 2))
}

/* 5. usual bootstrap addon exports */
exports.main = main;
exports.onUnload = onUnload
<commit_msg>Firefox Guide Study 1 survey link added<commit_after>/* 1. the modules needed to turn this into a STUDY */
const xutils = require("shield-studies-addon-utils");
const addonPrefs = require("sdk/simple-prefs").prefs;

/* 2. configuration / setup constants for the study.
 *  These are only ones needed, or supported
 */
const {quickCodes, modes} = require("./experiment-modes");

let variations = {};

Object.keys(quickCodes).forEach(function(v){
  variations[v] = function(){addonPrefs["shield.variation"] = v};
});

let variationsMod = {
  variations: variations,
  isEligible: function () {return true},
  cleanup: function () {}
};

const forSetup = {
  name: require("sdk/self").id, // unique for Telemetry
  choices: Object.keys(variationsMod.variations), // names of branches.
  duration: 30,   // in days,
  /* Get surveyUrl from Strategy + Insights */
  surveyUrl: "https://qsurvey.mozilla.com/s3/Firefox-Guide-Study-1-End-of-Study"
};

// 3. Study Object (module singleton);
var ourConfig = xutils.xsetup(forSetup);
// branch is now chosen; change the url
let mode = modes[quickCodes[ourConfig.variation]];

ourConfig.surveyUrl = "https://qsurvey.mozilla.com/s3/Firefox-Guide-Study-1-End-of-Study?"
         + [
            "coeff=" + mode.coeff,
            "moment=" + mode.moment,
            "rate_limit=" + mode.rateLimit
            ].join("&");

let thisStudy = new xutils.Study(ourConfig, variationsMod);

// 3a (optional). Watch for changes and reporting
xutils.Reporter.on("report",(d)=>console.log("telemetry", d));
thisStudy.on("change",(newState)=>console.log("newState:", newState));

/* 4. usual bootstrap / jetpack main function */
function main (options, callback) {
  xutils.generateTelemetryIdIfNeeded().then(function () {
    xutils.handleStartup(options, thisStudy);
  })
  // addon specific load code should go here, if there is additional.
  console.debug(`special addon loading code: ${options.loadReason}`)
  console.debug(JSON.stringify(addonPrefs, null, 2))
}

function onUnload (reason) {
  console.debug(`special addon unloading code: ${reason}`)
  xutils.handleOnUnload(reason, thisStudy);

  // special unload code, specific to addon if any.
  console.debug(`special addon unloading code: ${reason}`)
  console.debug(JSON.stringify(addonPrefs, null, 2))
}

/* 5. usual bootstrap addon exports */
exports.main = main;
exports.onUnload = onUnload
<|endoftext|>


<commit_before>var core = require('../../../');

core.Matrix.prototype.bitwiseNot = function() {
  var out = new core.Matrix();
  var args = Array.from(arguments);
  core.bitwiseNot.apply(global, args.slice(0, 1).concat(out, args.slice(1)));
  return out;
};
<commit_msg>fixed `bitwiseNot` operator<commit_after>var core = require('../../../');

core.Matrix.prototype.bitwiseNot = function() {
  var out = new core.Matrix();
  core.bitwiseNot.apply(global, [this, out].concat(Array.from(arguments)));
  return out;
};
<|endoftext|>


<commit_before>/**
 * @file Contain the description of the next classes:
 *

 *
[Validator]{@link Validator}

 *

 *
 * @author Pavel Dubenko
 *
 * @version 1.0.0
 */

/**
 * Validator.
 *
 * @constructor
 * @param {Element|string} form Form element.
 * @param {TabPane} tabPane Tab panels.
 */
var Validator = new Class(/** @lends Validator# */{
    // constructor
    initialize: function(form, tabPane) {
        /**
         * The form element.
         * @type {Element}
         */
        this.form = $(form);

        /**
         * The tab panels.
         * @type {TabPane}
         */
        this.tabPane = tabPane || null;
        this.prepareFloatFields();
    },

    /**
     * Prepare the fields with float values.
     * @function
     * @public
     */
    prepareFloatFields: function(){
        function prepareFunction(event){
            event.target.value = event.target.value.replace(/\,/, '.');
        }

        //Для всех field type=float(class=float)
        //меняем , на .
        this.form.getElements('.float').each(function(element){
            element.removeEvent('change', prepareFunction);
            element.addEvent('change', prepareFunction);
        });
    },

    /**
     * Remove the error from the invalid field.
     *
     * @function
     * @public
     * @param {Element} field Invalid field element (with the class <tt>'invalid'</tt>).
     */
    removeError: function(field){
        field = $(field);
        if (field.hasClass('invalid')) {
            field.removeClass('invalid');
            var errorDiv;
            if(errorDiv = field.getParent('.field').getElement('div.error')){
                errorDiv.destroy();
            }
        }
    },
    clearErrors: function(field){
        this.form.getElements('.field').each(this.removeError);
    },
    /**
     * Show the error message for specific field.
     *
     * @function
     * @public
     * @param {Element} field Make the field element invalid (add the class <tt>'invalid'</tt>).
     * @param {string} [message] Error message.
     */
    showError: function(field, message){
        field = $(field);
        this.removeError(field);
        field.addClass('invalid');
        new Element('div').addClass('error').appendText(message).inject(field.parentNode, 'after');
    },

    /**
     * Scroll to the field.
     *
     * @function
     * @public
     * @param {Element} field Field element.
     */
    scrollToElement: function(field){
        var context=document.getElement('.e-mainframe') || window;

        var scroll = new Fx.Scroll(context, {
            offset: {
                'x': -30,
                'y': -20
            },
            transition: Fx.Transitions.linear
        });

        scroll.toElement(field).chain(function(){
            try{
                field.focus()
            }catch(e){
                console.warn(e);
            }
        });
    },

    /**
     * Validate the field.
     * @param {Element} field Field element.
     * @returns {boolean} True, if the field was successful validated, otherwise - false.
     */
    validateElement: function(field){
        var result = true;
        var pattern,
            message;
        field = $(field);
        pattern = field.getProperty('nrgn:pattern');
        if (pattern
            && (message = field.getProperty('nrgn:message'))
            && !field.getProperty('disabled')
            && !field.hasClass('novalidation'))
        {
            var a = pattern.split('/');

            if (!new RegExp(a[1], a[2]).test(field.value)) {
            //if (!eval('field.value.match('+pattern+');')) {
                //Выводим информацию об ошибке
                this.showError(field, message);
                //Вешаем проверку правильности введения данных на onblur
                if(!field.getProperty('check')) {
                    field.addEvent('blur', this.validateElement.bind(this, field));
                    field.addEvent('keydown', this.removeError.bind(this, field));
                    field.setProperty('check', 'check');
                }
                result = false;
            } else {
                //Убираем информацию о предыдущей ошибке
                this.removeError(field);
            }
        }
        return result;
    },

    /**
     * Validate all fields.
     *
     * @function
     * @public
     * @returns {boolean} True if there were no errors, otherwise - false.
     */
    validate: function() {
        //Массив ошибочных полей
        var error = false,
            firstErrorField = null;

        //заполняем массив ошибочных полей
        new Elements(this.form.elements).each(function(field) {
            if(!this.validateElement(field) && !error) {
                //Нас интересует только первое поле
                firstErrorField = field;
                error = true;
            }
        }, this);

        //Если есть ошибки
        if (error) {
            //Если мы внутри табов
            //определяем таб первого ошибочного поля и переключаемся на этот таб
            if(this.tabPane){
                this.tabPane.show(this.tabPane.whereIs(firstErrorField))
            }
            //Скроллируем
            this.scrollToElement(firstErrorField);

            try {
                firstErrorField.focus()
            } catch (e) {
                console.warn(e);
            }
        }

        return !error;
    }
});<commit_msg>validator fix<commit_after>/**
 * @file Contain the description of the next classes:
 *

 *
[Validator]{@link Validator}

 *

 *
 * @author Pavel Dubenko
 *
 * @version 1.0.0
 */

/**
 * Validator.
 *
 * @constructor
 * @param {Element|string} form Form element.
 * @param {TabPane} tabPane Tab panels.
 */
var Validator = new Class(/** @lends Validator# */{
    // constructor
    initialize: function (form, tabPane) {
        /**
         * The form element.
         * @type {Element}
         */
        this.form = $(form);

        /**
         * The tab panels.
         * @type {TabPane}
         */
        this.tabPane = tabPane || null;
        this.prepareFloatFields();
    },

    /**
     * Prepare the fields with float values.
     * @function
     * @public
     */
    prepareFloatFields: function () {
        function prepareFunction(event) {
            event.target.value = event.target.value.replace(/\,/, '.');
        }

        //Для всех field type=float(class=float)
        //меняем , на .
        this.form.getElements('.float').each(function (element) {
            element.removeEvent('change', prepareFunction);
            element.addEvent('change', prepareFunction);
        });
    },

    /**
     * Remove the error from the invalid field.
     *
     * @function
     * @public
     * @param {Element} field Invalid field element (with the class <tt>'invalid'</tt>).
     */
    removeError: function (field) {
        field = $(field);
        if (field.hasClass('invalid')) {
            field.removeClass('invalid');
            var errorDiv;
            if (errorDiv = field.getParent('.field').getElement('div.error')) {
                errorDiv.destroy();
            }
        }
    },
    clearErrors: function (field) {
        this.form.getElements('.field').each(this.removeError);
    },
    /**
     * Show the error message for specific field.
     *
     * @function
     * @public
     * @param {Element} field Make the field element invalid (add the class <tt>'invalid'</tt>).
     * @param {string} [message] Error message.
     */
    showError: function (field, message) {
        field = $(field);
        this.removeError(field);
        field.addClass('invalid');
        new Element('div', {
            'class': 'error',
            'html': message,
            'events': {
                'click': this.removeError.pass(field, this)
            }
        }).inject(field.parentNode, 'after');
    },

    /**
     * Scroll to the field.
     *
     * @function
     * @public
     * @param {Element} field Field element.
     */
    scrollToElement: function (field) {
        var context = document.getElement('.e-mainframe') || window;

        var scroll = new Fx.Scroll(context, {
            offset: {
                'x': -30,
                'y': -20
            },
            transition: Fx.Transitions.linear
        });

        scroll.toElement(field).chain(function () {
            try {
                field.focus()
            } catch (e) {
                console.warn(e);
            }
        });
    },

    /**
     * Validate the field.
     * @param {Element} field Field element.
     * @returns {boolean} True, if the field was successful validated, otherwise - false.
     */
    validateElement: function (field) {
        var result = true;
        var pattern,
            message;
        field = $(field);
        pattern = field.getProperty('nrgn:pattern');
        if (pattern
            && (message = field.getProperty('nrgn:message'))
            && !field.getProperty('disabled')
            && !field.hasClass('novalidation')) {
            var a = pattern.split('/');

            if (!new RegExp(a[1], a[2]).test(field.value)) {
                //if (!eval('field.value.match('+pattern+');')) {
                //Выводим информацию об ошибке
                this.showError(field, message);
                //Вешаем проверку правильности введения данных на onblur
                if (!field.getProperty('check')) {
                    field.addEvent('blur', this.validateElement.bind(this, field));
                    field.addEvent('keydown', this.removeError.bind(this, field));
                    field.setProperty('check', 'check');
                }
                result = false;
            } else {
                //Убираем информацию о предыдущей ошибке
                this.removeError(field);
            }
        }
        return result;
    },

    /**
     * Validate all fields.
     *
     * @function
     * @public
     * @returns {boolean} True if there were no errors, otherwise - false.
     */
    validate: function () {
        //Массив ошибочных полей
        var error = false,
            firstErrorField = null;

        //заполняем массив ошибочных полей
        new Elements(this.form.elements).each(function (field) {
            if (!this.validateElement(field) && !error) {
                //Нас интересует только первое поле
                firstErrorField = field;
                error = true;
            }
        }, this);

        //Если есть ошибки
        if (error) {
            //Если мы внутри табов
            //определяем таб первого ошибочного поля и переключаемся на этот таб
            if (this.tabPane) {
                this.tabPane.show(this.tabPane.whereIs(firstErrorField))
            }
            //Скроллируем
            this.scrollToElement(firstErrorField);

            try {
                firstErrorField.focus()
            } catch (e) {
                console.warn(e);
            }
        }

        return !error;
    }
});<|endoftext|>


<commit_before>import React, { Component } from 'react';
import {Button, Glyphicon, Panel} from 'react-bootstrap';
import update from 'immutability-helper';
import Experiment from './Experiment.js'
import SelectableDocument from './SelectableDocument.js'
import Example from './SelectableDocumentExample.js'
import Instructions from './Instructions.js'
import SegmentList from './SegmentList';

import './SelectAcceptabilityApp.css';

class App extends Experiment {
  constructor(props) {
    super(props);
    this.handleValueChanged = this.handleValueChanged.bind(this);
    this.handleInstructionsUpdated = this.handleInstructionsUpdated.bind(this);
    this.setUpNextTimer = this.setUpNextTimer.bind(this);
    this.moveToNextTask = this.moveToNextTask.bind(this);
  }

  setUpNextTimer() {
    //50 characters ~ 1s
    const PER_CHAR = 1000./50;
    const time = this.props.contents[this.state.currentIdx].text.length * PER_CHAR;
    this.nextTimer = window.setInterval(this.moveToNextTask, time);
  }

  moveToNextTask() {
    if (this.nextTimer) {
      window.clearInterval(this.nextTimer);
      this.nextTimer = undefined;
    }

    this.setState(state => {
        state = update(state, {canNext: {$set: true}});
        if (this.state.currentIdx == this.props.contents.length-1) {
          state = update(state, {canSubmit: {$set: true}});
        }
        return state;
      });
  }

  componentDidMount() {
    super.componentDidMount();
    this.setUpNextTimer();
  }

  title() {
    return (
Identify mistakes in the short summary below
);
  }
  subtitle() {
    return (
Highlight grammatical or language errors
);
  }

  handleInstructionsUpdated(field, evt) {
    const value = {};
    value[field] = evt;

    this.setState(state => update(state, {instructionAnswers: {$merge: value}}));
  }

  instructionsVersion() {
    return '20171224';
  }

  instructionsIsComplete() {
    const questions = ["verb-1", "missing-1", "missing-2", "nonsense-1", "grammatical-1",];
    return this.instructionsComplete() || questions.every(q => this.state.instructionAnswers[q] === true);
  }

  instructions() {
    let paymentNote;
    if (!this.instructionsIsComplete()) {
      paymentNote = (
Before you proceed with the HIT, you will need to complete the tutorial below (you only need to do this once though!).
        The tutorial should take about 5-8 minutes to complete and you will get a (one-time) $0.75 bonus for completing it.

);
    }

    return (

      Imagine that you are a grade-school English
      teacher reading short essays written by your students: we'd like
      you to highlight any mistakes you find in each sentence.

      {paymentNote}

How to use the interface

Click or select some text to mark it as ungrammatical or otherwise poor use of language.

If you want to undo a highlight, simply click on it to remove it.

Sometimes the words written by the student are
        undecipherable and are displayed as ▃ . Here, try to be generous
        to the student and imagine what the word is likely to have been.
        For example, in "Leighton ▃ is the first female jockey in the history of Polo.", the ▃  is probably the person's last name.

Finally, the casing of some of these sentences may be off:
      for example, in "from a man purporting to be Robert
      durst", "durst" should be capitalized. Please be
      lenient and only mark such examples if you genuinely can't
      understand what was written.

Tutorial / Examples

      For the rest of the instructions, we have a tutorial with a couple
      of questions and a few quizzes. While the task certainly has
      subjective elements to it, in order to complete the tutorial you
      will need to highlight the same errors that we have. Don't worry
      though, we'll provide some hints to help you along the way!

      <Example
        title="1. A good sentence"
        leadUp="Let's start with a sentence we think is perfectly alright and hence does not need any highlighting."
        text="Yom Hazikaron, held this year on April 22, is Israel's official Memorial Day."
        successPrompt=""
      />

      <Example
        title="2. Bad verb conjugation (example)"
        leadUp="In the following sentence, there is a problem with the verb conjugation problem."
        text="A man |is stood| slumped over in a doorway as two women walk by as they celebrate the New Year."
        successPrompt="The sentence should either be 'A man is standing slumped over...' or 'A man stands slumped over...', so we'd like you to highlight either 'is stood' or just 'stood'."
      />

      <Example
        title="3. Bad verb conjugation (quiz)"
        leadUp="Now, try this next example:"
        text="Mario Balotelli |was| missed Liverpool's 4-1 defeat against Arsenal on Saturday."
        successPrompt={It should probably have been 'had missed' or just 'missed'. Another alternative could have been 'Mario Balotelli was missed at Liverpool's ...'.}
        editable={!this.instructionsComplete()}
        onStateChanged={(evt) => {this.handleInstructionsUpdated("verb-1", evt)}}
      />

      <Example
        title="4. Missing words (quiz)"
        leadUp={(
          Next, let's look at an example of a missing word: just select
          the space in between two words if you think something should
          be added here. How about you try this one on your own?
          (Remember, think of ▃  as a "fill-in-the-blank" word (here
            it the first ▃  might be Joy's last name and the second ▃
            is probably valve).)
          )}
        text="Joy ▃ died after she managed to manoeuvre herself over| |edge of her crib and a 'safety ▃ ' cut off the oxygen to her brain."
        successPrompt={It should probably have been 'over the edge'}
        editable={!this.instructionsComplete()}
        onStateChanged={(evt) => {this.handleInstructionsUpdated("missing-1", evt)}}
      />

      <Example
        title="5. Missing punctuation (quiz)"
        leadUp="Here's another one, this time with some missing punctuation."
        text="Paramedics were stretched to the limit| |and in Cambridge, a territorial army field hospital was set-up to deal with drunk partygoers."
        successPrompt={We need a comma before the 'and' to separate the two clauses.}
        editable={!this.instructionsComplete()}
        onStateChanged={(evt) => {this.handleInstructionsUpdated("missing-2", evt)}}
      />

      <Example
        title="6. Dealing with nonsense (example)"
        leadUp="Alright, now we'll look at some harder examples. Some of the sentences in the task may have entire parts that really don't make any sense. We'd like you select the smallest region (or regions) that you think are the culprit: imagine that if your student saw these red marks they may know how to fix it. That said, don't be afraid to highlight the whole sentence if it doesn't make sense though."
        text="Paramedics were stretched to the limit and |Cambridge territorial hospital in field a is the|."
        successPrompt=""
        editable={false}
      />

      <Example
        title="7. Dealing with nonsense (example)"
        leadUp="That said, don't be afraid to highlight the whole sentence if it doesn't make sense though."
        text="|▃ ▃ is the largest of ▃ ▃ - a ▃ tomb and part of an ancient ▃ settlement - stands by the mystery|."
        successPrompt=""
        editable={false}
      />

      <Example
        title="8. Dealing with nonsense (quiz)"
        leadUp="Alright, now try this one."
        text="|The arrests of a police officer, a police officer,| was arrested in the street, police say."
        successPrompt=""
        wrongPrompt="As a hint, we think that the latter half of the sentence is more sensible than the first."
        editable={!this.instructionsComplete()}
        onStateChanged={(evt) => {this.handleInstructionsUpdated("nonsense-1", evt)}}
      />

      <Example
        title="9. Grammatical but incoherent sentences (example)"
        leadUp="Finally, let's look at some errors that are perfectly grammatical but still make no sense."
        text="Floyd Mayweather and Manny Pacquiao will fight |Manny Pacquiao| in the match at the MGM Grand Garden Arena on May 2."
        successPrompt="Here, it's simply not possible for Manny Pacquaio to be fighting Manny Pacquaio in a match."
        editable={false}
      />

      <Example
        title="10. Grammatical but incoherent sentences (quiz)"
        leadUp="Alright, this is that last example! Give it a go!"
        text="Miami-dade Fire Rescue Battalion Chief Al Cruz |grew to be more than 10 times that within the next 24 hours|. The fire had burned nearly 2,000 acres and was 50% contained, the fire department says."
        successPrompt={Here, it makes no sense that Al Cruz 'grew' in size. The sentence probably wants to say '... Al Cruz said that the fire would grow to be more ...'.}
        editable={!this.instructionsComplete()}
        onStateChanged={(evt) => {this.handleInstructionsUpdated("grammatical-1", evt)}}
      />

);
  }

  initState(props) {
    let state = super.initState(props);
    state = update(state, {
      output: {$merge: {
        selections: props.contents.map(_ => []),
      }},
      currentIdx: {$set: 0},
      canNext: {$set: 0},
      instructionAnswers: {$set: {}}
    });

    if (props._output) {
      state = update(state, {
        output: {$merge: props._output},
      });
    }

    return state;
  }

  handleValueChanged(evt) {
    const value = evt;
    this.setState(state => {
      let diff = {output: {selections: {}}};
      diff.output.selections[state.currentIdx] = {$set: SelectableDocument.updateState(state.output.selections[state.currentIdx], value)};
      return update(state, diff);
    });
  }

  handleSubmit(evt) {
    if (this.state.canSubmit) {
      console.assert(this.state.currentIdx == this.props.contents.length-1);
      return true;
    } else if (this.state.canNext) {
      console.assert(this.state.currentIdx < this.props.contents.length-1);

      this.setState(state => update(state, {$merge: {
        currentIdx: state.currentIdx+1,
        canNext: false,
        canSubmit: false,
      }}));
      this.setUpNextTimer();
      evt.preventDefault();
      return false;
    } else {
      evt.preventDefault();
      return false;
    }
  }

  renderContents() {
    const text =  this.props.contents[this.state.currentIdx].text;
    const selections = this.state.output.selections[this.state.currentIdx];
    return (<Panel
              id="document"
              bsStyle="primary"
              header={Please read the summary below and highlight any grammatical or language errors}
              >
          <SelectableDocument
              id="document-contents"
              text={text}
              onValueChanged={this.handleValueChanged}
              selections={selections}
              editable={true}
              />
        </Panel>);
  }

  renderSubmit() {
    if (this.state.currentIdx < this.props.contents.length-1) {
      return (
        <Button type='button' disabled={!this.state.canNext} bsSize="large" bsStyle="primary" onClick={this.handleSubmit}><Glyphicon glyph="forward" /> Next ({this.state.currentIdx+1} / {this.props.contents.length}) </Button>
        );
    } else {
      return (
        <Button type='submit' disabled={!this.state.canSubmit} bsSize="large" bsStyle="success" onClick={this.handleSubmit}><Glyphicon glyph="ok" /> Submit</Button>
      );
    }
  }
}

App.defaultProps = {
  contents: [
    {id:"", text: "This is test sentence 1.", reference: "This is another sentence 1."},
    {id:"", text: "This is test sentence 2.", reference: "This is another sentence 2."},
    {id:"", text: "This is test sentence 3.", reference: "This is another sentence 3."},
  ],
  estimatedTime: 400,
  reward: 1.25,
}

export default App;
<commit_msg>Updated aceptability app to have better instructions<commit_after>import React, { Component } from 'react';
import {Button, Glyphicon, Panel, Well} from 'react-bootstrap';
import update from 'immutability-helper';
import Experiment from './Experiment.js'
import SelectableDocument from './SelectableDocument.js'
import SegmentList from './SegmentList';

import './SelectAcceptabilityApp.css';

class App extends Experiment {
  constructor(props) {
    super(props);
    this.handleValueChanged = this.handleValueChanged.bind(this);
    this.setUpNextTimer = this.setUpNextTimer.bind(this);
    this.moveToNextTask = this.moveToNextTask.bind(this);
  }

  setUpNextTimer() {
    //50 characters ~ 1s
    const PER_CHAR = 1000./50;
    const time = this.props.contents[this.state.currentIdx].text.length * PER_CHAR;
    this.nextTimer = window.setInterval(this.moveToNextTask, time);
  }

  moveToNextTask() {
    if (this.nextTimer) {
      window.clearInterval(this.nextTimer);
      this.nextTimer = undefined;
    }

    this.setState(state => {
        state = update(state, {canNext: {$set: true}});
        if (this.state.currentIdx == this.props.contents.length-1) {
          state = update(state, {canSubmit: {$set: true}});
        }
        return state;
      });
  }

  componentDidMount() {
    super.componentDidMount();
    this.setUpNextTimer();
  }

  instructionsVersion() {
    return '20180122';
  }

  instructions() {
    return (<InstructionContents
      isFirstTime={this.state.firstView}
      editable={!this.state.instructionsComplete}
      onValueChanged={(val) => this.setState({instructionsComplete: val})}
      />);
  }

  title() {
    return (
Identify mistakes in the short summary below
);
  }
  subtitle() {
    return (
Highlight grammatical or language errors
);
  }

  initState(props) {
    let state = super.initState(props);
    state = update(state, {
      output: {$merge: {
        selections: props.contents.map(_ => []),
      }},
      currentIdx: {$set: 0},
      canNext: {$set: 0},
    });

    if (props._output) {
      state = update(state, {
        output: {$merge: props._output},
      });
    }

    return state;
  }

  handleValueChanged(evt) {
    const value = evt;
    this.setState(state => {
      let diff = {output: {selections: {}}};
      diff.output.selections[state.currentIdx] = {$set: SelectableDocument.updateState(state.output.selections[state.currentIdx], value)};
      return update(state, diff);
    });
  }

  handleSubmit(evt) {
    if (this.state.canSubmit) {
      console.assert(this.state.currentIdx == this.props.contents.length-1);
      return true;
    } else if (this.state.canNext) {
      console.assert(this.state.currentIdx < this.props.contents.length-1);

      this.setState(state => update(state, {$merge: {
        currentIdx: state.currentIdx+1,
        canNext: false,
        canSubmit: false,
      }}));
      this.setUpNextTimer();
      evt.preventDefault();
      return false;
    } else {
      evt.preventDefault();
      return false;
    }
  }

  renderContents() {
    const text =  this.props.contents[this.state.currentIdx].text;
    const selections = this.state.output.selections[this.state.currentIdx];
    return (<Panel
              id="document"
              bsStyle="primary"
              header={Please read the summary below and highlight any grammatical or language errors}
              >
          <SelectableDocument
              id="document-contents"
              text={text}
              onValueChanged={this.handleValueChanged}
              selections={selections}
              editable={true}
              />
        </Panel>);
  }

  renderSubmit() {
    if (this.state.currentIdx < this.props.contents.length-1) {
      return (
        <Button type='button' disabled={!this.state.canNext} bsSize="large" bsStyle="primary" onClick={this.handleSubmit}><Glyphicon glyph="forward" /> Next ({this.state.currentIdx+1} / {this.props.contents.length}) </Button>
        );
    } else {
      return (
        <Button type='submit' disabled={!this.state.canSubmit} bsSize="large" bsStyle="success" onClick={this.handleSubmit}><Glyphicon glyph="ok" /> Submit</Button>
      );
    }
  }
}

App.defaultProps = {
  contents: [
    {id:"", text: "This is test sentence 1.", reference: "This is another sentence 1."},
    {id:"", text: "This is test sentence 2.", reference: "This is another sentence 2."},
    {id:"", text: "This is test sentence 3.", reference: "This is another sentence 3."},
  ],
  estimatedTime: 400,
  reward: 1.25,
}

class Example extends Component {
  constructor(props) {
    super(props);

    let [text, expectedSelections] = this._split(this.props.text);

    this.state = {
      text: text,
      expectedSelections: expectedSelections,
      selections: [],
    }

    this.handleValueChanged = this.handleValueChanged.bind(this);
  }

  handleValueChanged(evt) {
    const value = evt;
    this.setState(state => update(state, {selections: {$set: SelectableDocument.updateState(state.selections, value)}}), () => {
        this.props.onStateChanged(SegmentList.equals(this.state.expectedSelections, this.state.selections))
    });
  }

  _split(txt) {
    let text = "";
    let expectedSelections = [];

    let start = -1;
    for (let char of txt) {
      if (char === "|") {
        if (start === -1) {
          start = text.length;
        } else {
          expectedSelections.push([start, text.length]);
          start = -1;
        }
      } else {
        text += char;
      }
    }
    return [text, expectedSelections];
  }

  render() {
    let title = this.props.title && (
{this.props.title}
);

    let text = this.state.text;
    let expectedSelections = this.state.expectedSelections;

    let bsStyle, selections, handleValueChanged, well;
    if (this.props.editable) {
      handleValueChanged = this.handleValueChanged;
      selections = this.state.selections;
      if (selections.length === 0) {
        bsStyle = "primary";
      } else if (SegmentList.equals(expectedSelections, selections)) {
        bsStyle = "success";
        well = That's right! {this.props.successPrompt}
      } else if (SegmentList.contains(expectedSelections, selections)) {
        bsStyle = "warning";
        well = Almost! We're expecting something bigger. {this.props.biggerPrompt}
      } else if (SegmentList.contains(selections, expectedSelections)) {
        bsStyle = "warning";
        well = Almost! We're expecting something smaller. {this.props.smallerPrompt}
      } else {
        bsStyle = "danger";
        well = Hmm.. that doesn't seem quite right. {this.props.wrongPrompt}
      }
    } else {
      selections = expectedSelections;
      bsStyle = "success";
      handleValueChanged = (() => {});
      well = this.props.successPrompt && {this.props.successPrompt};
    }

    well = well && (<Well bsStyle={bsStyle}>{well}</Well>);

    return (
      <Panel header={title} bsStyle={bsStyle}>

{this.props.leadUp}

        <SelectableDocument
          id={this.props.id + "-document"}
          text={text}
          selections={selections}
          onValueChanged={handleValueChanged}
          />
        {well}

      </Panel>
    );
  }
}

Example.defaultProps = {
  id: "#example",
  title: "#. Description of example.",
  text: "Yom Hazikaron, held this year on April 22, is Israel's official Memorial Day.",
  editable: false,
  onStateChanged: () => {},
  successPrompt: "",
  almostPrompt: "You've selected more than what you needed to!",
  wrongPrompt: "",
}

class InstructionContents extends Component {
  constructor(props) {
    super(props);

    this.state = this.initState(props);
    this.handleValueChanged = this.handleValueChanged.bind(this);
  }
  key = {
    "verb-1": true,
    "missing-1": true,
    "missing-2": true,
    "nonsense-1": true,
    "grammatical-1": true,
  };

  initState(props) {
    let ret = {};
    if (props.isFirstTime) {
      for (let k in this.key) {
        ret[k] = undefined;
      }
    } else  {
      ret = this.key;
    }
    return ret;
  }

  handleValueChanged(update_) {
    this.setState(update_, () => Object.keys(this.key).every(k => this.state[k]) && this.props.onValueChanged(true));
  }

  render() {
    let paymentNote = (this.props.isFirstTime)
      ? (
Before you proceed with the HIT, you will need to complete the tutorial below (you only need to do this once though!).
        The tutorial should take about 5-8 minutes to complete and you will get a (one-time) $0.75 bonus for completing it.

)
      : undefined;

    return (

      Imagine that you are a grade-school English
      teacher reading short essays written by your students: we'd like
      you to highlight any mistakes you find in each sentence.

      {paymentNote}

How to use the interface

Click or select some text to mark it as ungrammatical or otherwise poor use of language.

If you want to undo a highlight, simply click on it to remove it.

Sometimes the words written by the student are
        undecipherable and are displayed as ▃ . Here, try to be generous
        to the student and imagine what the word is likely to have been.
        For example, in "Leighton ▃ is the first female jockey in the history of Polo.", the ▃  is probably the person's last name.

Finally, the casing of some of these sentences may be off:
      for example, in "from a man purporting to be Robert
      durst", "durst" should be capitalized. Please be
      lenient and only mark such examples if you genuinely can't
      understand what was written.

Tutorial / Examples

      For the rest of the instructions, we have a tutorial with a couple
      of questions and a few quizzes. While the task certainly has
      subjective elements to it, in order to complete the tutorial you
      will need to highlight the same errors that we have. Don't worry
      though, we'll provide some hints to help you along the way!

      <Example
        title="1. A good sentence"
        leadUp="Let's start with a sentence we think is perfectly alright and hence does not need any highlighting."
        text="Yom Hazikaron, held this year on April 22, is Israel's official Memorial Day."
        successPrompt=""
      />

      <Example
        title="2. Bad verb conjugation (example)"
        leadUp="In the following sentence, there is a problem with the verb conjugation problem."
        text="A man |is stood| slumped over in a doorway as two women walk by as they celebrate the New Year."
        successPrompt="The sentence should either be 'A man is standing slumped over...' or 'A man stands slumped over...', so we'd like you to highlight either 'is stood' or just 'stood'."
      />

      <Example
        title="3. Bad verb conjugation (quiz)"
        leadUp="Now, try this next example:"
        text="Mario Balotelli |was| missed Liverpool's 4-1 defeat against Arsenal on Saturday."
        successPrompt={It should probably have been 'had missed' or just 'missed'. Another alternative could have been 'Mario Balotelli was missed at Liverpool's ...'.}
        editable={this.props.editable}
        onStateChanged={val => {this.handleValueChanged({"verb-1": val})}}
      />

      <Example
        title="4. Missing words (quiz)"
        leadUp={(
          Next, let's look at an example of a missing word: just select
          the space in between two words if you think something should
          be added here. How about you try this one on your own?
          (Remember, think of ▃  as a "fill-in-the-blank" word (here
            it the first ▃  might be Joy's last name and the second ▃
            is probably valve).)
          )}
        text="Joy ▃ died after she managed to manoeuvre herself over| |edge of her crib and a 'safety ▃ ' cut off the oxygen to her brain."
        successPrompt={It should probably have been 'over the edge'}
        editable={this.props.editable}
        onStateChanged={val => {this.handleValueChanged({"missing-1": val})}}
      />

      <Example
        title="5. Missing punctuation (quiz)"
        leadUp="Here's another one, this time with some missing punctuation."
        text="Paramedics were stretched to the limit| |and in Cambridge, a territorial army field hospital was set-up to deal with drunk partygoers."
        successPrompt={We need a comma before the 'and' to separate the two clauses.}
        editable={this.props.editable}
        onStateChanged={val => {this.handleValueChanged({"missing-2": val})}}
      />

      <Example
        title="6. Dealing with nonsense (example)"
        leadUp="Alright, now we'll look at some harder examples. Some of the sentences in the task may have entire parts that really don't make any sense. We'd like you select the smallest region (or regions) that you think are the culprit: imagine that if your student saw these red marks they may know how to fix it. That said, don't be afraid to highlight the whole sentence if it doesn't make sense though."
        text="Paramedics were stretched to the limit and |Cambridge territorial hospital in field a is the|."
        successPrompt=""
        editable={false}
      />

      <Example
        title="7. Dealing with nonsense (example)"
        leadUp="That said, don't be afraid to highlight the whole sentence if it doesn't make sense though."
        text="|▃ ▃ is the largest of ▃ ▃ - a ▃ tomb and part of an ancient ▃ settlement - stands by the mystery|."
        successPrompt=""
        editable={false}
      />

      <Example
        title="8. Dealing with nonsense (quiz)"
        leadUp="Alright, now try this one."
        text="|The arrests of a police officer, a police officer,| was arrested in the street, police say."
        successPrompt=""
        wrongPrompt="As a hint, we think that the latter half of the sentence is more sensible than the first."
        editable={this.props.editable}
        onStateChanged={val => {this.handleValueChanged({"nonsense-1": val})}}
      />

      <Example
        title="9. Grammatical but incoherent sentences (example)"
        leadUp="Finally, let's look at some errors that are perfectly grammatical but still make no sense."
        text="Floyd Mayweather and Manny Pacquiao will fight |Manny Pacquiao| in the match at the MGM Grand Garden Arena on May 2."
        successPrompt="Here, it's simply not possible for Manny Pacquaio to be fighting Manny Pacquaio in a match."
        editable={false}
      />

      <Example
        title="10. Grammatical but incoherent sentences (quiz)"
        leadUp="Alright, this is that last example! Give it a go!"
        text="Miami-dade Fire Rescue Battalion Chief Al Cruz |grew to be more than 10 times that within the next 24 hours|. The fire had burned nearly 2,000 acres and was 50% contained, the fire department says."
        successPrompt={Here, it makes no sense that Al Cruz 'grew' in size. The sentence probably wants to say '... Al Cruz said that the fire would grow to be more ...'.}
        editable={this.props.editable}
        onStateChanged={val => {this.handleValueChanged({"grammatical-1": val})}}
      />

);
  }
}

InstructionContents.defaultProps = {
  isFirstTime: false,
  editable: false,
  onValueChanged: () => {},
}

export default App;
<|endoftext|>


<commit_before>'use strict'

const Slapp = require('slapp')
const Context = require('slapp-context-beepboop')
const ConvoStore = require('slapp-convo-beepboop')

module.exports = (server, db) => {
  let app = Slapp({
    verify_token: process.env.SLACK_VERIFY_TOKEN,
    context: Context(),
    convo_store: ConvoStore()
  })

  // Middleware
  app.use((msg, next) => {
    if (msg.body.event.user)
    {
      db.saveConvo(msg.body.event.user, msg.body, (err, convo) => {
        console.log(err)
      })
    }
    next()
  })

  var HELP_TEXT = `
  I will respond to the following messages:
  \`help\` - to see this message
  \`hi\` - to demonstrate a conversation that tracks state.
  \`thanks\` - to demonstrate a simple response.
  \`<type-any-other-text>\` - to demonstrate a random emoticon response, some of the time :wink:.
  \`attachment\` - to see a Slack attachment message.
  `

//*********************************************
// Setup different handlers for messages
//*********************************************

  app.message('store', ['mention', 'direct_message'], (msg, text, greeting) => {

    msg
      .say(`Conversation model stored!`)
      .route('store_step_2')
  })

  app.route('store_step_2', (msg, state) => {
    var text = (msg.body.event && msg.body.event.text) || ''
    msg.say(['Okay'])
  })

  app.message('test', ['direct_mention', 'direct_message'], (msg, text, greeting) => {
    msg
      .say(`How are you?`)
      .route('handleHowAreYou')  // where to route the next msg in the conversation
  })

  // register a route handler
  app.route('handleHowAreYou', (msg) => {
    // respond with a random entry from array
    msg.say(['Me too', 'Noted', 'That is interesting'])
  })

  app
    .message('motivators', ['direct_mention', 'direct_message'], (msg, text) => {

      db.getMotivations(msg.body.event.user, , (err, motivations) => {
        if (err) {
          console.error(err)
        }
        var motivators = motivations
      })

      if (motivators)
      {
        msg
          .say('You have motivations set.')
      }
      else
      {
        msg
          .say(`What is something that motivates you to create?`)
          // sends next event from user to this route, passing along state
          .route('motivates')
      }

    })
  app.route('motivates', (msg, state) => {
      var text = (msg.body.event && msg.body.event.text) || ''

      // user may not have typed text as their next action, ask again and re-route
      if (!text) {
        return msg
          .say("Whoops, I'm still waiting to hear a response.")
          .say('What is something that motivates you to create?')
          .route('motivates', state)
      }

      // add their response to state
      state.motivates = text

      msg
        .say(`Ok. And what's something that discourages you from creating?`)
        .route('discourages', state)
    })
  app.route('discourages', (msg, state) => {
      var text = (msg.body.event && msg.body.event.text) || ''

      // user may not have typed text as their next action, ask again and re-route
      if (!text) {
        return msg
          .say("I'm eagerly awaiting to hear something that discourages you from creating.")
          .route('discourages', state)
      }

      // add their response to state
      state.discourages = text

      // Store the responses
      db.saveMotivations(msg.body.event.user, { 'motivates' : state.motivates , 'discourages' : state.discourages }, (err, convo) => {
        console.log(err)
      })

      msg
        .say('Thanks for sharing.')
        .say(`Do more of this: `+state.motivates+'. Do less of this: '+state.discourages)
      // At this point, since we don't route anywhere, the "conversation" is over
    })

  // response to the user typing "help"
  app.message('help', ['mention', 'direct_message'], (msg) => {
    msg.say(HELP_TEXT)
  })

  // Test response for boxes
  app.message('yesno', (msg) => {
    msg.say({
      text: '',
      attachments: [
        {
          text: '',
          fallback: 'Yes or No?',
          callback_id: 'yesno_callback',
          actions: [
            { name: 'answer', text: 'Yes', type: 'button', value: 'yes' },
            { name: 'answer', text: 'No',  type: 'button',  value: 'no' }
          ]
        }]
      })
  })

  app.action('yesno_callback', 'answer', (msg, value) => {
    msg.respond(msg.body.response_url, `${value} is a good choice!`)
  })

  // "Conversation" flow that tracks state - kicks off when user says hi, hello or hey
  app
    .message('^(hi|hello|hey)$', ['direct_mention', 'direct_message'], (msg, text) => {
      msg
        .say(`${text}, how are you?`)
        // sends next event from user to this route, passing along state
        .route('how-are-you', { greeting: text })
    })
    .route('how-are-you', (msg, state) => {
      var text = (msg.body.event && msg.body.event.text) || ''

      // user may not have typed text as their next action, ask again and re-route
      if (!text) {
        return msg
          .say("Whoops, I'm still waiting to hear how you're doing.")
          .say('How are you?')
          .route('how-are-you', state)
      }

      // add their response to state
      state.status = text

      msg
        .say(`Ok then. What's your favorite color?`)
        .route('color', state)
    })
    .route('color', (msg, state) => {
      var text = (msg.body.event && msg.body.event.text) || ''

      // user may not have typed text as their next action, ask again and re-route
      if (!text) {
        return msg
          .say("I'm eagerly awaiting to hear your favorite color.")
          .route('color', state)
      }

      // add their response to state
      state.color = text

      msg
        .say('Thanks for sharing.')
        .say(`Here's what you've told me so far: \`\`\`${JSON.stringify(state)}\`\`\``)
      // At this point, since we don't route anywhere, the "conversation" is over
    })

  // Can use a regex as well
  app.message(/^(thanks|thank you)/i, ['mention', 'direct_message'], (msg) => {
    // You can provide a list of responses, and a random one will be chosen
    // You can also include slack emoji in your responses
    msg.say([
      "You're welcome :smile:",
      'You bet',
      ':+1: Of course',
      'Anytime :sun_with_face: :full_moon_with_face:'
    ])
  })

  // demonstrate returning an attachment...
  app.message('attachment', ['mention', 'direct_message'], (msg) => {
    msg.say({
      text: 'Check out this amazing attachment! :confetti_ball: ',
      attachments: [{
        text: 'Slapp is a robust open source library that sits on top of the Slack APIs',
        title: 'Slapp Library - Open Source',
        image_url: 'https://storage.googleapis.com/beepboophq/_assets/bot-1.22f6fb.png',
        title_link: 'https://beepboophq.com/',
        color: '#7CD197'
      }]
    })
  })

  // response to the user asking "how did you get here?"
  app.message('how did you get here?', ['mention', 'direct_message'], (msg) => {
    msg.say('Team Rocket! :rocket:')
  })

  // "Creative motivators" flow

  app
    .message('^(hi|hello|hey)$', ['direct_mention', 'direct_message'], (msg, text) => {
      msg
        .say(text + ', how are you?')
        .route('how-are-you', { text }, 60)
    })
    .route('how-are-you', (msg, state) => {
      var resp = msg.body.event && msg.body.event.text

      if (/good/i.test(resp)) {
        msg
          .say(['Great! Ready?', ':smile: Are you sure?'])
          .route('how-are-you', state, 60)
      } else {
        msg
          .say('Me too', () => msg.say(`Thanks for saying ${state.text}`))
      }
    })
    .message('^(thanks|thank you)', ['mention', 'direct_message'], (msg) => {
      msg.say(["You're welcome", 'Of course'])
    })
    .message('help', ['direct_message', 'direct_mention'], (msg) => {
      let help = `I will respond to the following messages:
\`@slapp hi||hello\` for a greeting.
\`mention me by name in a message\` to demonstrate detecting a mention.
\`@slapp help\` to see this again.`

      msg.say(help)
    })
    .message('fix it', 'ambient', (msg) => {
      msg.say('https://www.youtube.com/watch?v=yo3uxqwTxk0')
    })
    .message(/.*/, 'mention', (msg) => {
      msg.say('You really do care about me. :heart:')
    })

    app.attachToExpress(server)

  return app
}
<commit_msg>Removes trailing comma.<commit_after>'use strict'

const Slapp = require('slapp')
const Context = require('slapp-context-beepboop')
const ConvoStore = require('slapp-convo-beepboop')

module.exports = (server, db) => {
  let app = Slapp({
    verify_token: process.env.SLACK_VERIFY_TOKEN,
    context: Context(),
    convo_store: ConvoStore()
  })

  // Middleware
  app.use((msg, next) => {
    if (msg.body.event.user)
    {
      db.saveConvo(msg.body.event.user, msg.body, (err, convo) => {
        console.log(err)
      })
    }
    next()
  })

  var HELP_TEXT = `
  I will respond to the following messages:
  \`help\` - to see this message
  \`hi\` - to demonstrate a conversation that tracks state.
  \`thanks\` - to demonstrate a simple response.
  \`<type-any-other-text>\` - to demonstrate a random emoticon response, some of the time :wink:.
  \`attachment\` - to see a Slack attachment message.
  `

//*********************************************
// Setup different handlers for messages
//*********************************************

  app.message('store', ['mention', 'direct_message'], (msg, text, greeting) => {

    msg
      .say(`Conversation model stored!`)
      .route('store_step_2')
  })

  app.route('store_step_2', (msg, state) => {
    var text = (msg.body.event && msg.body.event.text) || ''
    msg.say(['Okay'])
  })

  app.message('test', ['direct_mention', 'direct_message'], (msg, text, greeting) => {
    msg
      .say(`How are you?`)
      .route('handleHowAreYou')  // where to route the next msg in the conversation
  })

  // register a route handler
  app.route('handleHowAreYou', (msg) => {
    // respond with a random entry from array
    msg.say(['Me too', 'Noted', 'That is interesting'])
  })

  app
    .message('motivators', ['direct_mention', 'direct_message'], (msg, text) => {

      db.getMotivations(msg.body.event.user, (err, motivations) => {
        if (err) {
          console.error(err)
        }
        var motivators = motivations
      })

      if (motivators)
      {
        msg
          .say('You have motivations set.')
      }
      else
      {
        msg
          .say(`What is something that motivates you to create?`)
          // sends next event from user to this route, passing along state
          .route('motivates')
      }

    })
  app.route('motivates', (msg, state) => {
      var text = (msg.body.event && msg.body.event.text) || ''

      // user may not have typed text as their next action, ask again and re-route
      if (!text) {
        return msg
          .say("Whoops, I'm still waiting to hear a response.")
          .say('What is something that motivates you to create?')
          .route('motivates', state)
      }

      // add their response to state
      state.motivates = text

      msg
        .say(`Ok. And what's something that discourages you from creating?`)
        .route('discourages', state)
    })
  app.route('discourages', (msg, state) => {
      var text = (msg.body.event && msg.body.event.text) || ''

      // user may not have typed text as their next action, ask again and re-route
      if (!text) {
        return msg
          .say("I'm eagerly awaiting to hear something that discourages you from creating.")
          .route('discourages', state)
      }

      // add their response to state
      state.discourages = text

      // Store the responses
      db.saveMotivations(msg.body.event.user, { 'motivates' : state.motivates , 'discourages' : state.discourages }, (err, convo) => {
        console.log(err)
      })

      msg
        .say('Thanks for sharing.')
        .say(`Do more of this: `+state.motivates+'. Do less of this: '+state.discourages)
      // At this point, since we don't route anywhere, the "conversation" is over
    })

  // response to the user typing "help"
  app.message('help', ['mention', 'direct_message'], (msg) => {
    msg.say(HELP_TEXT)
  })

  // Test response for boxes
  app.message('yesno', (msg) => {
    msg.say({
      text: '',
      attachments: [
        {
          text: '',
          fallback: 'Yes or No?',
          callback_id: 'yesno_callback',
          actions: [
            { name: 'answer', text: 'Yes', type: 'button', value: 'yes' },
            { name: 'answer', text: 'No',  type: 'button',  value: 'no' }
          ]
        }]
      })
  })

  app.action('yesno_callback', 'answer', (msg, value) => {
    msg.respond(msg.body.response_url, `${value} is a good choice!`)
  })

  // "Conversation" flow that tracks state - kicks off when user says hi, hello or hey
  app
    .message('^(hi|hello|hey)$', ['direct_mention', 'direct_message'], (msg, text) => {
      msg
        .say(`${text}, how are you?`)
        // sends next event from user to this route, passing along state
        .route('how-are-you', { greeting: text })
    })
    .route('how-are-you', (msg, state) => {
      var text = (msg.body.event && msg.body.event.text) || ''

      // user may not have typed text as their next action, ask again and re-route
      if (!text) {
        return msg
          .say("Whoops, I'm still waiting to hear how you're doing.")
          .say('How are you?')
          .route('how-are-you', state)
      }

      // add their response to state
      state.status = text

      msg
        .say(`Ok then. What's your favorite color?`)
        .route('color', state)
    })
    .route('color', (msg, state) => {
      var text = (msg.body.event && msg.body.event.text) || ''

      // user may not have typed text as their next action, ask again and re-route
      if (!text) {
        return msg
          .say("I'm eagerly awaiting to hear your favorite color.")
          .route('color', state)
      }

      // add their response to state
      state.color = text

      msg
        .say('Thanks for sharing.')
        .say(`Here's what you've told me so far: \`\`\`${JSON.stringify(state)}\`\`\``)
      // At this point, since we don't route anywhere, the "conversation" is over
    })

  // Can use a regex as well
  app.message(/^(thanks|thank you)/i, ['mention', 'direct_message'], (msg) => {
    // You can provide a list of responses, and a random one will be chosen
    // You can also include slack emoji in your responses
    msg.say([
      "You're welcome :smile:",
      'You bet',
      ':+1: Of course',
      'Anytime :sun_with_face: :full_moon_with_face:'
    ])
  })

  // demonstrate returning an attachment...
  app.message('attachment', ['mention', 'direct_message'], (msg) => {
    msg.say({
      text: 'Check out this amazing attachment! :confetti_ball: ',
      attachments: [{
        text: 'Slapp is a robust open source library that sits on top of the Slack APIs',
        title: 'Slapp Library - Open Source',
        image_url: 'https://storage.googleapis.com/beepboophq/_assets/bot-1.22f6fb.png',
        title_link: 'https://beepboophq.com/',
        color: '#7CD197'
      }]
    })
  })

  // response to the user asking "how did you get here?"
  app.message('how did you get here?', ['mention', 'direct_message'], (msg) => {
    msg.say('Team Rocket! :rocket:')
  })

  // "Creative motivators" flow

  app
    .message('^(hi|hello|hey)$', ['direct_mention', 'direct_message'], (msg, text) => {
      msg
        .say(text + ', how are you?')
        .route('how-are-you', { text }, 60)
    })
    .route('how-are-you', (msg, state) => {
      var resp = msg.body.event && msg.body.event.text

      if (/good/i.test(resp)) {
        msg
          .say(['Great! Ready?', ':smile: Are you sure?'])
          .route('how-are-you', state, 60)
      } else {
        msg
          .say('Me too', () => msg.say(`Thanks for saying ${state.text}`))
      }
    })
    .message('^(thanks|thank you)', ['mention', 'direct_message'], (msg) => {
      msg.say(["You're welcome", 'Of course'])
    })
    .message('help', ['direct_message', 'direct_mention'], (msg) => {
      let help = `I will respond to the following messages:
\`@slapp hi||hello\` for a greeting.
\`mention me by name in a message\` to demonstrate detecting a mention.
\`@slapp help\` to see this again.`

      msg.say(help)
    })
    .message('fix it', 'ambient', (msg) => {
      msg.say('https://www.youtube.com/watch?v=yo3uxqwTxk0')
    })
    .message(/.*/, 'mention', (msg) => {
      msg.say('You really do care about me. :heart:')
    })

    app.attachToExpress(server)

  return app
}
<|endoftext|>


<commit_before>// we have problems if the page has changed the definition of Set or Array
// http://www.polyvore.com/ does this for example
var __brzl_framesDone = new Set();
var __brzl_popup_re = /window.open\(\s*(['"])(.*?)\1/;
var __brzl_compileOutlinks = function(frame) {
    __brzl_framesDone.add(frame);
    var outlinks = [];
    try {
        if (frame && frame.document) {
            outlinks = Array.prototype.slice.call(
                frame.document.querySelectorAll('a[href], area[href]'));
            popups = Array.prototype.slice.call(
                frame.document.querySelectorAll('a[onclick], a[ondblclick]'));
            if (popups && popups.length > 0) {
                for (var p=0; p < popups.length; p++) {
                    if (popups[p].onclick){
                        m = popups[p].onclick.toString().match(__brzl_popup_re);
                    } else {
                        m = popups[p].ondblclick.toString().match(__brzl_popup_re);
                    }
                    if (m) {
                        outlinks.push(m[2]);
                    }
                }
            }
            for (var i = 0; i < frame.frames.length; i++) {
                if (frame.frames[i] && !__brzl_framesDone.has(frame.frames[i])) {
                    outlinks = outlinks.concat(
                        __brzl_compileOutlinks(frame.frames[i]));
                }
            }
        }
    } catch (e) {
        console.log("exception looking at frame" + frame + ": " + e);
    }

    return outlinks;
}
__brzl_compileOutlinks(window).join('\n');
<commit_msg>faster regex match<commit_after>// we have problems if the page has changed the definition of Set or Array
// http://www.polyvore.com/ does this for example
var __brzl_framesDone = new Set();
var __brzl_popup_re = /window.open\(\s*(['"])(.*?)\1/;
var __brzl_compileOutlinks = function(frame) {
    __brzl_framesDone.add(frame);
    var outlinks = [];
    try {
        if (frame && frame.document) {
            outlinks = Array.prototype.slice.call(
                frame.document.querySelectorAll('a[href], area[href]'));
            popups = Array.prototype.slice.call(
                frame.document.querySelectorAll('a[onclick], a[ondblclick]'));
            if (popups && popups.length > 0) {
                for (var p=0; p < popups.length; p++) {
                    if (popups[p].onclick){
                        m = __brzl_popup_re[Symbol.match](popups[p].onclick.toString());
                    } else {
                        m = __brzl_popup_re[Symbol.match](popups[p].ondblclick.toString());
                    }
                    if (m) {
                        outlinks.push(m[2]);
                    }
                }
            }
            for (var i = 0; i < frame.frames.length; i++) {
                if (frame.frames[i] && !__brzl_framesDone.has(frame.frames[i])) {
                    outlinks = outlinks.concat(
                        __brzl_compileOutlinks(frame.frames[i]));
                }
            }
        }
    } catch (e) {
        console.log("exception looking at frame" + frame + ": " + e);
    }

    return outlinks;
}
__brzl_compileOutlinks(window).join('\n');
<|endoftext|>


<commit_before>/**
 * Appcelerator Common Library for Node.js
 * Copyright (c) 2012 by Appcelerator, Inc. All Rights Reserved.
 * Please see the LICENSE file for information about licensing.
 *
 *

 * The messaging module provides communication capabilities with other processes via a RESTful client-server
 * architecture. The transport mechanism is pluggable so that different transports can be swapped out without changing
 * client code. Messages are passed inside of one or more protocols. The top-level protocol is defined below, and any
 * other parent/lower-level protocols are defined on a transport by transport basis.
 *

 * Request:
 *		{
 *			messageType: [value],
 *			data: [value],
 *		}
 *
 *	messageType: always a string, and is the value of messageType supplied to {@link module:messaging#MessagingInterface.listen} or {@link module:messaging#MessagingInterface.send}
 *	data: any valid JSON value
 *
 * Response:
 *
 *		{
 *			error: [value]
 *		}
 *
 *		or
 *
 *		{
 *			data: [value]
 *		}
 *
 *	error: error is a string if an error occured, null otherwise
 *	data: any valid JSON value
 * Note: a response must always sent, even if there is no data to send, because the message serves as a request ACK.
 *

 *

 *
 * @module messaging
 */

var transports,
	path = require('path'),
	wrench = require('wrench'),
	transportRegex = /Transport\.js/,
	i, len;

// Find the list of transports
transports = wrench.readdirSyncRecursive(path.join(__dirname, 'messaging'));
for(i = 0, len = transports.length; i < len; i++) {
	transports[i] = transports[i].replace(transportRegex, '');
}

/**
 * Creates a messaging interface over the specified transport
 *
 * @method
 * @param {String} transportType The transport to use. Must be 'stdio' currently
 */
exports.create = function(transportType) {
	if (transports.indexOf(transportType) === -1) {
		throw new Error('Invalid messaging transport type "' + transportType + '"');
	}
	return new MessagingInterface(transportType);
};

/**
 * @classdesc A messaging interface for communicating with an external service
 *
 * @constructor
 * @name module:messaging#MessagingInterface
 */
function MessagingInterface(transportType) {
	this._transportType = transportType;
	this._listeners = {};
}

/**
 * Opens the messaging interface
 *
 * @method
 * @name module:messaging#MessagingInterface.open
 */
MessagingInterface.prototype.open = function (options) {
	if (this._transport) {
		throw new Error('Cannot open a messaging interface that is already open');
	}
	this._transport = new (require('./messaging/' + this._transportType + 'Transport'))(function (requestData, response) {
		try {
			requestData = JSON.parse(requestData);
			if (!requestData.messageType) {
				throw 'missing message type';
			}
		} catch(e) {
			response(JSON.stringify({
				error: 'Malformed message: ' + e
			}));
			return;
		}
		if (this._listeners[requestData.messageType]) {
			this._listeners[requestData.messageType](requestData, function (error, data) {
				response(JSON.stringify({
					error: error,
					data: data
				}));
			});
		} else {
			response({
				error: 'No listener available to handle request'
			});
		}
	}.bind(this), options);
};

/**
 * Closes the messaging interface
 *
 * @method
 * @name module:messaging#MessagingInterface.close
 */
MessagingInterface.prototype.close = function () {
	this._transport.close();
	this._transport = null;
};

/**
 * @method
 * @name module:messaging#MessagingInterface~listenCallback
 * @param {Object} request The request object
 * @param {Any} request.data The data received, after having been parsed via JSON.parse
 * @param {module:messaging~listenCallbackResponse} response The response object
 */
/**
 * @method
 * @name module:messaging#MessagingInterface~listenCallbackResponse
 * @param {String|undefined} error The error, if one occured. Anything falsey is understood to mean no error occured, and
 *		the value is converted to undefined
 * @param {Any|undefined} data The data, if any. The value is ignored if an error is supplied
 */
/**
 * Listens for a message from Studio. Note: only one listener per message type is allowed because multiple listeners
 * would send multiple responses to the sender
 *
 * @method
 * @name module:messaging#MessagingInterface.listen
 * @param {String} messageType The name of the message to listen for
 * @param {module:messaging#MessagingInterface~listenCallback} callback The callback to fire when a message arrives. The callback is passed
 *		two parameters: request and response
 */
MessagingInterface.prototype.listen = function (messageType, callback) {
	this._listeners[messageType] = callback;
};

/**
 * @method
 * @name module:messaging#MessagingInterface~sendCallback
 * @param {String|undefined} error The error message, if one occured, else undefined
 * @param {Any|undefined} data The data, if an error did not occur, else undefined
 */
/**
 * Sends a message to Studio
 *
 * @method
 * @name module:messaging#MessagingInterface.send
 * @param {String|undefined} messageType The name of the message to send
 * @param {Any|undefined} data The data to send. Must be JSON.stringify-able (i.e. no cyclic structures). Can be primitive or
 *		undefined, although undefined is converted to null
 * @param {module:messaging#MessagingInterface~sendCallback} callback The callback to fire once the transmission is complete or
 *		has errored. The error parameter is null if no error occured, or a string indicating the error. The data
 *		parameter is null if an error occured, or any type of data (including null) if no error occured.
 * @throws {Error} An exception is thrown if send is called while the interface is closed
 */
MessagingInterface.prototype.send = function (messageType, data, callback) {
	if (!this._transport) {
		throw new Error('Attempted to send data over a closed messaging interface');
	}
	this._transport.send(JSON.stringify({
		messageType: messageType,
		data: typeof data === 'undefined' ? null : data
	}), function (response) {
		try {
			response = JSON.parse(response);
		} catch(e) {
			response = {
				error: 'Malformed message: ' + e
			};
		}
		if (callback) {
			callback(response.error, response.data);
		}
	});
};<commit_msg>Fixed a bug in messaging<commit_after>/**
 * Appcelerator Common Library for Node.js
 * Copyright (c) 2012 by Appcelerator, Inc. All Rights Reserved.
 * Please see the LICENSE file for information about licensing.
 *
 *

 * The messaging module provides communication capabilities with other processes via a RESTful client-server
 * architecture. The transport mechanism is pluggable so that different transports can be swapped out without changing
 * client code. Messages are passed inside of one or more protocols. The top-level protocol is defined below, and any
 * other parent/lower-level protocols are defined on a transport by transport basis.
 *

 * Request:
 *		{
 *			messageType: [value],
 *			data: [value],
 *		}
 *
 *	messageType: always a string, and is the value of messageType supplied to {@link module:messaging#MessagingInterface.listen} or {@link module:messaging#MessagingInterface.send}
 *	data: any valid JSON value
 *
 * Response:
 *
 *		{
 *			error: [value]
 *		}
 *
 *		or
 *
 *		{
 *			data: [value]
 *		}
 *
 *	error: error is a string if an error occured, null otherwise
 *	data: any valid JSON value
 * Note: a response must always sent, even if there is no data to send, because the message serves as a request ACK.
 *

 *

 *
 * @module messaging
 */

var transports,
	path = require('path'),
	wrench = require('wrench'),
	transportRegex = /Transport\.js/,
	i, len;

// Find the list of transports
transports = wrench.readdirSyncRecursive(path.join(__dirname, 'messaging'));
for(i = 0, len = transports.length; i < len; i++) {
	transports[i] = transports[i].replace(transportRegex, '');
}

/**
 * Creates a messaging interface over the specified transport
 *
 * @method
 * @param {String} transportType The transport to use. Must be 'stdio' currently
 */
exports.create = function(transportType) {
	if (transports.indexOf(transportType) === -1) {
		throw new Error('Invalid messaging transport type "' + transportType + '"');
	}
	return new MessagingInterface(transportType);
};

/**
 * @classdesc A messaging interface for communicating with an external service
 *
 * @constructor
 * @name module:messaging#MessagingInterface
 */
function MessagingInterface(transportType) {
	this._transportType = transportType;
	this._listeners = {};
}

/**
 * Opens the messaging interface
 *
 * @method
 * @name module:messaging#MessagingInterface.open
 */
MessagingInterface.prototype.open = function (options) {
	if (this._transport) {
		throw new Error('Cannot open a messaging interface that is already open');
	}
	this._transport = new (require('./messaging/' + this._transportType + 'Transport'))(function (requestData, response) {
		try {
			requestData = JSON.parse(requestData);
			if (!requestData.messageType) {
				throw 'missing message type';
			}
		} catch(e) {
			response(JSON.stringify({
				error: 'Malformed message: ' + e
			}));
			return;
		}
		if (this._listeners[requestData.messageType]) {
			this._listeners[requestData.messageType](requestData, function (error, data) {
				response(JSON.stringify({
					error: error,
					data: data
				}));
			});
		} else {
			response(JSON.stringify({
				error: 'No listener available to handle request'
			}));
		}
	}.bind(this), options);
};

/**
 * Closes the messaging interface
 *
 * @method
 * @name module:messaging#MessagingInterface.close
 */
MessagingInterface.prototype.close = function () {
	this._transport.close();
	this._transport = null;
};

/**
 * @method
 * @name module:messaging#MessagingInterface~listenCallback
 * @param {Object} request The request object
 * @param {Any} request.data The data received, after having been parsed via JSON.parse
 * @param {module:messaging~listenCallbackResponse} response The response object
 */
/**
 * @method
 * @name module:messaging#MessagingInterface~listenCallbackResponse
 * @param {String|undefined} error The error, if one occured. Anything falsey is understood to mean no error occured, and
 *		the value is converted to undefined
 * @param {Any|undefined} data The data, if any. The value is ignored if an error is supplied
 */
/**
 * Listens for a message from Studio. Note: only one listener per message type is allowed because multiple listeners
 * would send multiple responses to the sender
 *
 * @method
 * @name module:messaging#MessagingInterface.listen
 * @param {String} messageType The name of the message to listen for
 * @param {module:messaging#MessagingInterface~listenCallback} callback The callback to fire when a message arrives. The callback is passed
 *		two parameters: request and response
 */
MessagingInterface.prototype.listen = function (messageType, callback) {
	this._listeners[messageType] = callback;
};

/**
 * @method
 * @name module:messaging#MessagingInterface~sendCallback
 * @param {String|undefined} error The error message, if one occured, else undefined
 * @param {Any|undefined} data The data, if an error did not occur, else undefined
 */
/**
 * Sends a message to Studio
 *
 * @method
 * @name module:messaging#MessagingInterface.send
 * @param {String|undefined} messageType The name of the message to send
 * @param {Any|undefined} data The data to send. Must be JSON.stringify-able (i.e. no cyclic structures). Can be primitive or
 *		undefined, although undefined is converted to null
 * @param {module:messaging#MessagingInterface~sendCallback} callback The callback to fire once the transmission is complete or
 *		has errored. The error parameter is null if no error occured, or a string indicating the error. The data
 *		parameter is null if an error occured, or any type of data (including null) if no error occured.
 * @throws {Error} An exception is thrown if send is called while the interface is closed
 */
MessagingInterface.prototype.send = function (messageType, data, callback) {
	if (!this._transport) {
		throw new Error('Attempted to send data over a closed messaging interface');
	}
	this._transport.send(JSON.stringify({
		messageType: messageType,
		data: typeof data === 'undefined' ? null : data
	}), function (response) {
		try {
			response = JSON.parse(response);
		} catch(e) {
			response = {
				error: 'Malformed message: ' + e
			};
		}
		if (callback) {
			callback(response.error, response.data);
		}
	});
};<|endoftext|>