<commit_before>//
// HLF Hover Intent Extension
// ==========================
// [Tests](../../tests/js/hover-intent.html)
//
// The `hoverIntent` extension normalizes DOM events associated with mouse enter
// and leave interaction. It prevents the 'thrashing' of attached behaviors (ex:
// non-cancel-able animations) when matching mouse input arrives at frequencies
// past the threshold. It is heavily inspired by Brian Cherne's jQuery plugin of
// the same name (github.com/briancherne/jquery-hoverIntent).
(function(root, attach) {
  //
  // § __UMD__
  // - When AMD, register the attacher as an anonymous module.
  // - When Node or Browserify, set module exports to the attach result.
  // - When browser globals (root is window), Just run the attach function.
  //
  if (typeof define === 'function' && define.amd) {
    define(['hlf/core'], attach);
  } else if (typeof exports === 'object') {
    module.exports = attach(require('hlf/core'));
  } else {
    attach(hlf);
  }
})(this, function(hlf) {
  //
  // Namespace
  // ---------
  //
  // It takes some more boilerplate to write the extension. Any of this additional
  // support API is put into a extension specific namespace under `hlf`, which in
  // this case is __hlf.hoverIntent__.
  //
  // - __debug__ toggles debug logging for all instances of an extension.
  // - __toString__ helps to namespace when registering any DOM names.
  // - __attrName__, __className__, __eventName__ helpers are all attached to
  //   the namespace on extension creation, along with the __extension__ itself.
  //
  // The extension's __defaults__ are available as reference. Also note that _the
  // extension instance gets extended with the options_.
  //
  // - __interval__ is the millis to wait before deciding intent. `300` is the
  //   default to reduce more thrashing.
  //
  // - __sensitivity__ is the pixel threshold for mouse travel between polling
  //   intervals. With the minimum sensitivity threshold of 1, the mouse must
  //   not move between intervals. With higher values yield more false positives.
  //   `8` is the default to allow more flexibility.
  //
  // The events dispatched are the name-spaced `enter` and `leave` events. They
  // try to match system mouse events where possible and include values for:
  // `pageX`, `pageY`, `relatedTarget`.
  //
  hlf.hoverIntent = {
    debug: true,
    defaults: {
      interval: 300,
      sensitivity: 8,
    },
    toString(context) {
      switch (context) {
        case 'event': return 'hlfhi';
        case 'data': return 'hlf-hi';
        default: return 'hlf-hi';
      }
    },
  };
  //
  // HoverIntent
  // -----------
  //
  // To summarize the implementation, the `_onMouseOver` handler is the start of
  // the intent 'life-cycle', with state being the default. It records the mouse
  // coordinates, sets up a delayed intent check, and guards against unneeded
  // checking. Meanwhile, about every frame, the `_onMouseMove` handler tracks
  // the current mouse coordinates. If the `_onMouseLeave` handler runs before
  // the delayed check, the check and subsequent behavior get canceled as state
  // resets to default. Otherwise, if the check of the stored mouse coordinates
  // against `sensitivity` passes, an `enter` event gets dispatched, ensuring
  // a `leave` event will too during `_onMouseLeave`.
  //
  class HoverIntent {
    constructor(element, options) {
      this.eventListeners = {
        'mouseleave': this._onMouseLeave,
        'mousemove': this._onMouseMove,
        'mouseover': this._onMouseOver,
      };
    }
    init() {
      this._setDefaultState();
    }
    deinit() {
      this._setDefaultState();
    }
    //
    // § __Internal__
    //
    _dispatchHoverEvent(on, mouseEvent) {
      const { mouse: { x, y } } = this;
      let type = on ? 'enter' : 'leave';
      this.dispatchCustomEvent(type, {
        pageX: x.current,
        pageY: y.current,
        relatedTarget: mouseEvent.relatedTarget,
      });
      this.debugLog(type, x.current, y.current, Date.now() % 100000);
    }
    _onMouseLeave(event) {
      if (this.intentional) {
        this.debugLog('teardown');
        this._dispatchHoverEvent(false, event);
      }
      this._setDefaultState();
    }
    _onMouseMove(event) {
      if (this.trackTimeout != null) { return; }
      this.trackTimeout = setTimeout(() => {
        this.debugLog('track');
        let { mouse: { x, y } } = this;
        x.current = event.pageX;
        y.current = event.pageY;
        this.trackTimeout = null;
      }, 16);
    }
    _onMouseOver(event) {
      if (this.intentional) { return; }
      if (event.target !== this.element) { return; }
      if (this.timeout != null) { return; }
      this.debugLog('setup');
      this.timeout = setTimeout(() => {
        this._setState(event);
        if (this.intentional) {
          this._dispatchHoverEvent(true, event);
        }
      }, this.interval);
    }
    _setDefaultState() {
      this.debugLog('reset');
      this.intentional = false;
      this.mouse = {
        x: { current: 0, previous: 0 },
        y: { current: 0, previous: 0 },
      };
      clearTimeout(this.timeout);
      clearTimeout(this.trackTimeout);
      this.timeout = null;
      this.trackTimeout = null;
    }
    _setState(event) {
      this.debugLog('update');
      let { mouse: { x, y } } = this;
      this.intentional = (
        Math.abs(x.previous - x.current) + Math.abs(y.previous - y.current) >
        this.sensitivity
      );
      x.previous = event.pageX;
      y.previous = event.pageY;
      this.timeout = null;
    }
  }
  //
  // § __Attaching__
  //
  return hlf.createExtension({
    name: 'hoverIntent',
    namespace: hlf.hoverIntent,
    apiClass: HoverIntent,
    autoBind: true,
    autoListen: true,
    baseMethodGroups: ['event'],
    compactOptions: true,
  });
});
<commit_msg>Minor hover-intent mouse checking fix-up.<commit_after>//
// HLF Hover Intent Extension
// ==========================
// [Tests](../../tests/js/hover-intent.html)
//
// The `hoverIntent` extension normalizes DOM events associated with mouse enter
// and leave interaction. It prevents the 'thrashing' of attached behaviors (ex:
// non-cancel-able animations) when matching mouse input arrives at frequencies
// past the threshold. It is heavily inspired by Brian Cherne's jQuery plugin of
// the same name (github.com/briancherne/jquery-hoverIntent).
(function(root, attach) {
  //
  // § __UMD__
  // - When AMD, register the attacher as an anonymous module.
  // - When Node or Browserify, set module exports to the attach result.
  // - When browser globals (root is window), Just run the attach function.
  //
  if (typeof define === 'function' && define.amd) {
    define(['hlf/core'], attach);
  } else if (typeof exports === 'object') {
    module.exports = attach(require('hlf/core'));
  } else {
    attach(hlf);
  }
})(this, function(hlf) {
  //
  // Namespace
  // ---------
  //
  // It takes some more boilerplate to write the extension. Any of this additional
  // support API is put into a extension specific namespace under `hlf`, which in
  // this case is __hlf.hoverIntent__.
  //
  // - __debug__ toggles debug logging for all instances of an extension.
  // - __toString__ helps to namespace when registering any DOM names.
  // - __attrName__, __className__, __eventName__ helpers are all attached to
  //   the namespace on extension creation, along with the __extension__ itself.
  //
  // The extension's __defaults__ are available as reference. Also note that _the
  // extension instance gets extended with the options_.
  //
  // - __interval__ is the millis to wait before deciding intent. `300` is the
  //   default to reduce more thrashing.
  //
  // - __sensitivity__ is the pixel threshold for mouse travel between polling
  //   intervals. With the minimum sensitivity threshold of 1, the mouse must
  //   not move between intervals. With higher values yield more false positives.
  //   `8` is the default to allow more flexibility.
  //
  // The events dispatched are the name-spaced `enter` and `leave` events. They
  // try to match system mouse events where possible and include values for:
  // `pageX`, `pageY`, `relatedTarget`.
  //
  hlf.hoverIntent = {
    debug: true,
    defaults: {
      interval: 300,
      sensitivity: 8,
    },
    toString(context) {
      switch (context) {
        case 'event': return 'hlfhi';
        case 'data': return 'hlf-hi';
        default: return 'hlf-hi';
      }
    },
  };
  //
  // HoverIntent
  // -----------
  //
  // To summarize the implementation, the `_onMouseOver` handler is the start of
  // the intent 'life-cycle', with state being the default. It records the mouse
  // coordinates, sets up a delayed intent check, and guards against unneeded
  // checking. Meanwhile, about every frame, the `_onMouseMove` handler tracks
  // the current mouse coordinates. If the `_onMouseLeave` handler runs before
  // the delayed check, the check and subsequent behavior get canceled as state
  // resets to default. Otherwise, if the check of the stored mouse coordinates
  // against `sensitivity` passes, an `enter` event gets dispatched, ensuring
  // a `leave` event will too during `_onMouseLeave`.
  //
  class HoverIntent {
    constructor(element, options) {
      this.eventListeners = {
        'mouseleave': this._onMouseLeave,
        'mousemove': this._onMouseMove,
        'mouseover': this._onMouseOver,
      };
    }
    init() {
      this._setDefaultState();
    }
    deinit() {
      this._setDefaultState();
    }
    //
    // § __Internal__
    //
    _dispatchHoverEvent(on, mouseEvent) {
      const { mouse: { x, y } } = this;
      let type = on ? 'enter' : 'leave';
      this.dispatchCustomEvent(type, {
        pageX: x.current,
        pageY: y.current,
        relatedTarget: mouseEvent.relatedTarget,
      });
      this.debugLog(type, x.current, y.current, Date.now() % 100000);
    }
    _onMouseLeave(event) {
      if (this.intentional) {
        this.debugLog('teardown');
        this._dispatchHoverEvent(false, event);
      }
      this._setDefaultState();
    }
    _onMouseMove(event) {
      if (this.trackTimeout != null) { return; }
      this.trackTimeout = setTimeout(() => {
        this.debugLog('track');
        let { mouse: { x, y } } = this;
        x.current = event.pageX;
        y.current = event.pageY;
        this.trackTimeout = null;
      }, 16);
    }
    _onMouseOver(event) {
      if (this.intentional) { return; }
      if (event.target !== this.element) { return; }
      if (this.timeout != null) { return; }
      this.debugLog('setup');
      let { mouse: { x, y } } = this;
      x.previous = event.pageX;
      y.previous = event.pageY;
      this.timeout = setTimeout(() => {
        this._setState(event);
        if (this.intentional) {
          this._dispatchHoverEvent(true, event);
        }
      }, this.interval);
    }
    _setDefaultState() {
      this.debugLog('reset');
      this.intentional = false;
      this.mouse = {
        x: { current: 0, previous: 0 },
        y: { current: 0, previous: 0 },
      };
      clearTimeout(this.timeout);
      clearTimeout(this.trackTimeout);
      this.timeout = null;
      this.trackTimeout = null;
    }
    _setState(event) {
      this.debugLog('update');
      let { mouse: { x, y } } = this;
      this.intentional = (
        Math.abs(x.previous - x.current) + Math.abs(y.previous - y.current) >
        this.sensitivity
      );
      this.timeout = null;
    }
  }
  //
  // § __Attaching__
  //
  return hlf.createExtension({
    name: 'hoverIntent',
    namespace: hlf.hoverIntent,
    apiClass: HoverIntent,
    autoBind: true,
    autoListen: true,
    baseMethodGroups: ['event'],
    compactOptions: true,
  });
});
<|endoftext|>


<commit_before>/*
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * TERMS OF REPRODUCTION USE
 *
 * 1. Provide a link back to the original repository (this repository), as
 * 		in, https://github.com/ConnerGDavis/Plugbot, that is well-visible
 * 		wherever the source is being reproduced.  For example, should you
 * 		display it on a website, you should provide a link above/below that
 *		which the users use, titled something such as "ORIGINAL AUTHOR".
 *
 * 2. Retain these three comments:  the GNU GPL license statement, this comment,
 * 		and that below it, that details the author and purpose.
 */

/**
 * NOTE:  This is all procedural as hell because prototypes and any
 * 			OOP techniques in Javascript are stupid and confusing.
 *
 * @author 	Conner Davis ([VIP] ♫Łŏġïç®)
 * 			Harrison Schneidman ([VIDJ] EXƎ)
 */

// Triggers
var autowoot = true;
var autoqueue = false;
var hideVideo = false;
var userList = true;

// DJ Battles
var points = 0;
var highScore = 0;

// API listeners
function initAPIListeners()
{
	API.addEventListener(API.DJ_ADVANCE, djAdvanced);
	API.addEventListener(API.VOTE_UPDATE, function(obj) {
		if (userList)
			populateUserlist();
	});
	API.addEventListener(API.USER_JOIN, function(user) {
		if (userList)
			populateUserlist();
		if (isBoris())
			API.sendChat("\/me Welcome to " + $("#current-room-value").text() + ", " + user.username + "!");
	});
	API.addEventListener(API.USER_LEAVE, function(user) {
		if (userList)
			populateUserlist();
	})
}

// Display UI
function displayUI()
{
	$('#plugbot-ui').remove();
	$('#playback').css('z-index', '8'); // hack to make the buttons usable

	$('#playback').append('

');
		$("#plugbot-ui").animate({"height": "64px"}, {duration: "slow" });
		$('#plugbot-ui').append(
			'' +
			'' +
			'' +
			''
		);
}

// Some on-click listeners for the UI buttons
function initUIListeners()
{
	$("#plugbot-btn-userlist").on("click", function() {
		userList = !userList;
		$(this).attr("src", userList ? 'http://i.imgur.com/IGcMP.png' : 'http://i.imgur.com/pAFJS.png');
		$("#plugbot-userlist").css("visibility", userList ? ("visible") : ("hidden"));
		if (!userList) {
			$("#plugbot-userlist").empty();
		}
		console.log('Userlist is now ' + (userList ? 'enabled' : 'disabled'));
	});
	$("#plugbot-btn-woot").on("click", function() {
		autowoot = !autowoot;
		$(this).attr("src", autowoot ? 'http://i.imgur.com/fWb8n.png' : 'http://i.imgur.com/uyUtA.png');
		if (autowoot)
			$("#button-vote-positive").click();
		console.log('Auto-woot is now ' + (autowoot ? 'enabled' : 'disabled'));
	});

	$("#plugbot-btn-hidevideo").on("click", function() {
		hideVideo = !hideVideo;
		$(this).attr("src", hideVideo ? 'http://i.imgur.com/lwpfH.png' : 'http://i.imgur.com/jbJDe.png');
		$("#yt-frame").animate({"height": (hideVideo ? "0px" : "271px")}, {duration: "fast"});
	});

	$("#plugbot-btn-queue").on("click", function() {
		autoqueue = !autoqueue;
		$(this).attr("src", autoqueue ? 'http://i.imgur.com/IxK27.png' : 'http://i.imgur.com/W5ncS.png');
		$("#button-dj-waitlist-" + (autoqueue ? "join" : "leave")).click();
		console.log('Auto-queue is now ' + (autoqueue ? 'enabled' : 'disabled'));
	});
}

function djAdvanced(obj)
{
	if (autowoot)
		$("#button-vote-positive").click();

	if ($("#button-dj-waitlist-join").css("display") === "block" && autoqueue)
		$("#button-dj-waitlist-join").click();

	$("#yt-frame").css("height", "271px");
	$('#plugbot-btn-hidevideo').attr('src', 'http://i.imgur.com/jbJDe.png');
	hideVideo = false;

	points = 0;
	highScore = 0;

	if (userList)
		populateUserlist();

	if (stream)
		$("#yt-frame").remove();
}

function populateUserlist()
{
	$("#plugbot-userlist").remove();
	$('body').append('

');
	$('#plugbot-userlist');

	if ($('#button-dj-waitlist-leave').css('display') === 'block' && ($.inArray(API.getDJs(), API.getSelf()) == -1)) {
		var spot = $('#button-dj-waitlist-view').attr('title').split('(')[1];
			spot = spot.substring(0, spot.indexOf(')'));
		$('#plugbot-userlist').append('
Waitlist: ' + spot + '

');
	}

	points = 0;
	var userNames = new Array();

	for (var i = 0; i < API.getUsers().length; i++)
	{
		userNames[i] = API.getUsers()[i];
	}

	for (var i = 0; i < userNames.length; i++)
	{
		var user = userNames[i];
		refreshList(user.username, user.vote)
	}

	if (points > highScore)
		highScore = points;

	//$('#plugbot-userlist').append('
High Score: ' + highScore + '
');
}

function refreshList(username, vote)
{
	var colour;
	var currentDj = false;
	var moderator = false;
	var img;

	for (var i = 0; i < API.getModerators().length; i++) {
		if (API.getModerators()[i].username == username) {
			moderator = true;
		}
	}

	switch (vote)
	{
		case 1:
			colour = "3FFF00";
			points++;
			if (moderator)
				img = "http://i.imgur.com/T5G4f.png";
			break;
		case 0:
			colour = "FFFFFF";
			if (moderator)
				img = "http://i.imgur.com/sRsU0.png";
			break;
		case -1:
			colour = "ED1C24";
			if (moderator)
				img = "http://i.imgur.com/JPA1Q.png";
			break;
	}

	if (API.getDJs()[0].username == username) {
		currentDj = true;
		colour = "42A5DC";
		if (moderator)
			img = "http://i.imgur.com/CsK3d.png";
	}

	if (img == undefined && moderator)
		img = "http://i.imgur.com/sRsU0.png";

	$('#plugbot-userlist').append(
		(moderator ? '' : '')
		+ '
'
		+ username + '
'
	);
}

function isSebastian() { return API.getSelf().username == "Sebastian[BOT]"; }
function isBoris() { return API.getSelf().username == "BorisYeltsin[BOT]"; }

// On init

$('#plugbot-css').remove();
$('#plugbot-js').remove();

$('body').prepend('


<commit_before>"use strict";

var fs = require("fs");
var ju = require("./jakeutil")
var path = require("path")
var expand = ju.expand;
var cmdIn = ju.cmdIn;

function tscIn(task, dir) {
    cmdIn(task, dir, 'node ../node_modules/typescript/bin/tsc')
}

function compileDir(name, deps) {
    if (!deps) deps = []
    let dd = expand([name].concat(deps))
    file('built/' + name + '.js', dd, { async: true }, function () { tscIn(this, name) })
}

function loadText(filename) {
    return fs.readFileSync(filename, "utf8");
}

task('default', ['updatestrings', 'built/kind.js', 'built/kind.d.ts', 'built/kindrunner.js', 'built/backendutils.js', 'wapp'], { parallelLimit: 10 })

task('test', ['default', 'runprj', 'testfmt'])

task('clean', function () {
    expand(["built"]).forEach(f => {
        try {
            fs.unlinkSync(f)
        } catch (e) {
            console.log("cannot unlink:", f, e.message)
        }
    })
    jake.rmRf("built")
})

task('runprj', ['built/kind.js'], { async: true, parallelLimit: 10 }, function () {
    cmdIn(this, "libs/lang-test0", 'node --stack_trace_limit=30 ../../built/kind.js run')
})

task('testfmt', ['built/kind.js'], { async: true }, function () {
    cmdIn(this, "libs/format-test", 'node ../../built/kind.js format -t')
})

ju.catFiles('built/kind.js', [
    "node_modules/typescript/lib/typescript.js",
    "built/kindlib.js",
    "built/kindsim.js",
    "built/cli.js"
],
    `
"use strict";
// make sure TypeScript doesn't overwrite our module.exports
global.savedModuleExports = module.exports;
module.exports = null;
`)

file('built/nodeutil.js', ['built/cli.js'])
file('built/kind.d.ts', ['built/cli.js'], function () {
    jake.cpR("built/cli.d.ts", "built/kind.d.ts")
})
file('built/typescriptServices.d.ts', ['node_modules/typescript/lib/typescriptServices.d.ts'], function () {
    jake.cpR('node_modules/typescript/lib/typescriptServices.d.ts', "built/typescriptServices.d.ts")
})

compileDir("kindlib", ["built/typescriptServices.d.ts"])
compileDir("kindblocks", ["built/kindlib.js"])
compileDir("kindrunner", ["built/kindlib.js", "built/kindsim.js", "built/kindblocks.js"])
compileDir("kindsim", ["built/kindlib.js", "built/kindblocks.js"])
compileDir("cli", ["built/kindlib.js", "built/kindsim.js"])
compileDir("backendutils", ['kindlib/emitter/util.ts', 'kindlib/docsrender.ts'])

task("travis", ["test", "upload"])

task('upload', ["wapp", "built/kind.js"], { async: true }, function () {
    jake.exec([
          "node built/kind.js travis",
    ], { printStdout: true });
})

task('bump', function () {
    jake.exec([
        "node built/kind.js bump",
    ], { printStdout: true });
})

task('update', function () {
    jake.exec([
        "git pull",
        "npm install",
        "tsd reinstall"
    ], { printStdout: true });
})

task('updatestrings', ['built/localization.json'])

file('built/localization.json', ju.expand1(["webapp/src"]), function () {
    var errCnt = 0;
    var translationStrings = {}
    var translationHelpStrings = {}

    function processLf(filename) {
        if (!/\.(ts|tsx|html)$/.test(filename)) return
        if (/\.d\.ts$/.test(filename)) return

        //console.log('extracting strings from %s', filename);
        loadText(filename).split('\n').forEach((line, idx) => {
            function err(msg) {
                console.log("%s(%d): %s", filename, idx, msg);
                errCnt++;
            }

            while (true) {
                var newLine = line.replace(/\blf(_va)?\s*\(\s*(.*)/, (all, a, args) => {
                    var m = /^("([^"]|(\\"))+")\s*[\),]/.exec(args)
                    if (m) {
                        try {
                            var str = JSON.parse(m[1])
                            translationStrings[str] = 1
                        } catch (e) {
                            err("cannot JSON-parse " + m[1])
                        }
                    } else {
                        if (!/util\.ts$/.test(filename))
                            err("invalid format of lf() argument: " + args)
                    }
                    return "BLAH " + args
                })
                if (newLine == line) return;
                line = newLine
            }
        })
    }

    var fileCnt = 0;
    this.prereqs.forEach(pth => {
        fileCnt++;
        processLf(pth);
    });

    Object.keys(translationHelpStrings).forEach(k => translationStrings[k] = k)
    var tr = Object.keys(translationStrings)
    tr.sort()

    if (!fs.existsSync("built")) fs.mkdirSync("built");
    fs.writeFileSync("built/localization.json", JSON.stringify({ strings: tr }, null, 1))
    var strings = {};
    tr.forEach(function (k) { strings[k] = k; });
    fs.writeFileSync("built/strings.json", JSON.stringify(strings, null, 2));

    console.log("Localization extraction: " + fileCnt + " files; " + tr.length + " strings");
    if (errCnt > 0)
        console.log("%d errors", errCnt);
})

task('wapp', [
    "built/web/kindlib.js",
    'built/web/main.js',
    'built/web/worker.js',
    'built/web/fonts/icons.woff2',
    'built/web/hexinfo.js',
    'built/web/icons.css',
    'built/web/semantic.css',
    "built/web/semantic.js"
])

file("built/web/hexinfo.js", ["generated/hexinfo.js"], function() {
    let hi = fs.readFileSync("generated/hexinfo.js", "utf8")
    hi = hi.replace(/module.exports =/, "var ksHexInfo =")
    fs.writeFileSync("built/web/hexinfo.js", hi)
})

file("built/web/kindlib.js", ["webapp/ace/mode/assembly_armthumb.js", "built/kindlib.js", "built/kindblocks.js", "built/kindsim.js", "built/kindrunner.js"], function () {
    jake.mkdirP("built/web")
    jake.cpR("node_modules/jquery/dist/jquery.js", "built/web/jquery.js")
    jake.cpR("node_modules/bluebird/js/browser/bluebird.min.js", "built/web/bluebird.min.js")
    jake.cpR("webapp/ace/mode/assembly_armthumb.js", "node_modules/brace/mode/")
    jake.cpR("built/kindlib.js", "built/web/")
    jake.cpR("built/kindblocks.js", "built/web/")
    jake.cpR("built/kindsim.js", "built/web/")
    jake.cpR("built/kindrunner.js", "built/web/")

    let additionalExports = [
        "getCompletionData"
    ]

    let ts = fs.readFileSync("node_modules/typescript/lib/typescript.js", "utf8")
    ts = ts.replace(/getCompletionsAtPosition: getCompletionsAtPosition,/,
        f => f + " " + additionalExports.map(s => s + ": " + s + ",").join(" "))
    fs.writeFileSync("built/web/typescript.js", ts)
})

file('built/webapp/src/app.js', expand([
    "webapp", "built/web/kindlib.js"]), { async: true }, function () {
        tscIn(this, "webapp")
    })

file('built/web/main.js', ["built/webapp/src/app.js"], { async: true }, function () {
    cmdIn(this, ".", 'node node_modules/browserify/bin/cmd built/webapp/src/app.js -o built/web/main.js')
})

file('built/web/worker.js', ["built/webapp/src/app.js"], function () {
    jake.cpR("built/webapp/src/worker.js", "built/web/")
})

file('built/web/fonts/icons.woff2', [], function () {
    jake.cpR("node_modules/semantic-ui-less/themes/default/assets/fonts", "built/web/")
})

file('built/web/semantic.css', ["webapp/theme.config"], { async: true }, function () {
    cmdIn(this, ".", 'node node_modules/less/bin/lessc webapp/style.less built/web/semantic.css --include-path=node_modules/semantic-ui-less:webapp/foo/bar')
})

file('built/web/icons.css', expand(["svgicons"]), { async: true }, function () {
  let webfontsGenerator = require('webfonts-generator')
  let name = "xicon"
  let task = this

  webfontsGenerator({
    fontName: name,
    files: expand(["svgicons"], ".svg"),
    dest: "built/fonts/", // fake
    templateOptions: {
      classPrefix: name + ".",
      baseClass: name
    },
    writeFiles: false,
  }, function(error, res) {
    if (error) {
      task.fail(error)
    } else {
      let css = res.generateCss()
      let data = res["woff"].toString("base64")
      css = css.replace(/^\s*src:[^;]+;/m,
        "    src: url(data:application/x-font-woff;charset=utf-8;base64," + data + ") format(\"woff\");")
      css = css.replace(/line-height:\s*1;/, "")
      console.log("Generated icons.css -", css.length, "bytes")
      let html = "<!doctype html>\n\n"
      css.replace(/\.(\w+):before /g, (f, n) => {
        html += `<div style="margin:20px;"> <i class="${name} ${n}"></i> <span style='padding-left:1em; font-size:0.8em; opacity:0.5;'>${n}</span> </div>\n`
      })
      html += "\n"
      fs.writeFileSync("built/web/icons.html", html)
      fs.writeFileSync("built/web/icons.css", css)
      task.complete()
    }
  })
})

ju.catFiles("built/web/semantic.js",
    expand(["node_modules/semantic-ui-less/definitions/globals",
        "node_modules/semantic-ui-less/definitions/modules",
        "node_modules/semantic-ui-less/definitions/behaviors"], ".js"),
    "")

<commit_msg>Fix build<commit_after>"use strict";

var fs = require("fs");
var ju = require("./jakeutil")
var path = require("path")
var expand = ju.expand;
var cmdIn = ju.cmdIn;

function tscIn(task, dir) {
    cmdIn(task, dir, 'node ../node_modules/typescript/bin/tsc')
}

function compileDir(name, deps) {
    if (!deps) deps = []
    let dd = expand([name].concat(deps))
    file('built/' + name + '.js', dd, { async: true }, function () { tscIn(this, name) })
}

function loadText(filename) {
    return fs.readFileSync(filename, "utf8");
}

task('default', ['updatestrings', 'built/kind.js', 'built/kind.d.ts', 'built/kindrunner.js', 'built/backendutils.js', 'wapp'], { parallelLimit: 10 })

task('test', ['default', 'runprj', 'testfmt'])

task('clean', function () {
    expand(["built"]).forEach(f => {
        try {
            fs.unlinkSync(f)
        } catch (e) {
            console.log("cannot unlink:", f, e.message)
        }
    })
    jake.rmRf("built")
})

task('runprj', ['built/kind.js'], { async: true, parallelLimit: 10 }, function () {
    cmdIn(this, "libs/lang-test0", 'node --stack_trace_limit=30 ../../built/kind.js run')
})

task('testfmt', ['built/kind.js'], { async: true }, function () {
    cmdIn(this, "libs/format-test", 'node ../../built/kind.js format -t')
})

ju.catFiles('built/kind.js', [
    "node_modules/typescript/lib/typescript.js",
    "built/kindlib.js",
    "built/kindsim.js",
    "built/cli.js"
],
    `
"use strict";
// make sure TypeScript doesn't overwrite our module.exports
global.savedModuleExports = module.exports;
module.exports = null;
`)

file('built/nodeutil.js', ['built/cli.js'])
file('built/kind.d.ts', ['built/cli.js'], function () {
    jake.cpR("built/cli.d.ts", "built/kind.d.ts")
})
file('built/typescriptServices.d.ts', ['node_modules/typescript/lib/typescriptServices.d.ts'], function () {
    if (!fs.existsSync("built")) fs.mkdirSync("built");
    jake.cpR('node_modules/typescript/lib/typescriptServices.d.ts', "built/")
})

compileDir("kindlib", ["built/typescriptServices.d.ts"])
compileDir("kindblocks", ["built/kindlib.js"])
compileDir("kindrunner", ["built/kindlib.js", "built/kindsim.js", "built/kindblocks.js"])
compileDir("kindsim", ["built/kindlib.js", "built/kindblocks.js"])
compileDir("cli", ["built/kindlib.js", "built/kindsim.js"])
compileDir("backendutils", ['kindlib/emitter/util.ts', 'kindlib/docsrender.ts'])

task("travis", ["test", "upload"])

task('upload', ["wapp", "built/kind.js"], { async: true }, function () {
    jake.exec([
          "node built/kind.js travis",
    ], { printStdout: true });
})

task('bump', function () {
    jake.exec([
        "node built/kind.js bump",
    ], { printStdout: true });
})

task('update', function () {
    jake.exec([
        "git pull",
        "npm install",
        "tsd reinstall"
    ], { printStdout: true });
})

task('updatestrings', ['built/localization.json'])

file('built/localization.json', ju.expand1(["webapp/src"]), function () {
    var errCnt = 0;
    var translationStrings = {}
    var translationHelpStrings = {}

    function processLf(filename) {
        if (!/\.(ts|tsx|html)$/.test(filename)) return
        if (/\.d\.ts$/.test(filename)) return

        //console.log('extracting strings from %s', filename);
        loadText(filename).split('\n').forEach((line, idx) => {
            function err(msg) {
                console.log("%s(%d): %s", filename, idx, msg);
                errCnt++;
            }

            while (true) {
                var newLine = line.replace(/\blf(_va)?\s*\(\s*(.*)/, (all, a, args) => {
                    var m = /^("([^"]|(\\"))+")\s*[\),]/.exec(args)
                    if (m) {
                        try {
                            var str = JSON.parse(m[1])
                            translationStrings[str] = 1
                        } catch (e) {
                            err("cannot JSON-parse " + m[1])
                        }
                    } else {
                        if (!/util\.ts$/.test(filename))
                            err("invalid format of lf() argument: " + args)
                    }
                    return "BLAH " + args
                })
                if (newLine == line) return;
                line = newLine
            }
        })
    }

    var fileCnt = 0;
    this.prereqs.forEach(pth => {
        fileCnt++;
        processLf(pth);
    });

    Object.keys(translationHelpStrings).forEach(k => translationStrings[k] = k)
    var tr = Object.keys(translationStrings)
    tr.sort()

    if (!fs.existsSync("built")) fs.mkdirSync("built");
    fs.writeFileSync("built/localization.json", JSON.stringify({ strings: tr }, null, 1))
    var strings = {};
    tr.forEach(function (k) { strings[k] = k; });
    fs.writeFileSync("built/strings.json", JSON.stringify(strings, null, 2));

    console.log("Localization extraction: " + fileCnt + " files; " + tr.length + " strings");
    if (errCnt > 0)
        console.log("%d errors", errCnt);
})

task('wapp', [
    "built/web/kindlib.js",
    'built/web/main.js',
    'built/web/worker.js',
    'built/web/fonts/icons.woff2',
    'built/web/hexinfo.js',
    'built/web/icons.css',
    'built/web/semantic.css',
    "built/web/semantic.js"
])

file("built/web/hexinfo.js", ["generated/hexinfo.js"], function() {
    let hi = fs.readFileSync("generated/hexinfo.js", "utf8")
    hi = hi.replace(/module.exports =/, "var ksHexInfo =")
    fs.writeFileSync("built/web/hexinfo.js", hi)
})

file("built/web/kindlib.js", ["webapp/ace/mode/assembly_armthumb.js", "built/kindlib.js", "built/kindblocks.js", "built/kindsim.js", "built/kindrunner.js"], function () {
    jake.mkdirP("built/web")
    jake.cpR("node_modules/jquery/dist/jquery.js", "built/web/jquery.js")
    jake.cpR("node_modules/bluebird/js/browser/bluebird.min.js", "built/web/bluebird.min.js")
    jake.cpR("webapp/ace/mode/assembly_armthumb.js", "node_modules/brace/mode/")
    jake.cpR("built/kindlib.js", "built/web/")
    jake.cpR("built/kindblocks.js", "built/web/")
    jake.cpR("built/kindsim.js", "built/web/")
    jake.cpR("built/kindrunner.js", "built/web/")

    let additionalExports = [
        "getCompletionData"
    ]

    let ts = fs.readFileSync("node_modules/typescript/lib/typescript.js", "utf8")
    ts = ts.replace(/getCompletionsAtPosition: getCompletionsAtPosition,/,
        f => f + " " + additionalExports.map(s => s + ": " + s + ",").join(" "))
    fs.writeFileSync("built/web/typescript.js", ts)
})

file('built/webapp/src/app.js', expand([
    "webapp", "built/web/kindlib.js"]), { async: true }, function () {
        tscIn(this, "webapp")
    })

file('built/web/main.js', ["built/webapp/src/app.js"], { async: true }, function () {
    cmdIn(this, ".", 'node node_modules/browserify/bin/cmd built/webapp/src/app.js -o built/web/main.js')
})

file('built/web/worker.js', ["built/webapp/src/app.js"], function () {
    jake.cpR("built/webapp/src/worker.js", "built/web/")
})

file('built/web/fonts/icons.woff2', [], function () {
    jake.cpR("node_modules/semantic-ui-less/themes/default/assets/fonts", "built/web/")
})

file('built/web/semantic.css', ["webapp/theme.config"], { async: true }, function () {
    cmdIn(this, ".", 'node node_modules/less/bin/lessc webapp/style.less built/web/semantic.css --include-path=node_modules/semantic-ui-less:webapp/foo/bar')
})

file('built/web/icons.css', expand(["svgicons"]), { async: true }, function () {
  let webfontsGenerator = require('webfonts-generator')
  let name = "xicon"
  let task = this

  webfontsGenerator({
    fontName: name,
    files: expand(["svgicons"], ".svg"),
    dest: "built/fonts/", // fake
    templateOptions: {
      classPrefix: name + ".",
      baseClass: name
    },
    writeFiles: false,
  }, function(error, res) {
    if (error) {
      task.fail(error)
    } else {
      let css = res.generateCss()
      let data = res["woff"].toString("base64")
      css = css.replace(/^\s*src:[^;]+;/m,
        "    src: url(data:application/x-font-woff;charset=utf-8;base64," + data + ") format(\"woff\");")
      css = css.replace(/line-height:\s*1;/, "")
      console.log("Generated icons.css -", css.length, "bytes")
      let html = "<!doctype html>\n\n"
      css.replace(/\.(\w+):before /g, (f, n) => {
        html += `<div style="margin:20px;"> <i class="${name} ${n}"></i> <span style='padding-left:1em; font-size:0.8em; opacity:0.5;'>${n}</span> </div>\n`
      })
      html += "\n"
      fs.writeFileSync("built/web/icons.html", html)
      fs.writeFileSync("built/web/icons.css", css)
      task.complete()
    }
  })
})

ju.catFiles("built/web/semantic.js",
    expand(["node_modules/semantic-ui-less/definitions/globals",
        "node_modules/semantic-ui-less/definitions/modules",
        "node_modules/semantic-ui-less/definitions/behaviors"], ".js"),
    "")

<|endoftext|>


<commit_before>/*
 *  Manifest - organize a program of songs for an ensemble
 */

function Manifest(manifest) {

	var manifest = manifest ;

	var __Manifest = function(that) {
		that.manifest = this.manifest ;
		console.log('Creating manifest ', that.manifest) ;
	}(this) ;

    this.displaySong = function(song, baseUrl) {

    	console.log('song is ', song) ;

		var scoreIndex,
		    songIndex,
		    score,
		    part,
		    href,
			webDir = baseUrl + song.fileLocation + '/pdf/',
		    html = '
' + song.title + '
' +
				"
Composed by " + song.composer ;

		if ( song.hasOwnProperty('arranger') &&
			 song.arranger !== '' &&
			 song.composer !== song.arranger ) {
			html += ', Arranged by ' + song.arranger ;
		}

		html += "
\n" ;

		html += this.displayRecordings(song) ;

		html += this.displayScoresAndParts(song, baseUrl) ;

		return html ;
	} ;

	this.displayRecordings = function(song) {

		var name,
			recording,
			href,
			html = "
Recordings
\n
\n" ;

		for ( name in song.recordings ) {
	 		recording = song.recordings[name] ;
			href = recordings[name] ;
			html += '
' + name + "
\n" ;
		};

		html += "
\n" ;

		return html ;
	} ;

	this.getBaseUrl = function(song) {

		if ( song.hasOwnProperty('baseUrl') && song.baseUrl !== '' ) {
			return song.baseUrl ;
		}
		if ( this.manifest.hasOwnProperty('baseUrl') && this.manifest.baseUrl !== '' ) {
			return this.manifest.baseUrl ;
		}
		return '' ;
	} ;

	this.displayScoresAndParts = function(song, baseUrl) {

		var name,
			score,
			href,
			baseUrl = '',
			html = "
Scores
\n
\n" ;

		for ( name in song.scores ) {
	 		score = song.scores[name] ;
			href = this.getBaseUrl(song) + song.filePrefix + score.fileSuffix + '.pdf' ;
			html += '
' + name + "
\n" ;
		}

		html += "
\n
Parts
\n" ;

		for ( name in song.parts ) {
			part = song.parts[name] ;
			href = this.getBaseUrl(song) + song.filePrefix + part.fileSuffix + '.pdf' ;
			html += '
' + name + "
\n" ;
		};
		html += "
\n" ;

		return html ;
	} ;

	this.displayProgram = function() {

		console.log('in displayProgram with this.manifest', this.manifest +
		    ' and this.manifest.songs ', this.manifest.songs +
		    ' and this.manifest.programOrder ', this.manifest.programOrder ) ;

		var programIndex, number, songIndex, song, baseUrl, html ;
		for ( programIndex = this.manifest.programOrder.length - 1; programIndex >= 0; programIndex-- ) {

			number = this.manifest.programOrder[programIndex] ;
			songIndex = this.manifest.program[number] ;
			song = this.manifest.songs[songIndex] ;
			html += this.displaySong(song) ;
			console.log('in displayProgram with number ' + number +
				', songIndex ' + songIndex +
				', this.manifest.songs ', this.manifest.songs +
				' and song ' + song) ;
		}

		return html ;
	} ;

	this.displayPartsInBook = function(chair, partsLists) {

		var songId,
			song,
			partsList,
			partIndex,
			part,
			href,
			html = '
' + chair + '
' +
				"\n\n
\n" ;

		Object.keys(partsLists).forEach(function(songId) {

	    	song = this.manifest.song[songId] ;
			partsList = partsLists[songId] ;
			html += '
' + song.title ;
			for ( partIndex = 0 ; partIndex < partsList.length ; partIndex++ ) {
				part = partsList[partIndex] ;
				href = webDir + song.filePrefix + song.parts[part].fileSuffix + '.pdf' ;
				html += ' ' + part + '' ;
				if ( partIndex+1 < partsList.length ) {
					html += ',' ;
				}
			}
			html += "
\n" ;
		});

		html += "
\n" ;

		return html ;
	} ;

	this.displayPartsInBooks = function() {

		var html, key,
			books = this.manifest.partsInBooks ;

		for ( key in books ) {

			if ( books.hasOwnProperty(key) ) {

				html += this.displayPartsInBook( key, books[key] ) ;

			}
		}
	} ;

	this.displayManifest = function() {
		this.displayProgram() ;
		this.displayPartsInBooks() ;
	}
}

<commit_msg>incremental edits<commit_after>/*
 *  Manifest - organize a program of songs for an ensemble
 */

function Manifest(manifest) {

	var manifest = manifest ;

	var __Manifest = function(that) {
		that.manifest = this.manifest ;
		console.log('Creating manifest ', that.manifest) ;
	}(this) ;

    this.displaySong = function(song, baseUrl) {

    	console.log('song is ', song) ;

		var scoreIndex,
		    songIndex,
		    score,
		    part,
		    href,
			webDir = baseUrl + song.fileLocation + '/pdf/',
		    html = '
' + song.title + '
' +
				"
Composed by " + song.composer ;

		if ( song.hasOwnProperty('arranger') &&
			 song.arranger !== '' &&
			 song.composer !== song.arranger ) {
			html += ', Arranged by ' + song.arranger ;
		}

		html += "
\n" ;

		html += this.displayRecordings(song) ;

		html += this.displayScoresAndParts(song, baseUrl) ;

		return html ;
	} ;

	this.displayRecordings = function(song) {

		var name,
			recording,
			href,
			html = "
Recordings
\n
\n" ;

		for ( name in song.recordings ) {
	 		recording = song.recordings[name] ;
			href = recordings[name] ;
			html += '
' + name + "
\n" ;
		};

		html += "
\n" ;

		return html ;
	} ;

	this.getBaseUrl = function(song) {

		if ( song.hasOwnProperty('baseUrl') && song.baseUrl !== '' ) {
			return song.baseUrl ;
		}
		if ( this.manifest.hasOwnProperty('baseUrl') && this.manifest.baseUrl !== '' ) {
			return this.manifest.baseUrl ;
		}
		return '' ;
	} ;

	this.displayScoresAndParts = function(song, baseUrl) {

		var name,
			score,
			href,
			baseUrl = '',
			html = "
Scores
\n
\n" ;

		for ( name in song.scores ) {
	 		score = song.scores[name] ;
			href = this.getBaseUrl(song) + song.filePrefix + score.fileSuffix + '.pdf' ;
			html += '
' + name + "
\n" ;
		}

		html += "
\n
Parts
\n" ;

		for ( name in song.parts ) {
			part = song.parts[name] ;
			href = this.getBaseUrl(song) + song.filePrefix + part.fileSuffix + '.pdf' ;
			html += '
' + name + "
\n" ;
		};
		html += "
\n" ;

		return html ;
	} ;

	this.displayProgram = function() {

		console.log('in displayProgram with this.manifest', this.manifest,
		    ' and this.manifest.songs ', this.manifest.songs,
		    ' and this.manifest.programOrder ', this.manifest.programOrder,
		    ' and this.manifest.programOrder.length ', this.manifest.programOrder.length ) ;

		var programIndex, number, songIndex, song, baseUrl, html ;
		for ( programIndex = 0 ; programIndex < this.manifest.programOrder.length ; programIndex++ ) {

			number = this.manifest.programOrder[programIndex] ;
			songIndex = this.manifest.program[number] ;
			song = this.manifest.songs[songIndex] ;
			html += this.displaySong(song) ;
			console.log('in displayProgram with number ' + number +
				', songIndex ' + songIndex +
				', this.manifest.songs ', this.manifest.songs +
				' and song ' + song) ;
		}

		return html ;
	} ;

	this.displayPartsInBook = function(chair, partsLists) {

		var songId,
			song,
			partsList,
			partIndex,
			part,
			href,
			html = '
' + chair + '
' +
				"\n\n
\n" ;

		Object.keys(partsLists).forEach(function(songId) {

	    	song = this.manifest.song[songId] ;
			partsList = partsLists[songId] ;
			html += '
' + song.title ;
			for ( partIndex = 0 ; partIndex < partsList.length ; partIndex++ ) {
				part = partsList[partIndex] ;
				href = webDir + song.filePrefix + song.parts[part].fileSuffix + '.pdf' ;
				html += ' ' + part + '' ;
				if ( partIndex+1 < partsList.length ) {
					html += ',' ;
				}
			}
			html += "
\n" ;
		});

		html += "
\n" ;

		return html ;
	} ;

	this.displayPartsInBooks = function() {

		var html, key,
			books = this.manifest.partsInBooks ;

		for ( key in books ) {

			if ( books.hasOwnProperty(key) ) {

				html += this.displayPartsInBook( key, books[key] ) ;

			}
		}
	} ;

	this.displayManifest = function() {
		this.displayProgram() ;
		this.displayPartsInBooks() ;
	}
}

<|endoftext|>


<commit_before>CodeMirror.defineMode("karel-en", function(conf) {
    var ERRORCLASS = 'ka-error';

    function wordRegexp(words) {
        return new RegExp("^((" + words.join(")|(") + "))\\b");
    }

    var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!]");
    var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
    var doubleOperators = new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))");
    var doubleDelimiters = new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
    var tripleDelimiters = new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
    var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");

    var wordOperators = wordRegexp(['not', 'and', 'or']);
    var commonkeywords = ['go', 'left', 'right', 'put', 'get', 'repeat',
    'while', 'if', 'else', 'def'];
    var commontypes = ['home', 'north', 'empty', 'acid', 'anchor', 'bone', 'box', 'bush', 'cactus', 'corn', 'fire', 'gem', 'jellyfish', 'mark', 'mine', 'palm', 'plant', 'radiation', 'rock', 'scorpion', 'skull', 'stone', 'stump', 'tomb', 'torpedo', 'tray', 'tree', 'wall', 'water', 'wood', 'bag', 'baket', 'cart', 'chest', 'vault', 'net', 'bin', 'trash', 'toilet', 'bowl', 'nugget', 'pumpkin', 'spider', 'snake', 'rose', 'tulip', 'apple', 'cherry', 'eye', 'brain', 'candy', 'book', 'key', 'pie', 'gears', 'coin', 'gun', 'ammo', 'grenade', 'pill', 'medkit', 'radio', 'bomb', 'starfish', 'pearl', 'crab', 'shoe', 'beads', 'ribbon', 'ring', 'map', 'hat', 'pipe', 'lens', 'phone', 'watch', 'rug', 'shield', 'mask', 'ball', 'orchid', 'sword', 'chip', 'basket', 'lollipop', 'table', 'chair', 'barrel', 'oil', 'baseball', 'tools', 'orange', 'banana', 'potato', 'coconut', 'pot', 'crate'];
    var commonBlockKeywords = ['repeat', 'while', 'if', 'else', 'def'];
    var ka2 = {
        'types': ['basestring', 'buffer', 'file', 'long', 'unicode',
        'xrange'],
        'keywords': ['exec', 'print']
        };
    var ka3 = {
        'types': ['bytearray', 'bytes', 'filter', 'map', 'memoryview',
        'open', 'range', 'zip'],
        'keywords': ['nonlocal']
        };
    var stringPrefixes;

    if (!!conf.mode.version && parseInt(conf.mode.version, 10) === 3) {
        commonkeywords = commonkeywords.concat(ka3.keywords);
        commontypes = commontypes.concat(ka3.types);
        stringPrefixes = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i");
    } else {
        commonkeywords = commonkeywords.concat(ka2.keywords);
        commontypes = commontypes.concat(ka2.types);
        stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i");
    }
    var keywords = wordRegexp(commonkeywords);
    var types = wordRegexp(commontypes);
    var blockKeywords = new RegExp("^(" + commonBlockKeywords.join("|") + ")$");

    // tokenizers
    function tokenBase(stream, state) {
        // Handle scope changes
        if (stream.sol()) {
            var scopeOffset = state.scopes[0].offset;
            if (stream.eatSpace()) {
                var lineOffset = stream.indentation();
                if (lineOffset > scopeOffset) {
                    return 'ka-indent';
                } else if (lineOffset < scopeOffset) {
                    return 'ka-dedent';
                }
                return 'whitespace';
            } else {
                if (scopeOffset > 0) {
                    dedent(stream, state);
                }
            }
        }
        if (stream.eatSpace()) {
            return 'ka-space';
        }

        var ch = stream.peek();

        // Handle Comments
        if (ch === '#') {
            stream.skipToEnd();
            return 'ka-comment';
        }

        // Handle Number Literals
        if (stream.match(/^[0-9\.]/, false)) {
            var floatLiteral = false;
            // Floats
            if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) {
                floatLiteral = true;
            }
            if (stream.match(/^\d+\.\d*/)) {
                floatLiteral = true;
            }
            if (stream.match(/^\.\d+/)) {
                floatLiteral = true;
            }
            if (floatLiteral) {
                // Float literals may be "imaginary"
                stream.eat(/J/i);
                return 'ka-literal';
            }
            // Integers
            var intLiteral = false;
            // Hex
            if (stream.match(/^0x[0-9a-f]+/i)) {
                intLiteral = true;
            }
            // Binary
            if (stream.match(/^0b[01]+/i)) {
                intLiteral = true;
            }
            // Octal
            if (stream.match(/^0o[0-7]+/i)) {
                intLiteral = true;
            }
            // Decimal
            if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) {
                // Decimal literals may be "imaginary"
                stream.eat(/J/i);
                // TODO - Can you have imaginary longs?
                intLiteral = true;
            }
            // Zero by itself with no other piece of number.
            if (stream.match(/^0(?![\dx])/i)) {
                intLiteral = true;
            }
            if (intLiteral) {
                // Integer literals may be "long"
                stream.eat(/L/i);
                return 'ka-literal';
            }
        }

        // Handle Strings
        if (stream.match(stringPrefixes)) {
            state.tokenize = tokenStringFactory(stream.current());
            return state.tokenize(stream, state);
        }

        // Handle operators and Delimiters
        if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
            return 'ka-delimiter';
        }
        if (stream.match(doubleOperators)
            || stream.match(singleOperators)
            || stream.match(wordOperators)) {
            return 'ka-operator';
        }
        if (stream.match(singleDelimiters)) {
            return 'ka-delimiter';
        }

        if (stream.match(types)) {
            return 'ka-type';
        }

        if (stream.match(keywords)) {
            return 'ka-keyword';
        }

        if (stream.match(identifiers)) {
            return 'ka-identifier';
        }

        // Handle non-detected items
        stream.next();
        return ERRORCLASS;
    }

    function tokenStringFactory(delimiter) {
        while ('rub'.indexOf(delimiter[0].toLowerCase()) >= 0) {
            delimiter = delimiter.substr(1);
        }
        var delim_re = new RegExp(delimiter);
        var singleline = delimiter.length == 1;
        var OUTCLASS = 'ka-string';

        return function tokenString(stream, state) {
            while (!stream.eol()) {
                stream.eatWhile(/[^'"\\]/);
                if (stream.eat('\\')) {
                    stream.next();
                    if (singleline && stream.eol()) {
                        return OUTCLASS;
                    }
                } else if (stream.match(delim_re)) {
                    state.tokenize = tokenBase;
                    return OUTCLASS;
                } else {
                    stream.eat(/['"]/);
                }
            }
            if (singleline) {
                if (conf.mode.singleLineStringErrors) {
                    OUTCLASS = ERRORCLASS
                } else {
                    state.tokenize = tokenBase;
                }
            }
            return OUTCLASS;
        };
    }

    function indent(stream, state, type) {
        type = type || 'py';
        var indentUnit = 0;
        if (type === 'py') {
            for (var i = 0; i < state.scopes.length; ++i) {
                if (state.scopes[i].type === 'py') {
                    indentUnit = state.scopes[i].offset + conf.indentUnit;
                    break;
                }
            }
        } else {
            indentUnit = stream.column() + stream.current().length;
        }
        state.scopes.unshift({
            offset: indentUnit,
            type: type
        });
    }

    function dedent(stream, state) {
        if (state.scopes.length == 1) return;
        if (state.scopes[0].type === 'py') {
            var _indent = stream.indentation();
            var _indent_index = -1;
            for (var i = 0; i < state.scopes.length; ++i) {
                if (_indent === state.scopes[i].offset) {
                    _indent_index = i;
                    break;
                }
            }
            if (_indent_index === -1) {
                return true;
            }
            while (state.scopes[0].offset !== _indent) {
                state.scopes.shift();
            }
            return false
        } else {
            state.scopes.shift();
            return false;
        }
    }

    function tokenLexer(stream, state) {
        var style = state.tokenize(stream, state);
        var current = stream.current();

        // Handle '.' connected identifiers
        if (current === '.') {
            style = state.tokenize(stream, state);
            current = stream.current();
            if (style === 'ka-identifier') {
                return 'ka-identifier';
            } else {
                return ERRORCLASS;
            }
        }

        // Handle decorators
        if (current === '@') {
            style = state.tokenize(stream, state);
            current = stream.current();
            if (style === 'ka-identifier'
                || current === '@staticmethod'
                || current === '@classmethod') {
                return 'ka-decorator';
            } else {
                return ERRORCLASS;
            }
        }

        // Handle scope changes.
        if (current === 'pass' || current === 'return') {
            state.dedent += 1;
        }
        if ((stream.string.slice(stream.indentation(), stream.pos).match(blockKeywords)
            && !state.lambda && state.scopes[0].type == 'py')
            || style === 'ka-indent') {
            indent(stream, state);
        }
        var delimiter_index = '[({'.indexOf(current);
        if (delimiter_index !== -1) {
            indent(stream, state, '])}'.slice(delimiter_index, delimiter_index+1));
        }
        if (style === 'ka-dedent') {
            if (dedent(stream, state)) {
                return ERRORCLASS;
            }
        }
        delimiter_index = '])}'.indexOf(current);
        if (delimiter_index !== -1) {
            if (dedent(stream, state)) {
                return ERRORCLASS;
            }
        }
        if (state.dedent > 0 && stream.eol() && state.scopes[0].type == 'py') {
            if (state.scopes.length > 1) state.scopes.shift();
            state.dedent -= 1;
        }

        return style;
    }

    var external = {
        startState: function(basecolumn) {
            return {
                tokenize: tokenBase,
                scopes: [{
                    offset:basecolumn || 0,
                    type:'py'
                }],
                lastToken: null,
                lambda: false,
                dedent: 0
            };
        },

        token: function(stream, state) {
            var style = tokenLexer(stream, state);

            state.lastToken = {
                style:style,
                content: stream.current()
                };

            if (stream.eol() && stream.lambda) {
                state.lambda = false;
            }

            return style;
        },

        indent: function(state, textAfter) {
            if (state.tokenize != tokenBase) {
                return 0;
            }

            return state.scopes[0].offset;
        }

    };
    return external;
});

CodeMirror.defineMIME("text/x-karel", "karel-en");
<commit_msg>new keywords: bottle, popcorn<commit_after>CodeMirror.defineMode("karel-en", function(conf) {
    var ERRORCLASS = 'ka-error';

    function wordRegexp(words) {
        return new RegExp("^((" + words.join(")|(") + "))\\b");
    }

    var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!]");
    var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
    var doubleOperators = new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))");
    var doubleDelimiters = new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
    var tripleDelimiters = new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
    var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");

    var wordOperators = wordRegexp(['not', 'and', 'or']);
    var commonkeywords = ['go', 'left', 'right', 'put', 'get', 'repeat',
    'while', 'if', 'else', 'def'];
    var commontypes = ['home', 'north', 'empty', 'acid', 'anchor', 'bone', 'box', 'bush', 'cactus', 'corn', 'fire', 'gem', 'jellyfish', 'mark', 'mine', 'palm', 'plant', 'radiation', 'rock', 'scorpion', 'skull', 'stone', 'stump', 'tomb', 'torpedo', 'tray', 'tree', 'wall', 'water', 'wood', 'bag', 'baket', 'cart', 'chest', 'vault', 'net', 'bin', 'trash', 'toilet', 'bowl', 'nugget', 'pumpkin', 'spider', 'snake', 'rose', 'tulip', 'apple', 'cherry', 'eye', 'brain', 'candy', 'book', 'key', 'pie', 'gears', 'coin', 'gun', 'ammo', 'grenade', 'pill', 'medkit', 'radio', 'bomb', 'starfish', 'pearl', 'crab', 'shoe', 'beads', 'ribbon', 'ring', 'map', 'hat', 'pipe', 'lens', 'phone', 'watch', 'rug', 'shield', 'mask', 'ball', 'orchid', 'sword', 'chip', 'basket', 'lollipop', 'table', 'chair', 'barrel', 'oil', 'baseball', 'tools', 'orange', 'banana', 'potato', 'coconut', 'pot', 'crate', 'bottle', 'popcorn'];
    var commonBlockKeywords = ['repeat', 'while', 'if', 'else', 'def'];
    var ka2 = {
        'types': ['basestring', 'buffer', 'file', 'long', 'unicode',
        'xrange'],
        'keywords': ['exec', 'print']
        };
    var ka3 = {
        'types': ['bytearray', 'bytes', 'filter', 'map', 'memoryview',
        'open', 'range', 'zip'],
        'keywords': ['nonlocal']
        };
    var stringPrefixes;

    if (!!conf.mode.version && parseInt(conf.mode.version, 10) === 3) {
        commonkeywords = commonkeywords.concat(ka3.keywords);
        commontypes = commontypes.concat(ka3.types);
        stringPrefixes = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i");
    } else {
        commonkeywords = commonkeywords.concat(ka2.keywords);
        commontypes = commontypes.concat(ka2.types);
        stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i");
    }
    var keywords = wordRegexp(commonkeywords);
    var types = wordRegexp(commontypes);
    var blockKeywords = new RegExp("^(" + commonBlockKeywords.join("|") + ")$");

    // tokenizers
    function tokenBase(stream, state) {
        // Handle scope changes
        if (stream.sol()) {
            var scopeOffset = state.scopes[0].offset;
            if (stream.eatSpace()) {
                var lineOffset = stream.indentation();
                if (lineOffset > scopeOffset) {
                    return 'ka-indent';
                } else if (lineOffset < scopeOffset) {
                    return 'ka-dedent';
                }
                return 'whitespace';
            } else {
                if (scopeOffset > 0) {
                    dedent(stream, state);
                }
            }
        }
        if (stream.eatSpace()) {
            return 'ka-space';
        }

        var ch = stream.peek();

        // Handle Comments
        if (ch === '#') {
            stream.skipToEnd();
            return 'ka-comment';
        }

        // Handle Number Literals
        if (stream.match(/^[0-9\.]/, false)) {
            var floatLiteral = false;
            // Floats
            if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) {
                floatLiteral = true;
            }
            if (stream.match(/^\d+\.\d*/)) {
                floatLiteral = true;
            }
            if (stream.match(/^\.\d+/)) {
                floatLiteral = true;
            }
            if (floatLiteral) {
                // Float literals may be "imaginary"
                stream.eat(/J/i);
                return 'ka-literal';
            }
            // Integers
            var intLiteral = false;
            // Hex
            if (stream.match(/^0x[0-9a-f]+/i)) {
                intLiteral = true;
            }
            // Binary
            if (stream.match(/^0b[01]+/i)) {
                intLiteral = true;
            }
            // Octal
            if (stream.match(/^0o[0-7]+/i)) {
                intLiteral = true;
            }
            // Decimal
            if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) {
                // Decimal literals may be "imaginary"
                stream.eat(/J/i);
                // TODO - Can you have imaginary longs?
                intLiteral = true;
            }
            // Zero by itself with no other piece of number.
            if (stream.match(/^0(?![\dx])/i)) {
                intLiteral = true;
            }
            if (intLiteral) {
                // Integer literals may be "long"
                stream.eat(/L/i);
                return 'ka-literal';
            }
        }

        // Handle Strings
        if (stream.match(stringPrefixes)) {
            state.tokenize = tokenStringFactory(stream.current());
            return state.tokenize(stream, state);
        }

        // Handle operators and Delimiters
        if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
            return 'ka-delimiter';
        }
        if (stream.match(doubleOperators)
            || stream.match(singleOperators)
            || stream.match(wordOperators)) {
            return 'ka-operator';
        }
        if (stream.match(singleDelimiters)) {
            return 'ka-delimiter';
        }

        if (stream.match(types)) {
            return 'ka-type';
        }

        if (stream.match(keywords)) {
            return 'ka-keyword';
        }

        if (stream.match(identifiers)) {
            return 'ka-identifier';
        }

        // Handle non-detected items
        stream.next();
        return ERRORCLASS;
    }

    function tokenStringFactory(delimiter) {
        while ('rub'.indexOf(delimiter[0].toLowerCase()) >= 0) {
            delimiter = delimiter.substr(1);
        }
        var delim_re = new RegExp(delimiter);
        var singleline = delimiter.length == 1;
        var OUTCLASS = 'ka-string';

        return function tokenString(stream, state) {
            while (!stream.eol()) {
                stream.eatWhile(/[^'"\\]/);
                if (stream.eat('\\')) {
                    stream.next();
                    if (singleline && stream.eol()) {
                        return OUTCLASS;
                    }
                } else if (stream.match(delim_re)) {
                    state.tokenize = tokenBase;
                    return OUTCLASS;
                } else {
                    stream.eat(/['"]/);
                }
            }
            if (singleline) {
                if (conf.mode.singleLineStringErrors) {
                    OUTCLASS = ERRORCLASS
                } else {
                    state.tokenize = tokenBase;
                }
            }
            return OUTCLASS;
        };
    }

    function indent(stream, state, type) {
        type = type || 'py';
        var indentUnit = 0;
        if (type === 'py') {
            for (var i = 0; i < state.scopes.length; ++i) {
                if (state.scopes[i].type === 'py') {
                    indentUnit = state.scopes[i].offset + conf.indentUnit;
                    break;
                }
            }
        } else {
            indentUnit = stream.column() + stream.current().length;
        }
        state.scopes.unshift({
            offset: indentUnit,
            type: type
        });
    }

    function dedent(stream, state) {
        if (state.scopes.length == 1) return;
        if (state.scopes[0].type === 'py') {
            var _indent = stream.indentation();
            var _indent_index = -1;
            for (var i = 0; i < state.scopes.length; ++i) {
                if (_indent === state.scopes[i].offset) {
                    _indent_index = i;
                    break;
                }
            }
            if (_indent_index === -1) {
                return true;
            }
            while (state.scopes[0].offset !== _indent) {
                state.scopes.shift();
            }
            return false
        } else {
            state.scopes.shift();
            return false;
        }
    }

    function tokenLexer(stream, state) {
        var style = state.tokenize(stream, state);
        var current = stream.current();

        // Handle '.' connected identifiers
        if (current === '.') {
            style = state.tokenize(stream, state);
            current = stream.current();
            if (style === 'ka-identifier') {
                return 'ka-identifier';
            } else {
                return ERRORCLASS;
            }
        }

        // Handle decorators
        if (current === '@') {
            style = state.tokenize(stream, state);
            current = stream.current();
            if (style === 'ka-identifier'
                || current === '@staticmethod'
                || current === '@classmethod') {
                return 'ka-decorator';
            } else {
                return ERRORCLASS;
            }
        }

        // Handle scope changes.
        if (current === 'pass' || current === 'return') {
            state.dedent += 1;
        }
        if ((stream.string.slice(stream.indentation(), stream.pos).match(blockKeywords)
            && !state.lambda && state.scopes[0].type == 'py')
            || style === 'ka-indent') {
            indent(stream, state);
        }
        var delimiter_index = '[({'.indexOf(current);
        if (delimiter_index !== -1) {
            indent(stream, state, '])}'.slice(delimiter_index, delimiter_index+1));
        }
        if (style === 'ka-dedent') {
            if (dedent(stream, state)) {
                return ERRORCLASS;
            }
        }
        delimiter_index = '])}'.indexOf(current);
        if (delimiter_index !== -1) {
            if (dedent(stream, state)) {
                return ERRORCLASS;
            }
        }
        if (state.dedent > 0 && stream.eol() && state.scopes[0].type == 'py') {
            if (state.scopes.length > 1) state.scopes.shift();
            state.dedent -= 1;
        }

        return style;
    }

    var external = {
        startState: function(basecolumn) {
            return {
                tokenize: tokenBase,
                scopes: [{
                    offset:basecolumn || 0,
                    type:'py'
                }],
                lastToken: null,
                lambda: false,
                dedent: 0
            };
        },

        token: function(stream, state) {
            var style = tokenLexer(stream, state);

            state.lastToken = {
                style:style,
                content: stream.current()
                };

            if (stream.eol() && stream.lambda) {
                state.lambda = false;
            }

            return style;
        },

        indent: function(state, textAfter) {
            if (state.tokenize != tokenBase) {
                return 0;
            }

            return state.scopes[0].offset;
        }

    };
    return external;
});

CodeMirror.defineMIME("text/x-karel", "karel-en");
<|endoftext|>


<commit_before>// Copyright (c) 2012 Titanium I.T. LLC. All rights reserved. See LICENSE.txt for details.
/*global desc, task, jake, fail, complete, directory, require, console, process */
(function () {
	"use strict";

	var REQUIRED_BROWSERS = [
		"IE 8.0 (Windows)",
		"IE 9.0 (Windows)",
		"Firefox 22.0 (Mac)",
		"Chrome 28.0 (Mac)",
		"Safari 6.0 (Mac)",
		"Safari 6.0 (iOS)"
	];

	var lint = require("./build/util/lint_runner.js");
	var nodeunit = require("./build/util/nodeunit_runner.js");
	var karma = require("./build/util/karma_runner.js");

	desc("Lint and test");
	task("default", ["lint", "test"], function() {
		console.log("\n\nOK");
	});

	desc("Start Karma server -- run this first");
	task("karma", function() {
		karma.serve(complete, fail);
	}, {async: true});

	desc("Lint everything");
	task("lint", [], function () {
		var passed = lint.validateFileList(nodeFilesToLint(), nodeLintOptions(), {});
		passed = lint.validateFileList(browserFilesToLint(), browserLintOptions(), {}) && passed;
		if (!passed) fail("Lint failed");
	});

	desc("Test everything");
	task("test", ["testServer", "testClient"]);

	desc("Test node.js code");
	task("testServer", function() {
		nodeunit.runTests(nodeFilesToTest(), complete, fail);
	}, {async: true});

	desc("Test browser code");
	task("testClient", function() {
		karma.runTests(REQUIRED_BROWSERS, complete, fail);
	}, {async: true});

	function nodeFilesToTest() {
		var testFiles = new jake.FileList();
		testFiles.include("src/_*_test.js");
		testFiles.include("src/server/**/_*_test.js");
		testFiles.exclude("node_modules");
		var tests = testFiles.toArray();
		return tests;
	}

	function nodeFilesToLint() {
		var files = new jake.FileList();
		files.include("src/*.js");
		files.include("src/server/**/*.js");
		files.include("build/util/**/*.js");
		files.include("Jakefile.js");
		return files.toArray();
	}

	function browserFilesToLint() {
		var files = new jake.FileList();
		files.include("src/client/**/*.js");
		return files.toArray();
	}

	function globalLintOptions() {
		return {
			bitwise:true,
			curly:false,
			eqeqeq:true,
			forin:true,
			immed:true,
			latedef:false,
			newcap:true,
			noarg:true,
			noempty:true,
			nonew:true,
			regexp:true,
			undef:true,
			strict:true,
			trailing:true
		};
	}

	function nodeLintOptions() {
		var options = globalLintOptions();
		options.node = true;
		return options;
	}

	function browserLintOptions() {
		var options = globalLintOptions();
		options.browser = true;
		return options;
	}

}());<commit_msg>Updated browser versions<commit_after>// Copyright (c) 2012 Titanium I.T. LLC. All rights reserved. See LICENSE.txt for details.
/*global desc, task, jake, fail, complete, directory, require, console, process */
(function () {
	"use strict";

	var REQUIRED_BROWSERS = [
		"IE 8.0.0 (Windows XP)",
		"IE 9.0.0 (Windows 7)",
		"Firefox 23.0.0 (Mac OS X 10.8)",
		"Chrome 29.0.1547 (Mac OS X 10.8.5)",
		"Safari 6.0.5 (Mac OS X 10.8.5)",
		"Mobile Safari 6.0.0 (iOS 6.1)"
	];

	var lint = require("./build/util/lint_runner.js");
	var nodeunit = require("./build/util/nodeunit_runner.js");
	var karma = require("./build/util/karma_runner.js");

	desc("Lint and test");
	task("default", ["lint", "test"], function() {
		console.log("\n\nOK");
	});

	desc("Start Karma server -- run this first");
	task("karma", function() {
		karma.serve(complete, fail);
	}, {async: true});

	desc("Lint everything");
	task("lint", [], function () {
		var passed = lint.validateFileList(nodeFilesToLint(), nodeLintOptions(), {});
		passed = lint.validateFileList(browserFilesToLint(), browserLintOptions(), {}) && passed;
		if (!passed) fail("Lint failed");
	});

	desc("Test everything");
	task("test", ["testServer", "testClient"]);

	desc("Test node.js code");
	task("testServer", function() {
		nodeunit.runTests(nodeFilesToTest(), complete, fail);
	}, {async: true});

	desc("Test browser code");
	task("testClient", function() {
		karma.runTests(REQUIRED_BROWSERS, complete, fail);
	}, {async: true});

	function nodeFilesToTest() {
		var testFiles = new jake.FileList();
		testFiles.include("src/_*_test.js");
		testFiles.include("src/server/**/_*_test.js");
		testFiles.exclude("node_modules");
		var tests = testFiles.toArray();
		return tests;
	}

	function nodeFilesToLint() {
		var files = new jake.FileList();
		files.include("src/*.js");
		files.include("src/server/**/*.js");
		files.include("build/util/**/*.js");
		files.include("Jakefile.js");
		return files.toArray();
	}

	function browserFilesToLint() {
		var files = new jake.FileList();
		files.include("src/client/**/*.js");
		return files.toArray();
	}

	function globalLintOptions() {
		return {
			bitwise:true,
			curly:false,
			eqeqeq:true,
			forin:true,
			immed:true,
			latedef:false,
			newcap:true,
			noarg:true,
			noempty:true,
			nonew:true,
			regexp:true,
			undef:true,
			strict:true,
			trailing:true
		};
	}

	function nodeLintOptions() {
		var options = globalLintOptions();
		options.node = true;
		return options;
	}

	function browserLintOptions() {
		var options = globalLintOptions();
		options.browser = true;
		return options;
	}

}());<|endoftext|>


<commit_before>import {parse} from 'acorn'
import {simple, base} from 'acorn/dist/walk'

import {pack, unpack} from '../value'

import FUNCTIONS from '../functions/index'

/**
 * A Javascript context
 *
 * Implements the Stencila `Context` API. All methods return a Promise.
 */
export default class JsContext {

  /**
   * Run JavaScript code within the global context scope (execute a code "chunk")
   *
   * @param {string} code Javascript code
   * @param {object} options - Any execution options
   * @return {object} - A Promise resolving to object with any `errors` (an object with line numbers as keys) and `outputs` (
   *                         a data package)
   *
   * @example
   *
   * // You can also assign global variables which are available in subsequent calls,
   * context.call('foo = "bar"\n\n') // { errors: {}, output: null }
   * context.call('foo') // { errors: {}, output: { type: 'str', format: 'text', value: 'bar' } }
   */
  run (code, options) {
    code = code || ''
    options = options || {}
    if (options.pack !== false) options.pack = true

    let error = null

    // Create a function and execute it
    try {
      (new Function(code))() // eslint-disable-line no-new-func
    } catch (e) {
      // Catch any error
      error = e
    }

    let value
    if (!error) {
      // Evaluate the last line, and if any error then undefined result
      // This is inefficient in the sense that the last line is evaluated twice
      // but it anything else would appear to require some code parsing
      let lines = code.split('\n')
      let last = lines[lines.length - 1]
      try {
        value = (new Function('return ' + last))() // eslint-disable-line no-new-func
      } catch (error) {
        value = undefined
      }
    }

    return Promise.resolve(
      this._result(error, 0, value, options.pack)
    )
  }

  /**
   * Execute JavaScript code within a local function scope (execute a code "cell")
   *
   * @param {string} code - Javascript code
   * @param {object} args - An object with a data pack for each argument
   * @param {object} options - Any execution options
   * @return {object} - A Promise resolving to an object with any `errors` (an object with line numbers as keys) and `outputs` (
   *                         a data package)
   *
   * @example
   *
   * // Return statement must be used to return a value
   * context.call('return 6*7') // { errors: {}, output: { type: 'int', format: 'text', value: '42' } }
   * context.call('let x = 6\nreturn x*7') // { errors: {}, output: { type: 'int', format: 'text', value: '42' } }
   *
   * // You can specify input variables (that are local to that call),
   * context.call('return Math.PI*radius', {radius:{type:'flt', format:'text', value: '21.4'}}) // { errors: {}, output: { type: 'flt', format: 'text', value: '67.23008278682157' } }
   * context.call('return radius') // { errors: { '1': 'ReferenceError: radius is not defined' }, output: null }
   */
  call (code, args, options) {
    code = code || ''
    args = args || {}
    options = options || {}
    if (options.pack !== false) options.pack = true

    // Extract names and values of arguments
    let names = Object.keys(args)
    let values = names.map(name => unpack(args[name]))

    // Generate a function with parameter names matching the names of the supplied inputs
    let func = 'return (function(' + names.join(',') + '){\n' + code + '\n})(...values)'

    // Execute the function with the unpacked arguments. Using `new Function` avoids call to eval
    let error = null
    let value
    try {
      value = (new Function('values', func))(values) // eslint-disable-line no-new-func
    } catch (e) {
      // Catch any error
      error = e
    }

    return Promise.resolve(
      this._result(error, 2, value, options.pack)
    )
  }

  /**
   * Determine the dependencies for a piece of Javascript code
   *
   * Returns an array of all variable names not declared within
   * the piece of code. This might include global functions.
   *
   * @param  {string} code - JavaScript code
   * @return {array<string>} - A Promise resolving to a list of dependencies
   */
  depends (code) {
    let names = {}
    let ast = parse(code)
    simple(ast, {
      Identifier: node => {
        let name = node.name
        names[name] = Object.assign(names[name] || {}, {used: true})
      },
      VariableDeclarator: node => {
        let name = node.id.name
        names[name] = Object.assign(names[name] || {}, {declared: true})
      }
    }, base)
    let depends = []
    for (let name in names) {
      let usage = names[name]
      if (usage.used && !usage.declared) depends.push(name)
    }
    return Promise.resolve(depends)
  }

  /**
   * Return a result promise
   *
   * @param {object} error - Error object, if any
   * @param {int} offset - Line number offset
   * @param {object} value - The value to be packed
   * @param {boolean} packed - Should the output be packed (or left unpacked for calls withing Javascript)
   * @return {null|object} - A set of errors by line number
   */
  _result (error, offset, value, packed) {
    if (packed !== false) packed = true

    let errors = null
    if (error) {
      // Parse the error stack to get message and line number
      let lines = error.stack.split('\n')
      let message = lines[0]
      let match = lines[1].match(/<anonymous>:(\d+):\d+/)
      let line = 0
      if (match) line = parseInt(match[1]) - 1 - offset
      errors = {}
      errors[line] = message
    }

    let output
    if (value === undefined) output = null
    else if (packed) output = pack(value)
    else output = value

    return {
      errors: errors,
      output: output
    }
  }

  // EXPERIMENTAL
  // TODO: every context should implement this lookup service
  // so that we can:
  // - get all available functions
  // - check if a specific function is implemented
  // - and call a function

  hasFunction (name) {
    return Boolean(FUNCTIONS[name])
  }

  callFunction (name, args) {
    // args = args.map(unpack)
    const f = FUNCTIONS[name]
    return f(...args)
  }

}
<commit_msg>Simplify JsContext.call()<commit_after>import {parse} from 'acorn'
import {simple, base} from 'acorn/dist/walk'

import {pack, unpack} from '../value'

import FUNCTIONS from '../functions/index'

/**
 * A Javascript context
 *
 * Implements the Stencila `Context` API. All methods return a Promise.
 */
export default class JsContext {

  /**
   * Run JavaScript code within the global context scope (execute a code "chunk")
   *
   * @param {string} code Javascript code
   * @param {object} options - Any execution options
   * @return {object} - A Promise resolving to object with any `errors` (an object with line numbers as keys) and `outputs` (
   *                         a data package)
   *
   * @example
   *
   * // You can also assign global variables which are available in subsequent calls,
   * context.call('foo = "bar"\n\n') // { errors: {}, output: null }
   * context.call('foo') // { errors: {}, output: { type: 'str', format: 'text', value: 'bar' } }
   */
  run (code, options) {
    code = code || ''
    options = options || {}
    if (options.pack !== false) options.pack = true

    let error = null

    // Create a function and execute it
    try {
      (new Function(code))() // eslint-disable-line no-new-func
    } catch (e) {
      // Catch any error
      error = e
    }

    let value
    if (!error) {
      // Evaluate the last line, and if any error then undefined result
      // This is inefficient in the sense that the last line is evaluated twice
      // but it anything else would appear to require some code parsing
      let lines = code.split('\n')
      let last = lines[lines.length - 1]
      try {
        value = (new Function('return ' + last))() // eslint-disable-line no-new-func
      } catch (error) {
        value = undefined
      }
    }

    return Promise.resolve(
      this._result(error, 0, value, options.pack)
    )
  }

  /**
   * Execute JavaScript code within a local function scope (execute a code "cell")
   *
   * @param {string} code - Javascript code
   * @param {object} args - An object with a data pack for each argument
   * @param {object} options - Any execution options
   * @return {object} - A Promise resolving to an object with any `errors` (an object with line numbers as keys) and `outputs` (
   *                         a data package)
   *
   * @example
   *
   * // Return statement must be used to return a value
   * context.call('return 6*7') // { errors: {}, output: { type: 'int', format: 'text', value: '42' } }
   * context.call('let x = 6\nreturn x*7') // { errors: {}, output: { type: 'int', format: 'text', value: '42' } }
   *
   * // You can specify input variables (that are local to that call),
   * context.call('return Math.PI*radius', {radius:{type:'flt', format:'text', value: '21.4'}}) // { errors: {}, output: { type: 'flt', format: 'text', value: '67.23008278682157' } }
   * context.call('return radius') // { errors: { '1': 'ReferenceError: radius is not defined' }, output: null }
   */
  call (code, args, options) {
    code = code || ''
    args = args || {}
    options = options || {}
    const pack = (options.pack !== false)

    // Extract names and values of arguments
    let names = Object.keys(args)
    let values
    if (pack) {
      values = names.map(name => unpack(args[name]))
    } else {
      values = names.map(name => args[name])
    }

    // Execute the function with the unpacked arguments. Using `new Function` avoids call to eval
    let error = null
    let value
    try {
      const f = new Function(...names, code) // eslint-disable-line no-new-func
      value = f(...values)
    } catch (e) {
      // Catch any error
      error = e
    }

    return Promise.resolve(
      this._result(error, 0, value, pack)
    )
  }

  /**
   * Determine the dependencies for a piece of Javascript code
   *
   * Returns an array of all variable names not declared within
   * the piece of code. This might include global functions.
   *
   * @param  {string} code - JavaScript code
   * @return {array<string>} - A Promise resolving to a list of dependencies
   */
  depends (code) {
    let names = {}
    let ast = parse(code)
    simple(ast, {
      Identifier: node => {
        let name = node.name
        names[name] = Object.assign(names[name] || {}, {used: true})
      },
      VariableDeclarator: node => {
        let name = node.id.name
        names[name] = Object.assign(names[name] || {}, {declared: true})
      }
    }, base)
    let depends = []
    for (let name in names) {
      let usage = names[name]
      if (usage.used && !usage.declared) depends.push(name)
    }
    return Promise.resolve(depends)
  }

  /**
   * Return a result promise
   *
   * @param {object} error - Error object, if any
   * @param {int} offset - Line number offset
   * @param {object} value - The value to be packed
   * @param {boolean} packed - Should the output be packed (or left unpacked for calls withing Javascript)
   * @return {null|object} - A set of errors by line number
   */
  _result (error, offset, value, packed) {
    if (packed !== false) packed = true

    let errors = null
    if (error) {
      // Parse the error stack to get message and line number
      let lines = error.stack.split('\n')
      let message = lines[0]
      let match = lines[1].match(/<anonymous>:(\d+):\d+/)
      let line = 0
      if (match) line = parseInt(match[1]) - 1 - offset
      errors = {}
      errors[line] = message
    }

    let output
    if (value === undefined) output = null
    else if (packed) output = pack(value)
    else output = value

    return {
      errors: errors,
      output: output
    }
  }

  // EXPERIMENTAL
  // TODO: every context should implement this lookup service
  // so that we can:
  // - get all available functions
  // - check if a specific function is implemented
  // - and call a function

  hasFunction (name) {
    return Boolean(FUNCTIONS[name])
  }

  callFunction (name, args) {
    // args = args.map(unpack)
    const f = FUNCTIONS[name]
    return f(...args)
  }

}
<|endoftext|>


<commit_before>/**
 * @fileoverview Container for calendar-footer-component.
 */
import {connect} from 'react-redux';
import CalendarFooterComponent from 'components/calendar-footer-component';
import {goToPrevMonth, goToNextMonth} from 'actions/actions';

const mapStateToProps = () => ({});

const mapDispatchToProps = (dispatch, ownProps) => ({
  onClickPrev() {
    dispatch(goToPrevMonth(ownProps.prevYear, ownProps.prevMonth)
  },
  onClickNext() {
    dispatch(goToPrevMonth(ownProps.nextYear, ownProps.nextMonth)
  },
});

const CalendarFooterContainer = connect(mapStateToProps, mapDispatchToProps)(CalendarFooterComponent);

export default CalendarFooterComponent;
<commit_msg>fix: syntax error<commit_after>/**
 * @fileoverview Container for calendar-footer-component.
 */
import {connect} from 'react-redux';
import CalendarFooterComponent from 'components/calendar-footer-component';
import {goToPrevMonth, goToNextMonth} from 'actions/actions';

const mapStateToProps = () => ({});

const mapDispatchToProps = (dispatch, ownProps) => ({
  onClickPrev() {
    dispatch(goToPrevMonth(ownProps.prevYear, ownProps.prevMonth));
  },
  onClickNext() {
    dispatch(goToPrevMonth(ownProps.nextYear, ownProps.nextMonth));
  },
});

const CalendarFooterContainer = connect(mapStateToProps, mapDispatchToProps)(CalendarFooterComponent);

export default CalendarFooterComponent;
<|endoftext|>


<commit_before>/**
 * App store
 */

import {EventEmitter} from 'events';
import AppDispatcher from '../dispatchers/dispatcher';
import AppConstants from '../constants/constants';
import {Map} from 'immutable';
import MD5 from 'MD5';

class AppStore extends EventEmitter {

	constructor (props) {

		super(props);

		this.storeData = Map({
			configuration: Map({
				enable: false,
				updateFrequency: 2,
				autoupdate: false,
				stylesheets: []
			}),
			// TODO: move to react-router
			viewType: 'stylesheets', // stylesheets, options
			configurationKey: null
		});

		AppDispatcher.register(({actionType, payload}) => {

			switch (actionType) {

				case AppConstants.SWITCH_VIEW:

					this.switchView(payload.viewType);

					break;

				case AppConstants.GET_CONFIGURATION:

					this.getConfiguration();

					break;

				case AppConstants.SAVE_CONFIGURATION:

					this.saveConfiguration();

					break;

				case AppConstants.ADD_FIELD:

					this.addField();

					break;

				case AppConstants.REMOVE_FIELD:

					this.removeField(payload.key);

					break;

				case AppConstants.ADD_INPUT_VALUE:

					this.addInputValue({
						key: 	payload.key,
						value: 	payload.value
					});

					break;
			}

		});

		this.getConfiguration();

	}

	addChangeListener = handler => {

		this.on(AppConstants.CHANGE_EVENT, handler);

	}

	removeChangeListener = handler => {

		this.removeListener(AppConstants.CHANGE_EVENT, handler);

	}

	emitChange () {

		this.emit(AppConstants.CHANGE_EVENT);

	}

	switchView (viewType) {

		this.storeData = this.storeData.update('viewType', () => viewType);

		this.emitChange();

	}

	/**
	 * Retrieve configuration from localStorage
	 */
	getConfiguration () {

		let configurationKey = this.storeData.get('configurationKey');

		if (configurationKey) {
			this.getFromStorage(configurationData => {
				this.processConfiguration(configurationData);
			});
		} else {
			this.createConfigurationKey(() => {
				this.getFromStorage(configurationData => {
					this.processConfiguration(configurationData);
				});
			});
		}

	}

	processConfiguration (configurationData) {

		let configurationKey = this.storeData.get('configurationKey');

		if (configurationData.hasOwnProperty(configurationKey)) {
			let configuration = JSON.parse(configurationData[configurationKey]);
			this.storeData = this.storeData.update('configuration', c => Map(configuration));
			console.log(this.storeData.get('configuration'));
			this.emitChange();
		} else {
			console.error('1');
		}

	}

	/**
	 * Save configuration to localStorage
	 */
	saveConfiguration () {

		console.log('save configuration');

		let self = this;

		// let configurationKey = this.configurationKey;
		//
		// let configurationObject = {};
		// configurationObject[configurationKey] = configuration;
		//
		// chrome.storage.local.set(configurationObject, () => {
		// 	();
		// });

		let configurationKey 	= 	this.storeData.get('configurationKey');
		let configuration 		= 	this.storeData.get('configuration');
		let configurationJSON 	= 	JSON.stringify(configuration);

		if (configurationKey) {
			this.setToStorage(configurationJSON, () => {

			});
		} else {
			this.createConfigurationKey(() => {
				this.setToStorage(configurationJSON, () => {

				});
			});
		}

	}

	createConfigurationKey (callback) {

		chrome.tabs.getSelected(null, (tab) => {

			console.log('selected tab', tab);

			let tabUrl = tab.url;
			let linkParser = document.createElement('a');
			linkParser.href = tabUrl;

			this.storeData = this.storeData.update('configurationKey', c => MD5(linkParser.host));

			callback();

		});
	}

	getFromStorage (callback) {

		let configurationKey = this.storeData.get('configurationKey');

		chrome.storage.local.get(configurationKey, (data) => {
			callback.call(null, data);
		});

	}

	setToStorage (cofigurationJSON, callback) {

		let configurationKey = this.storeData.get('configurationKey');

		let configurationObject = {};
		configurationObject[configurationKey] = cofigurationJSON;

		chrome.storage.local.set(configurationObject, () => {
			callback();
		});

	}

	__sendMessage ({payload, callback}) {

		console.log('sendMessage');

		chrome.tabs.getSelected(null, (tab) => {

			chrome.tabs.sendMessage(tab.id, payload, response => {

				console.log('__sendMessage response', response);

				if (typeof callback === 'function') {
					callback.call(null, response);
				}

			});

		});

	}

	addField () {

		let stylesheetModel = {
			src: '',
			overrideOriginal: false,
			key: '' + Math.floor(Math.random() * 10e7) + (new Date()).getTime()
		};

		this.storeData = this.storeData.updateIn(['configuration', 'stylesheets'], stylesheets => {
			return stylesheets.push(stylesheetModel), stylesheets
		});

		this.emitChange();
	}

	removeField (key) {

		this.storeData = this.storeData.updateIn(['configuration', 'stylesheets'], stylesheets => {

			let stylesheetIndex = stylesheets.findIndex(stylesheet => {
				return stylesheet.key === key;
			});

			if (!!~stylesheetIndex) {
				stylesheets.splice(stylesheetIndex, 1);
			}

			return stylesheets;

		});

		this.emitChange();

	}

	addInputValue ({key, value}) {

		this.storeData = this.storeData.updateIn(['configuration', 'stylesheets'], stylesheets => {

			let stylesheetIndex = stylesheets.findIndex(stylesheet => {
				return stylesheet.key === key;
			});

			if (!!~stylesheetIndex) {
				stylesheets[stylesheetIndex].src = value;
			}

			return stylesheets;

		});

		this.emitChange();

	}

	getStoreData () {

		return this.storeData;

	}

}

export default new AppStore();
<commit_msg>Update store<commit_after>/**
 * App store
 */

import {EventEmitter} from 'events';
import AppDispatcher from '../dispatchers/dispatcher';
import AppConstants from '../constants/constants';
import {Map} from 'immutable';
import MD5 from 'MD5';

class AppStore extends EventEmitter {

	constructor (props) {

		super(props);

		this.storeData = Map({
			configuration: Map({
				enable: false,
				autoUpdate: false,
				updateFrequency: 2,
				styleSheets: []
			}),
			viewType: 'stylesheets', // stylesheets || options
			configurationKey: null
		});

		AppDispatcher.register(({actionType, payload}) => {

			switch (actionType) {

				case AppConstants.SWITCH_VIEW:

					this.switchView(payload.viewType);

					break;

				case AppConstants.GET_CONFIGURATION:

					this.getConfiguration();

					break;

				case AppConstants.SAVE_CONFIGURATION:

					this.saveConfiguration();

					break;

				case AppConstants.ADD_FIELD:

					this.addField();

					break;

				case AppConstants.REMOVE_FIELD:

					this.removeField(payload.key);

					break;

				case AppConstants.ADD_INPUT_VALUE:

					this.addInputValue({
						key: 	payload.key,
						value: 	payload.value
					});

					break;

				case AppConstants.SET_ENABLE:

					this.setEnable(payload.enable);

					break;

				case AppConstants.SET_AUTO_UPDATE:

					this.setAutoUpdate(payload.autoUpdate);

					break;

				case AppConstants.SET_UPDATE_FREQUENCY:

					this.setUpdateFrequency(payload.updateFrequency);

					break;
			}

		});

		this.getConfiguration();

	}

	addChangeListener = handler => {

		this.on(AppConstants.CHANGE_EVENT, handler);

	}

	removeChangeListener = handler => {

		this.removeListener(AppConstants.CHANGE_EVENT, handler);

	}

	emitChange () {

		this.emit(AppConstants.CHANGE_EVENT);

	}

	switchView (viewType) {

		this.storeData = this.storeData.update('viewType', () => viewType);

		this.emitChange();

	}

	/**
	 * Retrieve configuration from localStorage
	 */
	getConfiguration () {

		let configurationKey = this.storeData.get('configurationKey');

		if (configurationKey) {
			this.getFromStorage(configurationData => {
				this.processConfiguration(configurationData);
			});
		} else {
			this.createConfigurationKey(() => {
				this.getFromStorage(configurationData => {
					this.processConfiguration(configurationData);
				});
			});
		}

	}

	processConfiguration (configurationData) {

		let configurationKey = this.storeData.get('configurationKey');

		if (configurationData.hasOwnProperty(configurationKey)) {
			let configuration = JSON.parse(configurationData[configurationKey]);
			this.storeData = this.storeData.update('configuration', c => Map(configuration));
			this.emitChange();
		}

	}

	/**
	 * Save configuration to localStorage
	 */
	saveConfiguration () {

		let configurationKey 	= 	this.storeData.get('configurationKey');
		let configuration 		= 	this.storeData.get('configuration');
		let configurationJSON 	= 	JSON.stringify(configuration);

		if (configurationKey) {
			this.setToStorage(configurationJSON, () => {
				this.applyConfiguration()
			});
		} else {
			this.createConfigurationKey(() => {
				this.setToStorage(configurationJSON, () => {
					this.applyConfiguration();
				});
			});
		}

	}

	applyConfiguration () {

		let self = this;

		this.__sendMessage({
			payload: {
				action: 'applyConfiguration',
				configuration: self.storeData.get('configuration').toObject()
			},
			callback: (response) => {
				console.log(response);
			}
		});

	}

	createConfigurationKey (callback) {

		chrome.tabs.getSelected(null, (tab) => {

			let tabUrl = tab.url;
			let linkParser = document.createElement('a');
			linkParser.href = tabUrl;

			this.storeData = this.storeData.update('configurationKey', c => MD5(linkParser.host));

			callback();

		});
	}

	getFromStorage (callback) {

		let configurationKey = this.storeData.get('configurationKey');

		chrome.storage.local.get(configurationKey, (data) => {
			callback.call(null, data);
		});

	}

	setToStorage (cofigurationJSON, callback) {

		let configurationKey = this.storeData.get('configurationKey');

		let configurationObject = {};
		configurationObject[configurationKey] = cofigurationJSON;

		chrome.storage.local.set(configurationObject, () => {
			callback();
		});

	}

	__sendMessage ({payload, callback}) {

		chrome.tabs.getSelected(null, (tab) => {

			chrome.tabs.sendMessage(tab.id, payload, response => {

				if (typeof callback === 'function') {
					callback.call(null, response);
				}

			});

		});

	}

	addField () {

		let stylesheetModel = {
			src: '',
			overrideOriginal: true,
			key: '' + Math.floor(Math.random() * 10e7) + (new Date()).getTime()
		};

		this.storeData = this.storeData.updateIn(['configuration', 'styleSheets'], stylesheets => {
			return stylesheets.push(stylesheetModel), stylesheets
		});

		this.emitChange();
	}

	removeField (key) {

		this.storeData = this.storeData.updateIn(['configuration', 'styleSheets'], stylesheets => {

			let stylesheetIndex = stylesheets.findIndex(stylesheet => {
				return stylesheet.key === key;
			});

			if (!!~stylesheetIndex) {
				stylesheets.splice(stylesheetIndex, 1);
			}

			return stylesheets;

		});

		this.emitChange();

	}

	addInputValue ({key, value}) {

		this.storeData = this.storeData.updateIn(['configuration', 'styleSheets'], styleSheets => {

			let stylesheetIndex = styleSheets.findIndex(stylesheet => {
				return stylesheet.key === key;
			});

			if (!!~stylesheetIndex) {
				styleSheets[stylesheetIndex].src = value;
			}

			return styleSheets;

		});

		this.emitChange();

	}

	setEnable (enable) {

		this.storeData = this.storeData.updateIn(['configuration', 'enable'], v => enable);

		this.emitChange();

	}

	setAutoUpdate (autoUpdate) {

		this.storeData = this.storeData.updateIn(['configuration', 'autoUpdate'], v => autoUpdate);

		this.emitChange();

	}

	setUpdateFrequency (updateFrequency) {

		this.storeData = this.storeData.updateIn(['configuration', 'updateFrequency'], v => updateFrequency);

		this.emitChange();

	}

	getStoreData () {

		return this.storeData;

	}

}

export default new AppStore();
<|endoftext|>