<commit_before>import {bisector, tickStep} from "d3-array";
import {interpolateNumber as reinterpolate} from "d3-interpolate";
import {timeYear, timeMonth, timeWeek, timeDay, timeHour, timeMinute, timeSecond, timeMillisecond} from "d3-time";
import {timeFormat} from "d3-time-format";
import {map} from "./array";
import {default as continuous, copy, deinterpolateLinear as deinterpolate} from "./continuous";
import nice from "./nice";

var durationSecond = 1000,
    durationMinute = durationSecond * 60,
    durationHour = durationMinute * 60,
    durationDay = durationHour * 24,
    durationWeek = durationDay * 7,
    durationMonth = durationDay * 30,
    durationYear = durationDay * 365;

function date(t) {
  return new Date(t);
}

function number(t) {
  return t instanceof Date ? +t : +new Date(+t);
}

export function calendar(year, month, week, day, hour, minute, second, millisecond, format) {
  var scale = continuous(deinterpolate, reinterpolate),
      invert = scale.invert,
      domain = scale.domain;

  var formatMillisecond = format(".%L"),
      formatSecond = format(":%S"),
      formatMinute = format("%I:%M"),
      formatHour = format("%I %p"),
      formatDay = format("%a %d"),
      formatWeek = format("%b %d"),
      formatMonth = format("%B"),
      formatYear = format("%Y");

  var tickIntervals = [
    [second,  1,      durationSecond],
    [second,  5,  5 * durationSecond],
    [second, 15, 15 * durationSecond],
    [second, 30, 30 * durationSecond],
    [minute,  1,      durationMinute],
    [minute,  5,  5 * durationMinute],
    [minute, 15, 15 * durationMinute],
    [minute, 30, 30 * durationMinute],
    [  hour,  1,      durationHour  ],
    [  hour,  3,  3 * durationHour  ],
    [  hour,  6,  6 * durationHour  ],
    [  hour, 12, 12 * durationHour  ],
    [   day,  1,      durationDay   ],
    [   day,  2,  2 * durationDay   ],
    [  week,  1,      durationWeek  ],
    [ month,  1,      durationMonth ],
    [ month,  3,  3 * durationMonth ],
    [  year,  1,      durationYear  ]
  ];

  function tickFormat(date) {
    return (second(date) < date ? formatMillisecond
        : minute(date) < date ? formatSecond
        : hour(date) < date ? formatMinute
        : day(date) < date ? formatHour
        : month(date) < date ? (week(date) < date ? formatDay : formatWeek)
        : year(date) < date ? formatMonth
        : formatYear)(date);
  }

  function tickInterval(interval, start, stop, step) {
    if (interval == null) interval = 10;

    // If a desired tick count is specified, pick a reasonable tick interval
    // based on the extent of the domain and a rough estimate of tick size.
    // Otherwise, assume interval is already a time interval and use it.
    if (typeof interval === "number") {
      var target = Math.abs(stop - start) / interval,
          i = bisector(function(i) { return i[2]; }).right(tickIntervals, target);
      if (i === tickIntervals.length) {
        step = tickStep(start / durationYear, stop / durationYear, interval);
        interval = year;
      } else if (i) {
        i = tickIntervals[target / tickIntervals[i - 1][2] < tickIntervals[i][2] / target ? i - 1 : i];
        step = i[1];
        interval = i[0];
      } else {
        step = tickStep(start, stop, interval);
        interval = millisecond;
      }
    }

    return step == null ? interval : interval.every(step);
  }

  scale.invert = function(y) {
    return new Date(invert(y));
  };

  scale.domain = function(_) {
    return arguments.length ? domain(map.call(_, number)) : domain().map(date);
  };

  scale.ticks = function(interval, step) {
    var d = domain(),
        t0 = d[0],
        t1 = d[d.length - 1],
        r = t1 < t0,
        t;
    if (r) t = t0, t0 = t1, t1 = t;
    t = tickInterval(interval, t0, t1, step);
    t = t ? t.range(t0, t1 + 1) : []; // inclusive stop
    return r ? t.reverse() : t;
  };

  scale.tickFormat = function(count, specifier) {
    return specifier == null ? tickFormat : format(specifier);
  };

  scale.nice = function(interval, step) {
    var d = domain();
    return (interval = tickInterval(interval, d[0], d[d.length - 1], step))
        ? domain(nice(d, interval))
        : scale;
  };

  scale.copy = function() {
    return copy(scale, calendar(year, month, week, day, hour, minute, second, millisecond, format));
  };

  return scale;
}

export default function() {
  return calendar(timeYear, timeMonth, timeWeek, timeDay, timeHour, timeMinute, timeSecond, timeMillisecond, timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]);
}
<commit_msg>Allow Tiny Intervals<commit_after>import {bisector, tickStep} from "d3-array";
import {interpolateNumber as reinterpolate} from "d3-interpolate";
import {timeYear, timeMonth, timeWeek, timeDay, timeHour, timeMinute, timeSecond, timeMillisecond} from "d3-time";
import {timeFormat} from "d3-time-format";
import {map} from "./array";
import {default as continuous, copy, deinterpolateLinear as deinterpolate} from "./continuous";
import nice from "./nice";

var durationSecond = 1000,
    durationMinute = durationSecond * 60,
    durationHour = durationMinute * 60,
    durationDay = durationHour * 24,
    durationWeek = durationDay * 7,
    durationMonth = durationDay * 30,
    durationYear = durationDay * 365;

function date(t) {
  return new Date(t);
}

function number(t) {
  return t instanceof Date ? +t : +new Date(+t);
}

export function calendar(year, month, week, day, hour, minute, second, millisecond, format) {
  var scale = continuous(deinterpolate, reinterpolate),
      invert = scale.invert,
      domain = scale.domain;

  var formatMillisecond = format(".%L"),
      formatSecond = format(":%S"),
      formatMinute = format("%I:%M"),
      formatHour = format("%I %p"),
      formatDay = format("%a %d"),
      formatWeek = format("%b %d"),
      formatMonth = format("%B"),
      formatYear = format("%Y");

  var tickIntervals = [
    [second,  1,      durationSecond],
    [second,  5,  5 * durationSecond],
    [second, 15, 15 * durationSecond],
    [second, 30, 30 * durationSecond],
    [minute,  1,      durationMinute],
    [minute,  5,  5 * durationMinute],
    [minute, 15, 15 * durationMinute],
    [minute, 30, 30 * durationMinute],
    [  hour,  1,      durationHour  ],
    [  hour,  3,  3 * durationHour  ],
    [  hour,  6,  6 * durationHour  ],
    [  hour, 12, 12 * durationHour  ],
    [   day,  1,      durationDay   ],
    [   day,  2,  2 * durationDay   ],
    [  week,  1,      durationWeek  ],
    [ month,  1,      durationMonth ],
    [ month,  3,  3 * durationMonth ],
    [  year,  1,      durationYear  ]
  ];

  function tickFormat(date) {
    return (second(date) < date ? formatMillisecond
        : minute(date) < date ? formatSecond
        : hour(date) < date ? formatMinute
        : day(date) < date ? formatHour
        : month(date) < date ? (week(date) < date ? formatDay : formatWeek)
        : year(date) < date ? formatMonth
        : formatYear)(date);
  }

  function tickInterval(interval, start, stop, step) {
    if (interval == null) interval = 10;

    // If a desired tick count is specified, pick a reasonable tick interval
    // based on the extent of the domain and a rough estimate of tick size.
    // Otherwise, assume interval is already a time interval and use it.
    if (typeof interval === "number") {
      var target = Math.abs(stop - start) / interval,
          i = bisector(function(i) { return i[2]; }).right(tickIntervals, target);
      if (i === tickIntervals.length) {
        step = tickStep(start / durationYear, stop / durationYear, interval);
        interval = year;
      } else if (i) {
        i = tickIntervals[target / tickIntervals[i - 1][2] < tickIntervals[i][2] / target ? i - 1 : i];
        step = i[1];
        interval = i[0];
      } else {
        step = Math.max(tickStep(start, stop, interval), 1);
        interval = millisecond;
      }
    }

    return step == null ? interval : interval.every(step);
  }

  scale.invert = function(y) {
    return new Date(invert(y));
  };

  scale.domain = function(_) {
    return arguments.length ? domain(map.call(_, number)) : domain().map(date);
  };

  scale.ticks = function(interval, step) {
    var d = domain(),
        t0 = d[0],
        t1 = d[d.length - 1],
        r = t1 < t0,
        t;
    if (r) t = t0, t0 = t1, t1 = t;
    t = tickInterval(interval, t0, t1, step);
    t = t ? t.range(t0, t1 + 1) : []; // inclusive stop
    return r ? t.reverse() : t;
  };

  scale.tickFormat = function(count, specifier) {
    return specifier == null ? tickFormat : format(specifier);
  };

  scale.nice = function(interval, step) {
    var d = domain();
    return (interval = tickInterval(interval, d[0], d[d.length - 1], step))
        ? domain(nice(d, interval))
        : scale;
  };

  scale.copy = function() {
    return copy(scale, calendar(year, month, week, day, hour, minute, second, millisecond, format));
  };

  return scale;
}

export default function() {
  return calendar(timeYear, timeMonth, timeWeek, timeDay, timeHour, timeMinute, timeSecond, timeMillisecond, timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]);
}
<|endoftext|>


<commit_before>
$(function() {
    var chat_container = $('.chat-container');
    if (!chat_container) return;

    var chat_controller = $('

');
    chat_controller.append('');
    chat_controller.append('');

    $('body').append(chat_controller);

    var li_count = null;

    chat_controller.on('click', function(event) {
        $('.chat-container').toggleClass('focus');
        if ($('.chat-container').hasClass('focus')){
            chat_controller.find('span.glyphicon-envelope').removeClass('new-messages');
        }
    });

    var pannel_body = $('

');
    chat_container.append(pannel_body);
    pannel_footer = $('

');
    chat_container.append(pannel_footer);

    var chat_url = $('.chat-container').data('chaturl');
    var post_chat_url = $('.chat-container').data('postchaturl');

    function update_chat_pannel(data){
        pannel_body.children().remove();
        pannel_body.append($(data).find('.panel-body .chat'));

        var li_number = pannel_body.find('li').length;
        if (li_count && li_count<li_number){
            if (!$('.chat-container').hasClass('focus')){
                chat_controller.find('span.glyphicon-envelope').addClass('new-messages');
            }
        }
        li_count = li_number;

        pannel_footer.children().remove();
        pannel_footer.append($(data).find('.panel-footer form'));
        pannel_body.animate({
            scrollTop: pannel_body[0].scrollHeight
        }, 500);
        setTimeout($.get, 60000, chat_url, update_chat_pannel);
    }

    $.get(chat_url, update_chat_pannel);

    $('.panel-footer').on('click', '#btn-chat', function(){
        $.post(
            post_chat_url,
            $('.panel-footer form').serialize(),
            update_chat_pannel
        )
        return false;
    });

})
<commit_msg>small js fix<commit_after>
$(function() {
    var chat_container = $('.chat-container');
    if (!chat_container.length) return;

    var chat_controller = $('

');
    chat_controller.append('');
    chat_controller.append('');

    $('body').append(chat_controller);

    var li_count = null;

    chat_controller.on('click', function(event) {
        $('.chat-container').toggleClass('focus');
        if ($('.chat-container').hasClass('focus')){
            chat_controller.find('span.glyphicon-envelope').removeClass('new-messages');
        }
    });

    var pannel_body = $('

');
    chat_container.append(pannel_body);
    pannel_footer = $('

');
    chat_container.append(pannel_footer);

    var chat_url = $('.chat-container').data('chaturl');
    var post_chat_url = $('.chat-container').data('postchaturl');

    function update_chat_pannel(data){
        pannel_body.children().remove();
        pannel_body.append($(data).find('.panel-body .chat'));

        var li_number = pannel_body.find('li').length;
        if (li_count && li_count<li_number){
            if (!$('.chat-container').hasClass('focus')){
                chat_controller.find('span.glyphicon-envelope').addClass('new-messages');
            }
        }
        li_count = li_number;

        pannel_footer.children().remove();
        pannel_footer.append($(data).find('.panel-footer form'));
        pannel_body.animate({
            scrollTop: pannel_body[0].scrollHeight
        }, 500);
        setTimeout($.get, 60000, chat_url, update_chat_pannel);
    }

    $.get(chat_url, update_chat_pannel);

    $('.panel-footer').on('click', '#btn-chat', function(){
        $.post(
            post_chat_url,
            $('.panel-footer form').serialize(),
            update_chat_pannel
        )
        return false;
    });

})
<|endoftext|>


<commit_before>var Formulae = Formulae || {};

Formulae.tree = (function () {

	var transverser = function () {
		var i, j, d;
		var started = {};
		var resolved = {};

		Formulae.tree.cache = function (i, j) {
			return resolved[Formulae.cells.toCell(i, j)];
		};

		var resolve = function (i, j) {
			var cell = Formulae.cells.toCell(i, j), content;
			if (resolved[cell]) {
				return;
			}

			started[cell] = true;
			content = resolveContent(i, j, cell);
			Formulae.tableAccess.set(i, j, content);
			resolved[cell] = content;
		};

		var resolveContent = function (i, j, cell) {
			var content = Formulae.tableAccess.get(i, j);
			if (content[0] !== '=') {
				return content;
			}

			var result;
			try {
				result = Formulae.parseExpression(content.substr(1));
			} catch (ex) {
				return Formulae.errors.cell(cell, ex);
			}

			var dependencies = Formulae.utils.flatten(result).filter(function (el) {
				return typeof el === 'function';
			}).map(function (fn) {
				return fn.cell;
			});
			dependencies.forEach(function (dep) {
				if (typeof resolved[dep] === 'undefined') {
					if (started[dep]) {
						return Formulae.errors.cell(cell, { message : 'cyclic_dependency', args: [ dep ] });
					}
					var arr = Formulae.cells.cellToArray(dep);
					resolve(arr[0], arr[1]);
				}
				if (Formulae.tree.cache.isError) {
					return Formulae.errors.cell(cell, { message : 'error_in_dependency', args: [ dep ] });
				}
			});

			try {
				return Formulae.main.unravel(result);
			} catch (ex) {
				return Formulae.errors.cell(cell, ex);
			}
		};

		for (i = 1; i <= Formulae.tableAccess.columns(); i++) {
			for (j = 1; j <= Formulae.tableAccess.rows(); j++) {
				resolve(i, j);
			}
		}
	};

	return transverser;

})();<commit_msg>Fix error in error handling<commit_after>var Formulae = Formulae || {};

Formulae.tree = (function () {

	var transverser = function () {
		var i, j, d;
		var started = {};
		var resolved = {};

		Formulae.tree.cache = function (i, j) {
			return resolved[Formulae.cells.toCell(i, j)];
		};

		var resolve = function (i, j) {
			var cell = Formulae.cells.toCell(i, j), content;
			if (resolved[cell]) {
				return;
			}

			started[cell] = true;
			content = resolveContent(i, j, cell);
			Formulae.tableAccess.set(i, j, content);
			resolved[cell] = content;
		};

		var resolveContent = function (i, j, cell) {
			var content = Formulae.tableAccess.get(i, j);
			if (content[0] !== '=') {
				return content;
			}

			var result;
			try {
				result = Formulae.parseExpression(content.substr(1));
			} catch (ex) {
				return Formulae.errors.cell(cell, ex);
			}

			var dependencies = Formulae.utils.flatten(result).filter(function (el) {
				return typeof el === 'function';
			}).map(function (fn) {
				return fn.cell;
			});
			dependencies.forEach(function (dep) {
				var arr = Formulae.cells.cellToArray(dep);
				if (typeof resolved[dep] === 'undefined') {
					if (started[dep]) {
						return Formulae.errors.cell(cell, { message : 'cyclic_dependency', args: [ dep ] });
					}
					resolve(arr[0], arr[1]);
				}
				if (Formulae.tree.cache(arr[0], arr[1]).isError) {
					return Formulae.errors.cell(cell, { message : 'error_in_dependency', args: [ dep ] });
				}
			});

			try {
				return Formulae.main.unravel(result);
			} catch (ex) {
				return Formulae.errors.cell(cell, ex);
			}
		};

		for (i = 1; i <= Formulae.tableAccess.columns(); i++) {
			for (j = 1; j <= Formulae.tableAccess.rows(); j++) {
				resolve(i, j);
			}
		}
	};

	return transverser;

})();<|endoftext|>


<commit_before>'use strict';

const Type = { config };

function config(Player, Npc, Item, Account) {
  Type.isPlayer  = is(Player);
  Type.isNpc     = is(Npc);
  Type.isItem    = is(Item);
  Type.isAccount = is(Account);

}

exports.Type = Type;

/**
 * Takes a constructor and a thing and returns function
 * which then returns a boolean (partial application station)
 * @param typeClass constructor functions
 * @param thing     object
 * @return boolean True is thing is of typeClass
 */

function is(typeClass) {
  console.log(typeClass);
  return thing => thing ?
    thing instanceof typeClass :
    false;
}
<commit_msg>Rm console log from debugging.<commit_after>'use strict';

const Type = { config };

function config(Player, Npc, Item, Account) {
  Type.isPlayer  = is(Player);
  Type.isNpc     = is(Npc);
  Type.isItem    = is(Item);
  Type.isAccount = is(Account);
}

exports.Type = Type;

/**
 * Takes a constructor and a thing and returns function
 * which then returns a boolean (partial application station)
 * @param typeClass constructor functions
 * @param thing     object
 * @return boolean True is thing is of typeClass
 */

function is(typeClass) {
  return thing => thing ?
    thing instanceof typeClass :
    false;
}
<|endoftext|>


<commit_before>let js_type={
	number:'number',
	string:'string',
	object:'object',
	'undefined':'undefined',
	bool:'boolean',
	symbol:'symbol',
	fn:'function',
	array:Array
};

let alias={
	u8:js_type.number,
	u16:js_type.number,
	u32:js_type.number,
	u64:js_type.number,
	i8:js_type.number,
	i16:js_type.number,
	i32:js_type.number,
	i64:js_type.number,
	f32:js_type.number,
	f64:js_type.number,
	usize:js_type.number,
	isize:js_type.number,
	char:js_type.string,
	str:js_type.string
};

export default alias;
<commit_msg>Add `any`<commit_after>let js_type={
	number:'number',
	string:'string',
	object:'object',
	'undefined':'undefined',
	bool:'boolean',
	symbol:'symbol',
	fn:'function',
	array:Array
};

let alias={
	u8:js_type.number,
	u16:js_type.number,
	u32:js_type.number,
	u64:js_type.number,
	i8:js_type.number,
	i16:js_type.number,
	i32:js_type.number,
	i64:js_type.number,
	f32:js_type.number,
	f64:js_type.number,
	usize:js_type.number,
	isize:js_type.number,
	char:js_type.string,
	str:js_type.string,
	any:'any'
};

export default alias;
<|endoftext|>


<commit_before>const pg = require("pg")
const fs = require("fs")
const crypto = require("crypto")
const bluebird = require("bluebird")
const path = require("path")
const SQL = require("sql-template-strings")
const dedent = require("dedent-js")

module.exports = migrate

function migrate(dbConfig = {}, migrationsDirectory, config = {}) { // eslint-disable-line complexity
  if (
    typeof dbConfig.database !== "string" ||
    typeof dbConfig.user !== "string" ||
    typeof dbConfig.password !== "string" ||
    typeof dbConfig.host !== "string" ||
    typeof dbConfig.port !== "number"
  ) {
    return Promise.reject(new Error("Database config problem"))
  }
  if (typeof migrationsDirectory !== "string") {
    return Promise.reject(new Error("Must pass migrations directory as a string"))
  }

  const log = config.logger || (() => {})

  const client = bluebird.promisifyAll(new pg.Client(dbConfig))

  log("Attempting database migration")

  return client.connectAsync()
    .then(() => log("Connected to database"))
    .then(() => loadMigrationFiles(migrationsDirectory, log))
    .then(filterMigrations(client))
    .then(runMigrations(client, log))
    .then(() => client.end())
    .then(() => log("Successfully applied all migrations"))
    .catch((err) => {
      log(`Migration failed. Reason: ${err.message}`)
      throw err
    })
}

// Work out which migrations to apply
function filterMigrations(client) {
  return (migrations) => {
    // Arrange in ID order
    const orderedMigrations = migrations.sort((a, b) => a.id - b.id)

    // Assert their IDs are consecutive integers
    migrations.forEach((mig, i) => {
      if (mig.id !== i) {
        throw new Error("Found a non-consecutive migration ID")
      }
    })

    return doesTableExist(client, "migrations")
      .then((exists) => {
        if (!exists) {
          // Migrations table hasn't been created,
          // so the database is new and we need to run all migrations
          return orderedMigrations
        }

        return client.queryAsync("SELECT * FROM migrations")
          .then(filterUnappliedMigrations(orderedMigrations))
      })
  }
}

// Remove migrations that have already been applied
function filterUnappliedMigrations(orderedMigrations) {
  return ({rows: appliedMigrations}) => {
    return orderedMigrations.filter((mig) => {
      const migRecord = appliedMigrations[mig.id]
      if (!migRecord) {
        return true
      }
      if (migRecord.hash !== mig.hash) {
        // Someone has altered a migration which has already run - gasp!
        throw new Error(dedent`
          Hashes don't match for migration '${mig.name}'.
          This means that the script has changed since it was applied.`)
      }
      return false
    })
  }
}

// For each migration, inside a transaction:
// - run migration
// - add to migration table
function runMigrations(client, log) {
  return (migrationsToRun) => bluebird.each(migrationsToRun, (migration) => {
    log(`Starting migration: ${migration.name}`)
    return client.queryAsync("START TRANSACTION")
      .then(() => client.queryAsync(migration.sql))
      .then(() => {
        return client.queryAsync(SQL`
          INSERT INTO migrations (id, name, hash)
            VALUES (${migration.id}, ${migration.name}, ${migration.hash})
        `)
      })
      .then(() => client.queryAsync("COMMIT"))
      .then(() => log(`Finished migration: ${migration.name}`))
      .catch((err) => {
        log(`Caught error running migration '${migration.name}' - rolling back.`)
        return client.queryAsync("ROLLBACK")
          .then(() => {
            throw new Error(dedent`
              An error occurred running '${migration.name}'. Rolled back this migration.
              No further migrations were run.
              Reason: ${err.message}`)
          })
      })
  })
}

const readDir = bluebird.promisify(fs.readdir)
function loadMigrationFiles(directory, log) {
  log(`Loading migrations from: ${directory}`)
  return readDir(directory)
    .then((fileNames) => {
      log(`Found migration files: ${fileNames}`)
      return fileNames
        .filter((fileName) => fileName.toLowerCase().endsWith(".sql"))
        .map((fileName) => path.resolve(directory, fileName))
    })
    .then((fileNames) => {
      // Add a special zeroth migration to create the migrations table
      fileNames.unshift(path.resolve("src/migrations", "0_create-migrations-table.sql"))
      return fileNames
    })
    .then((fileNames) => bluebird.map(fileNames, loadFile))
}

const readFile = bluebird.promisify(fs.readFile)
function loadFile(filePath) {
  const fileName = path.basename(filePath, ".sql")

  const id = parseInt(fileName, 10)
  if (isNaN(id)) {
    return Promise.reject(new Error(dedent`
      Migration files should begin with an integer ID.
      Offending file: '${path.basename(filePath)}'`))
  }

  return readFile(filePath, "utf8")
    .then((contents) => {
      const hash = crypto.createHash("sha1")
      hash.update(fileName + contents, "utf8")
      const encodedHash = hash.digest("hex")

      return {
        id,
        name: fileName,
        sql: contents,
        hash: encodedHash,
      }
    })
}

// Check whether table exists in postgres - http://stackoverflow.com/a/24089729
function doesTableExist(client, tableName) {
  return client.queryAsync(SQL`
      SELECT EXISTS (
        SELECT 1
        FROM   pg_catalog.pg_class c
        WHERE  c.relname = ${tableName}
        AND    c.relkind = 'r'
      );
    `)
    .then((result) => {
      return result.rows.length > 0 && result.rows[0].exists
    })
}
<commit_msg>Use __dirname for relative path<commit_after>const pg = require("pg")
const fs = require("fs")
const crypto = require("crypto")
const bluebird = require("bluebird")
const path = require("path")
const SQL = require("sql-template-strings")
const dedent = require("dedent-js")

module.exports = migrate

function migrate(dbConfig = {}, migrationsDirectory, config = {}) { // eslint-disable-line complexity
  if (
    typeof dbConfig.database !== "string" ||
    typeof dbConfig.user !== "string" ||
    typeof dbConfig.password !== "string" ||
    typeof dbConfig.host !== "string" ||
    typeof dbConfig.port !== "number"
  ) {
    return Promise.reject(new Error("Database config problem"))
  }
  if (typeof migrationsDirectory !== "string") {
    return Promise.reject(new Error("Must pass migrations directory as a string"))
  }

  const log = config.logger || (() => {})

  const client = bluebird.promisifyAll(new pg.Client(dbConfig))

  log("Attempting database migration")

  return client.connectAsync()
    .then(() => log("Connected to database"))
    .then(() => loadMigrationFiles(migrationsDirectory, log))
    .then(filterMigrations(client))
    .then(runMigrations(client, log))
    .then(() => client.end())
    .then(() => log("Successfully applied all migrations"))
    .catch((err) => {
      log(`Migration failed. Reason: ${err.message}`)
      throw err
    })
}

// Work out which migrations to apply
function filterMigrations(client) {
  return (migrations) => {
    // Arrange in ID order
    const orderedMigrations = migrations.sort((a, b) => a.id - b.id)

    // Assert their IDs are consecutive integers
    migrations.forEach((mig, i) => {
      if (mig.id !== i) {
        throw new Error("Found a non-consecutive migration ID")
      }
    })

    return doesTableExist(client, "migrations")
      .then((exists) => {
        if (!exists) {
          // Migrations table hasn't been created,
          // so the database is new and we need to run all migrations
          return orderedMigrations
        }

        return client.queryAsync("SELECT * FROM migrations")
          .then(filterUnappliedMigrations(orderedMigrations))
      })
  }
}

// Remove migrations that have already been applied
function filterUnappliedMigrations(orderedMigrations) {
  return ({rows: appliedMigrations}) => {
    return orderedMigrations.filter((mig) => {
      const migRecord = appliedMigrations[mig.id]
      if (!migRecord) {
        return true
      }
      if (migRecord.hash !== mig.hash) {
        // Someone has altered a migration which has already run - gasp!
        throw new Error(dedent`
          Hashes don't match for migration '${mig.name}'.
          This means that the script has changed since it was applied.`)
      }
      return false
    })
  }
}

// For each migration, inside a transaction:
// - run migration
// - add to migration table
function runMigrations(client, log) {
  return (migrationsToRun) => bluebird.each(migrationsToRun, (migration) => {
    log(`Starting migration: ${migration.name}`)
    return client.queryAsync("START TRANSACTION")
      .then(() => client.queryAsync(migration.sql))
      .then(() => {
        return client.queryAsync(SQL`
          INSERT INTO migrations (id, name, hash)
            VALUES (${migration.id}, ${migration.name}, ${migration.hash})
        `)
      })
      .then(() => client.queryAsync("COMMIT"))
      .then(() => log(`Finished migration: ${migration.name}`))
      .catch((err) => {
        log(`Caught error running migration '${migration.name}' - rolling back.`)
        return client.queryAsync("ROLLBACK")
          .then(() => {
            throw new Error(dedent`
              An error occurred running '${migration.name}'. Rolled back this migration.
              No further migrations were run.
              Reason: ${err.message}`)
          })
      })
  })
}

const readDir = bluebird.promisify(fs.readdir)
function loadMigrationFiles(directory, log) {
  log(`Loading migrations from: ${directory}`)
  return readDir(directory)
    .then((fileNames) => {
      log(`Found migration files: ${fileNames}`)
      return fileNames
        .filter((fileName) => fileName.toLowerCase().endsWith(".sql"))
        .map((fileName) => path.resolve(directory, fileName))
    })
    .then((fileNames) => {
      // Add a special zeroth migration to create the migrations table
      fileNames.unshift(path.join(__dirname, "migrations/0_create-migrations-table.sql"))
      return fileNames
    })
    .then((fileNames) => bluebird.map(fileNames, loadFile))
}

const readFile = bluebird.promisify(fs.readFile)
function loadFile(filePath) {
  const fileName = path.basename(filePath, ".sql")

  const id = parseInt(fileName, 10)
  if (isNaN(id)) {
    return Promise.reject(new Error(dedent`
      Migration files should begin with an integer ID.
      Offending file: '${path.basename(filePath)}'`))
  }

  return readFile(filePath, "utf8")
    .then((contents) => {
      const hash = crypto.createHash("sha1")
      hash.update(fileName + contents, "utf8")
      const encodedHash = hash.digest("hex")

      return {
        id,
        name: fileName,
        sql: contents,
        hash: encodedHash,
      }
    })
}

// Check whether table exists in postgres - http://stackoverflow.com/a/24089729
function doesTableExist(client, tableName) {
  return client.queryAsync(SQL`
      SELECT EXISTS (
        SELECT 1
        FROM   pg_catalog.pg_class c
        WHERE  c.relname = ${tableName}
        AND    c.relkind = 'r'
      );
    `)
    .then((result) => {
      return result.rows.length > 0 && result.rows[0].exists
    })
}
<|endoftext|>


<commit_before>const PieceEnum = Object.freeze({
  KING: 'king',
  QUEEN: 'queen',
  ROOK: 'rook',
  BISHOP: 'bishop',
  KNIGHT: 'knight',
  PAWN: 'pawn',
});

// crée le board par défaut (placement initial)
function getDefaultPieces() {
  // fonction qui va définir un square en fonction de sa position dans l'échiquier (i)
  const defineSquare = function defineSquare(_, i) {
    const sq = { };

    // on définit la couleur de la pièce
    if (i < 16) {
      sq.player = 'black';
    } else if (i > 63 - 16) {
      sq.player = 'white';
    }

    // on définit le type de la pièce (grâce à la symétrie)
    // x = pièce haut gauche; 7-x = symétrie horizontale; 63-x = symétrie verticale
    switch (i) {
      case 0:
      case 7 - 0:
      case 63 - 0:
      case (63 - 7) + 0:
        sq.piece = PieceEnum.ROOK;
        break;
      case 1:
      case 7 - 1:
      case 63 - 1:
      case (63 - 7) + 1:
        sq.piece = PieceEnum.KNIGHT;
        break;
      case 2:
      case 7 - 2:
      case 63 - 2:
      case (63 - 7) + 2:
        sq.piece = PieceEnum.BISHOP;
        break;
      case 3:
      case 59:
        sq.piece = PieceEnum.QUEEN;
        break;
      case 4:
      case 60:
        sq.piece = PieceEnum.KING;
        break;
      default:
        break;
    }

    // pions : 8 -> 15 et symétrie
    if ((i >= 8 && i <= 15) || (i >= 63 - 15 && i <= 63 - 8)) {
      sq.piece = PieceEnum.PAWN;
    }
    return sq;
  };

  // on déclare un Array de 64 élements
  // puis on applique la fonction de définition sur chacun des squares
  const squares = [...Array(64)].map(defineSquare);
  return squares;
}

function getX(i) {
  return i % 8;
}

function getY(i) {
  return parseInt(i / 8, 10);
}

function getId(x, y) {
  return (y * 8) + x;
}

export { PieceEnum, getX, getY, getId, getDefaultPieces };
<commit_msg>refactor getDefaultPieces<commit_after>const PieceEnum = Object.freeze({
  KING: 'king',
  QUEEN: 'queen',
  ROOK: 'rook',
  BISHOP: 'bishop',
  KNIGHT: 'knight',
  PAWN: 'pawn',
});

// crée le board par défaut (placement initial)
function getDefaultPieces() {
  // définit la couleur de la pièce
  const definePlayer = function definePlayer(i) {
    if (i < 16) {
      return 'black';
    } else if (i > 63 - 16) {
      return ('white');
    }

    return undefined;
  };

  // on définit le type de la pièce (grâce à la symétrie)
  // x = pièce haut gauche; 7-x = symétrie horizontale; 63-x = symétrie verticale
  const definePiece = function definePiece(i) {
    // pions : 8 -> 15 et symétrie
    if ((i >= 8 && i <= 15) || (i >= 63 - 15 && i <= 63 - 8)) {
      return PieceEnum.PAWN;
    }

    switch (i) {
      case 0:
      case 7 - 0:
      case 63 - 0:
      case (63 - 7) + 0:
        return PieceEnum.ROOK;
      case 1:
      case 7 - 1:
      case 63 - 1:
      case (63 - 7) + 1:
        return PieceEnum.KNIGHT;
      case 2:
      case 7 - 2:
      case 63 - 2:
      case (63 - 7) + 2:
        return PieceEnum.BISHOP;
      case 3:
      case 59:
        return PieceEnum.QUEEN;
      case 4:
      case 60:
        return PieceEnum.KING;
      default:
        return undefined;
    }
  };

  // on déclare un Array de 64 élements
  // puis on applique les fonctions de définition sur chacun des squares
  return [...Array(64)].map((_, i) => ({
    player: definePlayer(i),
    piece: definePiece(i),
  }));
}

function getX(i) {
  return i % 8;
}

function getY(i) {
  return parseInt(i / 8, 10);
}

function getId(x, y) {
  return (y * 8) + x;
}

export { PieceEnum, getX, getY, getId, getDefaultPieces };
<|endoftext|>


<commit_before>'use strict';

var arg = function(val, defaultVal) {
    return val !== undefined ? val : defaultVal;
};

module.exports = {
    arg: arg,

    makeArray: function(length, value) {
        value = arg(value, 0);
        var a = [];

        for (var i = 0; i < length; i++) {
            a[i] = value;
        }
        return a;
    },

    /**
     * Slice array values within given range relative to i
     * @method sliceRelativeRange
     * @param {Array} array
     * @param {Number} i - index
     * @param {Number} range - number of array values to include before and after i
     * @return {Array}
     */
    sliceRelativeRange: function(array, i, range) {
        var minI = Math.max(i - range, 0);
        var maxI = i + range + 1;
        return array.slice(minI, maxI);
    },
    arrayChunk: function(array, startIndex, endIndex) {
        var minI = Math.max(startIndex, 0);
        var maxI = endIndex + 1;
        return array.slice(minI, maxI);
    },
    arrayFilterIndexes: function(arr, func) {
        var out = [];
        arr.forEach(function(val, i) {
            if (func(val, i, arr)) {
                out.push(i);
            }
        });
        return out;
    },
    arraySum: function(arr, defaultVal) {
        return arr.reduce(function(prev, current){
            return prev + current
        }, defaultVal);
    }

};<commit_msg>fix default value in arraySum<commit_after>'use strict';

var arg = function(val, defaultVal) {
    return val !== undefined ? val : defaultVal;
};

module.exports = {
    arg: arg,

    makeArray: function(length, value) {
        value = arg(value, 0);
        var a = [];

        for (var i = 0; i < length; i++) {
            a[i] = value;
        }
        return a;
    },

    /**
     * Slice array values within given range relative to i
     * @method sliceRelativeRange
     * @param {Array} array
     * @param {Number} i - index
     * @param {Number} range - number of array values to include before and after i
     * @return {Array}
     */
    sliceRelativeRange: function(array, i, range) {
        var minI = Math.max(i - range, 0);
        var maxI = i + range + 1;
        return array.slice(minI, maxI);
    },
    arrayChunk: function(array, startIndex, endIndex) {
        var minI = Math.max(startIndex, 0);
        var maxI = endIndex + 1;
        return array.slice(minI, maxI);
    },
    arrayFilterIndexes: function(arr, func) {
        var out = [];
        arr.forEach(function(val, i) {
            if (func(val, i, arr)) {
                out.push(i);
            }
        });
        return out;
    },
    arraySum: function(arr, defaultVal) {
        defaultVal = arg(defaultVal, 0);
        return arr.reduce(function(prev, current){
            return prev + current
        }, defaultVal);
    }

};<|endoftext|>


<commit_before>'use strict';
let fs = require('fs');
let async = require('async');

const fullURL   = /http[s]?:\/\/codepen\.io\/(.*)\/(.*)\/(.*)/;
const domainURL = /codepen\.io\/(.*)\/(.*)\/(.*)/;
const penURL    = /\/(.*)\/(.*)\/(.*)/;

const normalURL = /htt[s]?:\/\/(.*)/;

module.exports = {

  evaluateOptions(options) {
    if (options === null || options === undefined)
      return this.defaultOptions;

    for(let opt in this.defaultOptions) {
      if (!options.hasOwnProperty(opt)) {
        options[opt] = this.defaultOptions[opt];
      };
    };

    return options;
  },

  parseUrl(url) {
    if (fullURL.exec(url) !== null) {
      return url;
    } else if (domainURL.exec(url) !== null){
      return `http://${url}`;
    } else if (penURL.exec(url) !== null) {
      return `http://codepen.io${url}`;
    } else {
      throw new Error('Invalid URL');
    }
  },

  createDirectoryIfMissing(destination, callback) {
    fs.readdir(destination, (err) => {
      if (!err) return callback();
      fs.mkdir(destination, (err) => {
        callback(err);
      });
    });
  },

  parseScriptUrl(url) {
    if (normalURL.exec(url) === null)
      return `http:${url}`;
    else
      return url;
  },

  createScriptTag(result) {
    let scripts = "";
    if (result.deps) {
      result.deps.resources.forEach((d) => {
        d.url = this.parseScriptUrl(d.url);
        if (d.resource_type === 'js')
        scripts = `${scripts}\n \
        <script src=${d.url}></script>`;
      });
    }
    return scripts;
  },

  createIndexHtmlFile(file, result, fn) {
    async.parallel([
      (callback) => fs.readFile(__dirname + '/template/head01.html', callback),
      (callback) => fs.readFile(__dirname + '/template/head02.html', callback),
      (callback) => fs.readFile(__dirname + '/template/foot.html', callback)
    ], (err, data) => {
      if(err) return fn(err);
      this.removeFileIfExists(file, (err) => {
        if (err) return fn(err);
        fs.appendFileSync(file, data[0]);
        fs.appendFileSync(file, this.createScriptTag(result));
        fs.appendFileSync(file, data[1]);
        fs.appendFileSync(file, result.html);
        fs.appendFileSync(file, data[2]);
        fn(null, file);
      });
    });
  },

  createFile(file, data, fn) {
    this.removeFileIfExists(file, (err) => {
      if (err) return fn(err);
      fs.appendFile(file, data, fn);
    });
  },

  removeFileIfExists(file, fn) {
    fs.stat(file, (err) => {
      if(!err) {
        fs.unlink(file, fn);
      } else if (err.code !== "ENOENT") {
        fn(err);
      } else {
        fn(null);
      }
    });
  },

  defaultOptions : {
    targetFiles : ['html', 'css', 'js'],
    includeDependencies : true,
    includePreProcessed : true,
    onTick : null
  }

};
<commit_msg>fix property name<commit_after>'use strict';
let fs = require('fs');
let async = require('async');

const fullURL   = /http[s]?:\/\/codepen\.io\/(.*)\/(.*)\/(.*)/;
const domainURL = /codepen\.io\/(.*)\/(.*)\/(.*)/;
const penURL    = /\/(.*)\/(.*)\/(.*)/;

const normalURL = /htt[s]?:\/\/(.*)/;

module.exports = {

  evaluateOptions(options) {
    if (options === null || options === undefined)
      return this.defaultOptions;

    for(let opt in this.defaultOptions) {
      if (!options.hasOwnProperty(opt)) {
        options[opt] = this.defaultOptions[opt];
      };
    };

    return options;
  },

  parseUrl(url) {
    if (fullURL.exec(url) !== null) {
      return url;
    } else if (domainURL.exec(url) !== null){
      return `http://${url}`;
    } else if (penURL.exec(url) !== null) {
      return `http://codepen.io${url}`;
    } else {
      throw new Error('Invalid URL');
    }
  },

  createDirectoryIfMissing(destination, callback) {
    fs.readdir(destination, (err) => {
      if (!err) return callback();
      fs.mkdir(destination, (err) => {
        callback(err);
      });
    });
  },

  parseScriptUrl(url) {
    if (normalURL.exec(url) === null)
      return `http:${url}`;
    else
      return url;
  },

  createScriptTag(result) {
    let scripts = "";
    if (result.details) {
      result.details.resources.forEach((d) => {
        d.url = this.parseScriptUrl(d.url);
        if (d.resource_type === 'js')
        scripts = `${scripts}\n \
        <script src=${d.url}></script>`;
      });
    }
    return scripts;
  },

  createIndexHtmlFile(file, result, fn) {
    async.parallel([
      (callback) => fs.readFile(__dirname + '/template/head01.html', callback),
      (callback) => fs.readFile(__dirname + '/template/head02.html', callback),
      (callback) => fs.readFile(__dirname + '/template/foot.html', callback)
    ], (err, data) => {
      if(err) return fn(err);
      this.removeFileIfExists(file, (err) => {
        if (err) return fn(err);
        fs.appendFileSync(file, data[0]);
        fs.appendFileSync(file, this.createScriptTag(result));
        fs.appendFileSync(file, data[1]);
        fs.appendFileSync(file, result.html);
        fs.appendFileSync(file, data[2]);
        fn(null, file);
      });
    });
  },

  createFile(file, data, fn) {
    this.removeFileIfExists(file, (err) => {
      if (err) return fn(err);
      fs.appendFile(file, data, fn);
    });
  },

  removeFileIfExists(file, fn) {
    fs.stat(file, (err) => {
      if(!err) {
        fs.unlink(file, fn);
      } else if (err.code !== "ENOENT") {
        fn(err);
      } else {
        fn(null);
      }
    });
  },

  defaultOptions : {
    targetFiles : ['html', 'css', 'js'],
    includeDependencies : true,
    includePreProcessed : true,
    onTick : null
  }

};
<|endoftext|>


<commit_before>var assert = require('assert')
var _ = require('./_')
var {Cards, Sets} = require('./data')
var BASICS = [
  'Forest',
  'Island',
  'Mountain',
  'Plains',
  'Swamp'
]

function transform(cube) {
  assert(typeof cube.list === 'string', 'typeof cube.list')

  var list = cube.list.split('\n').map(util.name)

  var bad = []
  for (var cardName of list)
    if (!(cardName in Cards))
      bad.push(cardName)

  if (bad.length) {
    var err = `invalid cards: ${bad.splice(-10).join('; ')}`
    if (bad.length)
      err += `; and ${bad.length} more`
    throw Error(err)
  }

  cube.list = list
}

var util = module.exports = {
  name(s) {
    return s.replace(/[Æâàáéíöúû’]/g, c => {
      switch (c) {
      case 'Æ': return 'AE'
      case 'â': case 'à': case 'á': return 'a'
      case 'é': return 'e'
      case 'í': return 'i'
      case 'ö': return 'o'
      case 'ú': case 'û': return 'u'
      case '’': return "'"
      }
    })
  },
  deck(deck, pool) {
    pool = _.count(pool, 'name')

    for (var zoneName in deck) {
      var zone = deck[zoneName]
      for (var cardName in zone) {
        if (typeof zone[cardName] !== 'number')
          return
        if (BASICS.indexOf(cardName) > -1)
          continue
        if (!(cardName in pool))
          return
        pool[cardName] -= zone[cardName]
        if (pool[cardName] < 0)
          return
      }
    }

    return true
  },
  game({id, seats, type, sets, cube}) {
    assert(typeof id === 'string', 'typeof string')
    assert(typeof seats === 'number', 'typeof seats')
    assert(2 <= seats && seats <= 8, 'seats range')
    assert(['draft', 'sealed', 'cube draft', 'cube sealed'].indexOf(type) > -1,
      'indexOf type')

    if (!/cube/.test(type))
      return sets.forEach(set => assert(set in Sets, `${set} in Sets`))

    var {cards, packs} = cube
    assert(typeof cards === 'number', 'typeof cards')
    assert(8 <= cards && cards <= 15, 'cards range')
    assert(typeof packs === 'number', 'typeof packs')
    assert(3 <= packs && packs <= 5, 'packs range')
    transform(cube)
  }
}
<commit_msg>server side cube size validation<commit_after>var assert = require('assert')
var _ = require('./_')
var {Cards, Sets} = require('./data')
var BASICS = [
  'Forest',
  'Island',
  'Mountain',
  'Plains',
  'Swamp'
]

function transform(cube, seats, type) {
  var {list, cards, packs} = cube

  assert(typeof list === 'string', 'typeof list')
  assert(typeof cards === 'number', 'typeof cards')
  assert(8 <= cards && cards <= 15, 'cards range')
  assert(typeof packs === 'number', 'typeof packs')
  assert(3 <= packs && packs <= 5, 'packs range')

  list = cube.list.split('\n').map(util.name)

  var bad = []
  for (var cardName of list)
    if (!(cardName in Cards))
      bad.push(cardName)

  if (bad.length) {
    var err = `invalid cards: ${bad.splice(-10).join('; ')}`
    if (bad.length)
      err += `; and ${bad.length} more`
    throw Error(err)
  }

  var min = type === 'cube draft'
    ? seats * cards * packs
    : seats * 90
  assert(min <= list.length && list.length <= 1e3,
    `this cube needs between ${min} and 1000 cards; it has ${list.length}`)

  cube.list = list
}

var util = module.exports = {
  name(s) {
    return s.replace(/[Æâàáéíöúû’]/g, c => {
      switch (c) {
      case 'Æ': return 'AE'
      case 'â': case 'à': case 'á': return 'a'
      case 'é': return 'e'
      case 'í': return 'i'
      case 'ö': return 'o'
      case 'ú': case 'û': return 'u'
      case '’': return "'"
      }
    })
  },
  deck(deck, pool) {
    pool = _.count(pool, 'name')

    for (var zoneName in deck) {
      var zone = deck[zoneName]
      for (var cardName in zone) {
        if (typeof zone[cardName] !== 'number')
          return
        if (BASICS.indexOf(cardName) > -1)
          continue
        if (!(cardName in pool))
          return
        pool[cardName] -= zone[cardName]
        if (pool[cardName] < 0)
          return
      }
    }

    return true
  },
  game({id, seats, type, sets, cube}) {
    assert(typeof id === 'string', 'typeof string')
    assert(typeof seats === 'number', 'typeof seats')
    assert(2 <= seats && seats <= 8, 'seats range')
    assert(['draft', 'sealed', 'cube draft', 'cube sealed'].indexOf(type) > -1,
      'indexOf type')

    if (/cube/.test(type))
      transform(cube, seats, type)
    else
      sets.forEach(set => assert(set in Sets, `${set} in Sets`))
  }
}
<|endoftext|>


<commit_before>import { NON_DIMENSION_PROPS } from './constants';

/** Copy own-properties from `props` onto `obj`.
 *	@returns obj
 *	@private
 */
export function extend(obj, props) {
	for (let i in props) if (hasOwnProperty.call(props, i)) {
		obj[i] = props[i];
	}
	return obj;
}

/** Fast clone. Note: does not filter out non-own properties. */
export function clone(obj) {
	let out = {};
	/*eslint guard-for-in:0*/
	for (let i in obj) out[i] = obj[i];
	return out;
}

/** Create a caching wrapper for the given function.
 *	@private
 */
export function memoize(fn, mem) {
	mem = mem || {};
	return k => hasOwnProperty.call(mem, k) ? mem[k] : (mem[k] = fn(k));
}

/** Get a deep property value from the given object, expressed in dot-notation.
 *	@private
 */
export function delve(obj, key) {
	for (let p=key.split('.'), i=0; i<p.length && obj; i++) {
		obj = obj[p];
	}
	return obj;
}

/** Convert an Array-like object to an Array
 *	@private
 */
export function toArray(obj) {
	let arr = [],
		i = obj.length;
	while (i--) arr[i] = obj[i];
	return arr;
}

/** @private is the given object a Function? */
export const isFunction = obj => 'function'===typeof obj;

/** @private is the given object a String? */
export const isString = obj => 'string'===typeof obj;

/** @private Safe reference to builtin hasOwnProperty */
export const hasOwnProperty = {}.hasOwnProperty;

/** Check if a value is `null` or `undefined`.
 *	@private
 */
export const empty = x => x==null;

/** Check if a value is `null`, `undefined`, or explicitly `false`. */
export const falsey = value => value===false || value==null;

/** Convert a hashmap of styles to CSSText
 *	@private
 */
export function styleObjToCss(s) {
	let str = '';
	for (let prop in s) {
		if (hasOwnProperty.call(s, prop)) {
			let val = s[prop];
			if (!empty(val)) {
				str += jsToCss(prop);
				str += ': ';
				str += val;
				if (typeof val==='number' && !NON_DIMENSION_PROPS[prop]) {
					str += 'px';
				}
				str += '; ';
			}
		}
	}
	return str;
}

/** Convert a hashmap of CSS classes to a space-delimited className string
 *	@private
 */
export function hashToClassName(c) {
	let str = '';
	for (let prop in c) {
		if (c[prop]) {
			if (str) str += ' ';
			str += prop;
		}
	}
	return str;
}

/** Convert a JavaScript camel-case CSS property name to a CSS property name
 *	@private
 *	@function
 */
export const jsToCss = memoize( s => s.replace(/([A-Z])/g,'-$1').toLowerCase() );

/** Just a memoized String.prototype.toLowerCase */
export const toLowerCase = memoize( s => s.toLowerCase() );

// For animations, rAF is vastly superior. However, it scores poorly on benchmarks :(
// export const setImmediate = typeof requestAnimationFrame==='function' ? requestAnimationFrame : setTimeout;

let ch;
try { ch = new MessageChannel(); } catch (e) {}

/** Call a function asynchronously, as soon as possible.
 *	@param {Function} callback
 */
export const setImmediate = ch ? ( f => {
	ch.port1.onmessage = f;
	ch.port2.postMessage('');
}) : setTimeout;
<commit_msg>Update util.js have a error<commit_after>import { NON_DIMENSION_PROPS } from './constants';

/** Copy own-properties from `props` onto `obj`.
 *	@returns obj
 *	@private
 */
export function extend(obj, props) {
	for (let i in props) if (hasOwnProperty.call(props, i)) {
		obj[i] = props[i];
	}
	return obj;
}

/** Fast clone. Note: does not filter out non-own properties. */
export function clone(obj) {
	let out = {};
	/*eslint guard-for-in:0*/
	for (let i in obj) out[i] = obj[i];
	return out;
}

/** Create a caching wrapper for the given function.
 *	@private
 */
export function memoize(fn, mem) {
	mem = mem || {};
	return k => hasOwnProperty.call(mem, k) ? mem[k] : (mem[k] = fn(k));
}

/** Get a deep property value from the given object, expressed in dot-notation.
 *	@private
 */
export function delve(obj, key) {
	for (let p=key.split('.'), i=0; i<p.length && obj; i++) {
		obj = obj[p[i]];
	}
	return obj;
}

/** Convert an Array-like object to an Array
 *	@private
 */
export function toArray(obj) {
	let arr = [],
		i = obj.length;
	while (i--) arr[i] = obj[i];
	return arr;
}

/** @private is the given object a Function? */
export const isFunction = obj => 'function'===typeof obj;

/** @private is the given object a String? */
export const isString = obj => 'string'===typeof obj;

/** @private Safe reference to builtin hasOwnProperty */
export const hasOwnProperty = {}.hasOwnProperty;

/** Check if a value is `null` or `undefined`.
 *	@private
 */
export const empty = x => x==null;

/** Check if a value is `null`, `undefined`, or explicitly `false`. */
export const falsey = value => value===false || value==null;

/** Convert a hashmap of styles to CSSText
 *	@private
 */
export function styleObjToCss(s) {
	let str = '';
	for (let prop in s) {
		if (hasOwnProperty.call(s, prop)) {
			let val = s[prop];
			if (!empty(val)) {
				str += jsToCss(prop);
				str += ': ';
				str += val;
				if (typeof val==='number' && !NON_DIMENSION_PROPS[prop]) {
					str += 'px';
				}
				str += '; ';
			}
		}
	}
	return str;
}

/** Convert a hashmap of CSS classes to a space-delimited className string
 *	@private
 */
export function hashToClassName(c) {
	let str = '';
	for (let prop in c) {
		if (c[prop]) {
			if (str) str += ' ';
			str += prop;
		}
	}
	return str;
}

/** Convert a JavaScript camel-case CSS property name to a CSS property name
 *	@private
 *	@function
 */
export const jsToCss = memoize( s => s.replace(/([A-Z])/g,'-$1').toLowerCase() );

/** Just a memoized String.prototype.toLowerCase */
export const toLowerCase = memoize( s => s.toLowerCase() );

// For animations, rAF is vastly superior. However, it scores poorly on benchmarks :(
// export const setImmediate = typeof requestAnimationFrame==='function' ? requestAnimationFrame : setTimeout;

let ch;
try { ch = new MessageChannel(); } catch (e) {}

/** Call a function asynchronously, as soon as possible.
 *	@param {Function} callback
 */
export const setImmediate = ch ? ( f => {
	ch.port1.onmessage = f;
	ch.port2.postMessage('');
}) : setTimeout;
<|endoftext|>


<commit_before>/*-----------------------------------------------------------------

Modular - JS Extension
Made by @esr360
http://github.com/esr360/Modular/

-----------------------------------------------------------------*/

//-----------------------------------------------------------------
// Convert CSS config to JS
//-----------------------------------------------------------------

// Get styles' configuration
var stylesConfigJSON = document.getElementById("stylesConfigJSON");

// Remove quotes from computed JSON
function removeQuotes(json) {
    json = json.replace(/^['"]+|\s+|\\|(;\s?})+|['"]$/g, '');
    return json;
}

// Convert computed JSON to camelCase
function camelCase(json) {
	json = json.replace(/-([a-z])/g, function (g) {
		return g[1].toUpperCase();
	});
	return json;
}

// Convert the config to JS
function getStylesConfig(camelCase) {
    var style = null;
    style = window.getComputedStyle(stylesConfigJSON, '::before');
    style = style.content;
	style = removeQuotes(style);
	if(camelCase) {
		style = camelCase(style);
	}
    return JSON.parse(style);
}

// Store configuartion data in a variable
var module = getStylesConfig();<commit_msg>CamelCase the config<commit_after>/*-----------------------------------------------------------------

Modular - JS Extension
Made by @esr360
http://github.com/esr360/Modular/

-----------------------------------------------------------------*/

//-----------------------------------------------------------------
// Convert CSS config to JS
//-----------------------------------------------------------------

// Get styles' configuration
var stylesConfigJSON = document.getElementById("stylesConfigJSON");

// Remove quotes from computed JSON
function removeQuotes(json) {
    json = json.replace(/^['"]+|\s+|\\|(;\s?})+|['"]$/g, '');
    return json;
}

// Convert computed JSON to camelCase
function camelCase(json) {
	json = json.replace(/-([a-z])/g, function (g) {
		return g[1].toUpperCase();
	});
	return json;
}

// Convert the config to JS
function getStylesConfig(camelCase) {
    var style = null;
    style = window.getComputedStyle(stylesConfigJSON, '::before');
    style = style.content;
	style = removeQuotes(style);
	if(camelCase) {
		style = camelCase(style);
	}
    return JSON.parse(style);
}

// Store configuartion data in a variable
var module = getStylesConfig();

// CamelCase the config
var moduleCC = getStylesConfig(camelCase);<|endoftext|>


<commit_before>/**
 * Exports: Monster
 */

function Monster(x, y, name) {
    this.x = x || 0;
    this.y = y || 0;
    this.timer = 0;
    this.thrown = false;
}

Monster.prototype.sleepRadius = 10;

Monster.prototype.display = function() {
    if (world.isVisible(this.x, this.y)) {
        display.add(this.x, this.y, this.constructor.name);
    }
};

Monster.prototype.toString = function() {
    return this.name || 'the ' + this.constructor.name.toLowerCase();
};

Monster.prototype.move = function(x, y) {
    this.x = x;
    this.y = y;
};

Monster.prototype.moveBy = function(dx, dy) {
    var x = this.x + dx;
    var y = this.y + dy;
    if (world.isPassable(x, y)) {
        this.move(x, y);
        return true;
    } else {
        return false;
    }
};

Monster.prototype.tryMove = function(x, y) {
    return this.moveBy(x - this.x, y - this.y);
};

Monster.prototype.damage = function(damage) {
    this.awake = true;
    this.hp -= damage;
    if (this.hp <= 0) {
        world.remove(this);
        return true;
    }
    return false;
};

Monster.prototype.act = function(callback) {
    // Do nothing
    callback();
};

/**
 * Perform an attack on a target.
 * @param {Monster} target
 */
Monster.prototype.attack = function(target, base) {
    var place = world.map.get(this.x, this.y);
    var tplace = world.map.get(target.x, target.y);

    if (this.player && place.corrupted) {
        unimportant('You notice that standing in corruption is making you ' +
                    'less effective in combat.');
    }

    var roll = d20();
    var basemod = bonus(this[base] + place.modify(base));
    var tdex = bonus(target.dexterity + tplace.modify('dexterity'));
    var damage = this.weapon.damage() + place.modify('damage') + basemod;
    damage = Math.max(0, damage);

    var qualifier = ' ';
    if (roll === 20) {
        damage *= 2;
        qualifier = 'critically ';
    }

    var attack = roll + basemod + this.level + place.modify('hit');
    var ac = 10 + tdex + target.armor + tplace.modify('ac') +
            (target.thrown ? 0 : 2);
    if (roll === 20 || attack > ac) {
        if (this.player) {
            unimportant('You %shit %s for %d damage.',
                        qualifier, target, damage);
        } else if (target.player) {
            unimportant('%s %shits you for %d damage.',
                        this, qualifier, damage);
        } else {
            unimportant('%s %shits %s for %d damage.',
                        this, qualifier, target, damage);
        }
        target.damage(damage);
    } else {
        if (this.player) {
            unimportant('You %smiss %s.', qualifier, target);
        } else if (target.player) {
            unimportant('%s %smisses you.', this, qualifier);
        } else {
            unimportant('%s %smisses %s.', this, qualifier, target);
        }
    }
};

Monster.prototype.melee = function(target) {
    this.attack(target, 'strength');
};

Monster.prototype.ranged = function(target, callback) {
    if (this.player) {
        unimportant('You throw your disc at %s!', target);
    } else if (target.player) {
        unimportant('%s throws its disc at you!', this);
    } else {
        unimportant('%s throws its disc at %s!', this, target);
    }
    this.attack(target, 'dexterity');
    this.thrown = true;
    if (callback) {
        display.throwDisc(this, target, callback);
    }
};

/**
 * @returns true if the monster is at x, y.
 */
Monster.prototype.isAt = function(x, y) {
    return this.x === x && this.y === y;
};

Monster.prototype.dist = function(m, y) {
    var dx = m.x - this.x;
    var dy = m.y - this.y;
    return Math.sqrt(dx * dx + dy * dy);
};

/**
 * Tile distance (steps to travel).
 */
Monster.prototype.tdist = function(p) {
    return Math.max(Math.abs(p.x - this.x), Math.abs(p.y - this.y));
};
<commit_msg>Update the display before animating.<commit_after>/**
 * Exports: Monster
 */

function Monster(x, y, name) {
    this.x = x || 0;
    this.y = y || 0;
    this.timer = 0;
    this.thrown = false;
}

Monster.prototype.sleepRadius = 10;

Monster.prototype.display = function() {
    if (world.isVisible(this.x, this.y)) {
        display.add(this.x, this.y, this.constructor.name);
    }
};

Monster.prototype.toString = function() {
    return this.name || 'the ' + this.constructor.name.toLowerCase();
};

Monster.prototype.move = function(x, y) {
    this.x = x;
    this.y = y;
};

Monster.prototype.moveBy = function(dx, dy) {
    var x = this.x + dx;
    var y = this.y + dy;
    if (world.isPassable(x, y)) {
        this.move(x, y);
        return true;
    } else {
        return false;
    }
};

Monster.prototype.tryMove = function(x, y) {
    return this.moveBy(x - this.x, y - this.y);
};

Monster.prototype.damage = function(damage) {
    this.awake = true;
    this.hp -= damage;
    if (this.hp <= 0) {
        world.remove(this);
        return true;
    }
    return false;
};

Monster.prototype.act = function(callback) {
    // Do nothing
    callback();
};

/**
 * Perform an attack on a target.
 * @param {Monster} target
 */
Monster.prototype.attack = function(target, base) {
    var place = world.map.get(this.x, this.y);
    var tplace = world.map.get(target.x, target.y);

    if (this.player && place.corrupted) {
        unimportant('You notice that standing in corruption is making you ' +
                    'less effective in combat.');
    }

    var roll = d20();
    var basemod = bonus(this[base] + place.modify(base));
    var tdex = bonus(target.dexterity + tplace.modify('dexterity'));
    var damage = this.weapon.damage() + place.modify('damage') + basemod;
    damage = Math.max(0, damage);

    var qualifier = ' ';
    if (roll === 20) {
        damage *= 2;
        qualifier = 'critically ';
    }

    var attack = roll + basemod + this.level + place.modify('hit');
    var ac = 10 + tdex + target.armor + tplace.modify('ac') +
            (target.thrown ? 0 : 2);
    if (roll === 20 || attack > ac) {
        if (this.player) {
            unimportant('You %shit %s for %d damage.',
                        qualifier, target, damage);
        } else if (target.player) {
            unimportant('%s %shits you for %d damage.',
                        this, qualifier, damage);
        } else {
            unimportant('%s %shits %s for %d damage.',
                        this, qualifier, target, damage);
        }
        target.damage(damage);
    } else {
        if (this.player) {
            unimportant('You %smiss %s.', qualifier, target);
        } else if (target.player) {
            unimportant('%s %smisses you.', this, qualifier);
        } else {
            unimportant('%s %smisses %s.', this, qualifier, target);
        }
    }
};

Monster.prototype.melee = function(target) {
    this.attack(target, 'strength');
};

Monster.prototype.ranged = function(target, callback) {
    if (this.player) {
        unimportant('You throw your disc at %s!', target);
    } else if (target.player) {
        unimportant('%s throws its disc at you!', this);
    } else {
        unimportant('%s throws its disc at %s!', this, target);
    }
    this.attack(target, 'dexterity');
    this.thrown = true;
    if (callback) {
        world.look();
        world.display();
        display.throwDisc(this, target, callback);
    }
};

/**
 * @returns true if the monster is at x, y.
 */
Monster.prototype.isAt = function(x, y) {
    return this.x === x && this.y === y;
};

Monster.prototype.dist = function(m, y) {
    var dx = m.x - this.x;
    var dy = m.y - this.y;
    return Math.sqrt(dx * dx + dy * dy);
};

/**
 * Tile distance (steps to travel).
 */
Monster.prototype.tdist = function(p) {
    return Math.max(Math.abs(p.x - this.x), Math.abs(p.y - this.y));
};
<|endoftext|>


<commit_before>Minionette.View = Backbone.View.extend({
    constructor: function(options) {
        this._initializeRegions(options || {});

        Backbone.View.apply(this, arguments);

        // Have the view listenTo the model and collection.
        this._listenToEvents(this.model, _.result(this, 'modelEvents'));
        this._listenToEvents(this.collection, _.result(this, 'collectionEvents'));
    },

    // The Parent View of this View
    // Defaults to nothing
    _parent: null,

    // A default template that will clear this.$el.
    // Override this in a subclass to something useful.
    template: function() { return ''; },

    // A default function that will have it's return passed
    // to this.template
    // Override this in a subclass to something useful.
    serializeData: function() {
        //TODO: FIX THIS
        return {};
    },

    // When delegating events, bind this view to jQuery's special remove event.
    // Allows us to clean up the view, even if you remove this.$el with jQuery.
    // http://blog.alexmaccaw.com/jswebapps-memory-management
    delegateEvents: function() {
        Backbone.View.prototype.delegateEvents.apply(this, arguments);

        _.bindAll(this, '_jqueryRemove');
        this.$el.on('remove.delegateEvents' + this.cid, this._jqueryRemove);
    },

    // A useful remove method to that triggers events.
    remove: function() {
        this.trigger('remove:before');

        this._removeFromParent();
        _.invoke(this._regions, 'remove');

        Backbone.View.prototype.remove.apply(this, arguments);

        this.trigger('remove');
    },

    // A useful default render method.
    render: function() {
        this.trigger('render:before');

        // Detach all our regions, so they don't need to be re-rendered.
        _.invoke(this._regions, 'detach');

        this.$el.html(this.template(this.serializeData()));

        // Reattach all our regions
        _.invoke(this._regions, 'reattach');

        this.trigger('render');
        return this;
    },

    // A remove helper to remove this view from it's parent
    _removeFromParent: function() {
        if (this._parent && this._parent._removeView) {
            this._parent._removeView(this);
            this._parent = null;
        }
    },

    // Does the same thing as this.remove(), without
    // actually removing the element. Done to prevent
    // us from removing an element that is already removed.
    _jqueryRemove: function() {
        this.trigger('remove:jquery');
        this._removeFromParent();
        this.stopListening();
    },

    // Loop through the events given, and listen to
    // entity's event.
    _listenToEvents: function(entity, events) {
        if (!entity) { return; }
        _.each(events, function(method, event) {
            if (!_.isFunction(method)) { method = this[method]; }
            this.listenTo(entity, event, method);
        }, this);
    },

    // TODO: comments
    _initializeRegions: function(options) {
        // Initialize our regions object
        this._regions = {};

        // Pull regions from instantiated options.
        var regions = {};
        if (options.regions) { regions = options.regions; }

        // Add the regions
        _.each(regions, function(view, name) {
            this.addRegion(name, view);
        }, this);
    },

    addRegion: function(name, view) {
        this[name] = this._regions[name] = new Minionette.Region({view: view});
        return this[name];
    }
});
<commit_msg>Allow regions to be specified when extending<commit_after>Minionette.View = Backbone.View.extend({
    constructor: function(options) {
        this._initializeRegions(options || {});

        Backbone.View.apply(this, arguments);

        // Have the view listenTo the model and collection.
        this._listenToEvents(this.model, _.result(this, 'modelEvents'));
        this._listenToEvents(this.collection, _.result(this, 'collectionEvents'));
    },

    // The Parent View of this View
    // Defaults to nothing
    _parent: null,

    // A default template that will clear this.$el.
    // Override this in a subclass to something useful.
    template: function() { return ''; },

    // A default function that will have it's return passed
    // to this.template
    // Override this in a subclass to something useful.
    serializeData: function() {
        //TODO: FIX THIS
        return {};
    },

    // When delegating events, bind this view to jQuery's special remove event.
    // Allows us to clean up the view, even if you remove this.$el with jQuery.
    // http://blog.alexmaccaw.com/jswebapps-memory-management
    delegateEvents: function() {
        Backbone.View.prototype.delegateEvents.apply(this, arguments);

        _.bindAll(this, '_jqueryRemove');
        this.$el.on('remove.delegateEvents' + this.cid, this._jqueryRemove);
    },

    // A useful remove method to that triggers events.
    remove: function() {
        this.trigger('remove:before');

        this._removeFromParent();
        _.invoke(this._regions, 'remove');

        Backbone.View.prototype.remove.apply(this, arguments);

        this.trigger('remove');
    },

    // A useful default render method.
    render: function() {
        this.trigger('render:before');

        // Detach all our regions, so they don't need to be re-rendered.
        _.invoke(this._regions, 'detach');

        this.$el.html(this.template(this.serializeData()));

        // Reattach all our regions
        _.invoke(this._regions, 'reattach');

        this.trigger('render');
        return this;
    },

    // A remove helper to remove this view from it's parent
    _removeFromParent: function() {
        if (this._parent && this._parent._removeView) {
            this._parent._removeView(this);
            this._parent = null;
        }
    },

    // Does the same thing as this.remove(), without
    // actually removing the element. Done to prevent
    // us from removing an element that is already removed.
    _jqueryRemove: function() {
        this.trigger('remove:jquery');
        this._removeFromParent();
        this.stopListening();
    },

    // Loop through the events given, and listen to
    // entity's event.
    _listenToEvents: function(entity, events) {
        if (!entity) { return; }
        _.each(events, function(method, event) {
            if (!_.isFunction(method)) { method = this[method]; }
            this.listenTo(entity, event, method);
        }, this);
    },

    // TODO: comments
    _initializeRegions: function(options) {
        // Initialize our regions object
        this._regions = {};

        // Pull regions from instantiated options.
        var regions = this.regions;
        if (options.regions) { regions = options.regions; }

        // Add the regions
        _.each(regions, function(view, name) {
            this.addRegion(name, view);
        }, this);
    },

    addRegion: function(name, view) {
        this[name] = this._regions[name] = new Minionette.Region({view: view});
        return this[name];
    }
});
<|endoftext|>


<commit_before>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
function NormalModuleReplacementPlugin(resourceRegExp, newResource) {
	this.resourceRegExp = resourceRegExp;
	this.newResource = newResource
}
module.exports = NormalModuleReplacementPlugin;
NormalModuleReplacementPlugin.prototype.apply = function(compiler) {
	var resourceRegExp = this.resourceRegExp;
	var newResource = this.newResource;
	compiler.plugin("normal-module-factory", function(nmf) {
		nmf.plugin("before-resolve", function(result, callback) {
			if(!result) return callback();
			if(resourceRegExp.test(result.request)) {
				result.request = newResource;
			}
			return callback(null, result);
		});
		nmf.plugin("after-resolve", function(result, callback) {
			if(!result) return callback();
			if(resourceRegExp.test(result.resource)) {
				result.resource = newResource;
			}
			return callback(null, result);
		});
	});
};<commit_msg>make sure newResource for NormalModuleReplacementPlugin is an absolute path<commit_after>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

var path = require('path');
function NormalModuleReplacementPlugin(resourceRegExp, newResource) {
	this.resourceRegExp = resourceRegExp;
	this.newResource = newResource
}
module.exports = NormalModuleReplacementPlugin;
NormalModuleReplacementPlugin.prototype.apply = function(compiler) {
	var resourceRegExp = this.resourceRegExp;
	var newResource = this.newResource;
	compiler.plugin("normal-module-factory", function(nmf) {
		nmf.plugin("before-resolve", function(result, callback) {
			if(!result) return callback();
			if(resourceRegExp.test(result.request)) {
				result.request = path.resolve(newResource);
			}
			return callback(null, result);
		});
		nmf.plugin("after-resolve", function(result, callback) {
			if(!result) return callback();
			if(resourceRegExp.test(result.resource)) {
				result.resource = path.resolve(newResource);
			}
			return callback(null, result);
		});
	});
};
<|endoftext|>


<commit_before>/*globals require, module, setImmediate */

'use strict';

var util, Writable, EventEmitter, check, errors, events, terminators, escapes;

// TODO: Make `isEnd` async (consider promises, don't forget usage)
// TODO: Update calls to `isEnd` to await result
// TODO: Consider when to test `walking` and `finished` (currently in `end`)
// TODO: Consider how `end` should behave in the unfinished case (currently throws)
// NOTE: Exceptions swallowed by `defer`

util = require('util');
Writable = require('stream').Writable;
EventEmitter = require('events').EventEmitter;
check = require('check-types');
errors = require('./errors');
events = require('./events');

terminators = {
    obj: '}',
    arr: ']'
};

escapes = {
    '"': '"',
    '\\': '\\',
    '/': '/',
    'b': '\b',
    'f': '\f',
    'n': '\n',
    'r': '\r',
    't': '\t'
};

module.exports = begin;

function begin () {
    var json, emitter, stream,
        position, scopes, handlers,
        walking, insideString, finished;

    json = '';
    emitter = new EventEmitter();
    stream = new JsonStream(proceed);

    position = {
        index: 0,
        current: {
            line: 1,
            column: 1
        },
        previous: {}
    };
    scopes = [];
    handlers = {
        arr: value,
        obj: property
    };

    stream.on('finish', finish);

    return {
        emitter: emitter,
        stream: stream
    };

    function proceed (chunk) {
        json += chunk;

        if (!walking) {
            walking = true;
            defer(value);
        }
    }

    function finish () {
        finished = true;
    }

    function value () {
        var character;

        ignoreWhitespace();

        character = next();

        switch (character) {
            case '[':
                return array();
            case '{':
                return object();
            case '"':
                return string();
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
            case '-':
            case '.':
                return number(character);
            case 'f':
                return literalFalse();
            case 'n':
                return literalNull();
            case 't':
                return literalTrue();
            default:
                error(character, 'value', 'previous');
                value();
        }
    }

    function ignoreWhitespace () {
        while (isWhitespace(character())) {
            next();
        }
    }

    function next () {
        var result;

        if (isEnd()) {
            end();
        }

        result = character();

        position.index += 1;
        position.previous.line = position.current.line;
        position.previous.column = position.current.column;

        if (result === '\n') {
            position.current.line += 1;
            position.current.column = 1;
        } else {
            position.current.column += 1;
        }

        return result;
    }

    function isEnd (callback) {
        if (walking) {
            return position.index === json.length;
        }

        defer(isEnd.bind(null, callback));
    }

    function end () {
        if (!finished) {
            walking = false;
            return;
        }

        if (insideString) {
            error('EOF', '"', 'current');
        }

        while (scopes.length > 0) {
            error('EOF', terminators[scopes.pop()], 'current');
        }

        emitter.emit(events.end);

        throw events.end;
    }

    function error (actual, expected, positionKey) {
        emitter.emit(
            events.error,
            errors.create(
                actual,
                expected,
                position[positionKey].line,
                position[positionKey].column
            )
        );
    }

    function character () {
        return json[position.index];
    }

    function array () {
        scope(events.array, value);
    }

    function scope (event, contentHandler) {
        emitter.emit(event);
        scopes.push(event);
        if (!endScope(event)) {
            defer(contentHandler);
        }
    }

    function object () {
        scope(events.object, property);
    }

    function property () {
        ignoreWhitespace();
        checkCharacter(next(), '"');

        walkString(events.property);

        ignoreWhitespace();
        checkCharacter(next(), ':');

        defer(value);
    }

    function walkString (event) {
        var quoting, string;

        insideString = true;
        quoting = false;
        string = '';

        while (quoting || character() !== '"') {
            if (quoting) {
                quoting = false;
                string += escape(next());
            } else if (character() === '\\') {
                quoting = true;
                next();
            } else {
                string += next();
            }
        }

        insideString = false;

        emitter.emit(event, string);
    }

    function escape (character) {
        if (escapes[character]) {
            return escapes[character];
        }

        if (character === 'u') {
            return escapeHex();
        }

        error(character, 'escape character', 'previous');

        return '\\' + character;
    }

    function escapeHex () {
        var hexits, i, character;

        hexits = '';

        for (i = 0; i < 4; i += 1) {
            character = next();
            if (isHexit(character)) {
                hexits += character;
            }
        }

        if (hexits.length === 4) {
            return String.fromCharCode(parseInt(hexits, 16));
        }

        error(character, 'hex digit', 'previous');

        return '\\u' + hexits + character;
    }

    function checkCharacter (character, expected) {
        if (character !== expected) {
            return error(character, expected, 'previous');
        }
    }

    function endScope (scope) {
        if (character() === terminators[scope]) {
            emitter.emit(events.endPrefix + scope);
            scopes.pop();
            next();
            defer(endValue);
            return true;
        }

        return false;
    }

    function endValue () {
        var scope;

        ignoreWhitespace();

        if (scopes.length === 0 && !isEnd()) {
            error(character(), 'EOF', 'current');
            return defer(value);
        }

        scope = scopes[scopes.length - 1];

        if (!endScope(scope)) {
            checkCharacter(next(), ',');
            defer(handlers[scope]);
        }
    }

    function string () {
        walkString(events.string);
        next();
        defer(endValue);
    }

    function number (firstCharacter) {
        var digits = firstCharacter + walkDigits();

        if (character() === '.') {
            digits += next() + walkDigits();
        }

        if (character() === 'e' || character() === 'E') {
            digits += next();

            if (character() === '+' || character() === '-') {
                digits += next();
            }

            digits += walkDigits();
        }

        emitter.emit(events.number, parseFloat(digits));
        defer(endValue);
    }

    function walkDigits () {
        var digits = '';

        while (!isEnd() && isDigit(character())) {
            digits += next();
        }

        return digits;
    }

    function literalFalse () {
        literal([ 'a', 'l', 's', 'e' ], false);
    }

    function literal (expectedCharacters, value) {
        var actual, expected, invalid;

        while (expectedCharacters.length > 0 && !isEnd()) {
            actual = next();
            expected = expectedCharacters.shift();

            if (actual !== expected) {
                invalid = true;
                break;
            }
        }

        if (invalid) {
            error(actual, expected, 'previous');
        } else if (expectedCharacters.length > 0) {
            error('EOF', expectedCharacters.shift(), 'current');
        } else {
            emitter.emit(events.literal, value);
        }

        defer(endValue);
    }

    function literalNull () {
        literal([ 'u', 'l', 'l' ], null);
    }

    function literalTrue () {
        literal([ 'r', 'u', 'e' ], true);
    }
}

function JsonStream (write, options) {
    if (!(this instanceof JsonStream)) {
        return new JsonStream();
    }

    this._write = function (chunk, encoding, callback) {
        write(chunk.toString());
    };

    return Writable.call(this);
}

util.inherits(JsonStream, Writable);

function defer (fn) {
    setImmediate(function () {
        try {
            fn();
        } catch (error) {
            /*jshint noempty:false */
        }
    });
}

function isWhitespace (character) {
    switch (character) {
        case ' ':
        case '\t':
        case '\r':
        case '\n':
            return true;
    }

    return false;
}

function isHexit (character) {
    return isDigit(character) || isInRange(character, 'a', 'f');
}

function isDigit (character) {
    return isInRange(character, '0', '9');
}

function isInRange (character, lower, upper) {
    var code = character.charCodeAt(0);

    return code >= lower.charCodeAt(0) && code <= upper.charCodeAt(0);
}

<commit_msg>Start promisified omnistream solution.<commit_after>/*globals require, module, setImmediate */

'use strict';

var util, Writable, EventEmitter, check, errors, events, terminators, escapes;

// TODO: Make `isEnd` async (consider promises, don't forget usage)
// TODO: Update calls to `isEnd` to await result
// TODO: Consider when to test `walking` and `finished` (currently in `end`)
// TODO: Consider how `end` should behave in the unfinished case (currently throws)
// NOTE: Exceptions swallowed by `defer`

util = require('util');
Writable = require('stream').Writable;
EventEmitter = require('events').EventEmitter;
check = require('check-types');
errors = require('./errors');
events = require('./events');

terminators = {
    obj: '}',
    arr: ']'
};

escapes = {
    '"': '"',
    '\\': '\\',
    '/': '/',
    'b': '\b',
    'f': '\f',
    'n': '\n',
    'r': '\r',
    't': '\t'
};

module.exports = begin;

function begin () {
    var json, emitter, stream,
        position, scopes, handlers,
        walking, insideString, finished;

    json = '';
    emitter = new EventEmitter();
    stream = new JsonStream(proceed);

    position = {
        index: 0,
        current: {
            line: 1,
            column: 1
        },
        previous: {}
    };
    scopes = [];
    handlers = {
        arr: value,
        obj: property
    };

    stream.on('finish', finish);

    return {
        emitter: emitter,
        stream: stream
    };

    function proceed (chunk) {
        json += chunk;

        if (!walking) {
            walking = true;
            defer(value);
        }
    }

    function finish () {
        finished = true;
    }

    function value () {
        var character;

        ignoreWhitespace();

        character = next();

        switch (character) {
            case '[':
                return array();
            case '{':
                return object();
            case '"':
                return string();
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
            case '-':
            case '.':
                return number(character);
            case 'f':
                return literalFalse();
            case 'n':
                return literalNull();
            case 't':
                return literalTrue();
            default:
                error(character, 'value', 'previous');
                value();
        }
    }

    function ignoreWhitespace () {
        while (isWhitespace(character())) {
            next();
        }
    }

    // TODO: promisify usage
    function next () {
        var resolve;

        isEnd().then(function (atEnd) {
            var result;

            if (atEnd) {
                end();
            }

            result = character();

            position.index += 1;
            position.previous.line = position.current.line;
            position.previous.column = position.current.column;

            if (result === '\n') {
                position.current.line += 1;
                position.current.column = 1;
            } else {
                position.current.column += 1;
            }

            resolve(result);
        });

        return new Promise(function (r) {
            resolve = r;
        });
    }

    function isEnd () {
        var resolve;

        defer(step);

        return new Promise(function (r) {
            resolve = r;
        });

        function step () {
            if (walking) {
                return resolve(position.index === json.length);
            }

            // TODO: implement delay (parameterise delay length?)
            delay(step);
        }
    }

    function end () {
        if (!finished) {
            walking = false;
            return;
        }

        if (insideString) {
            error('EOF', '"', 'current');
        }

        while (scopes.length > 0) {
            error('EOF', terminators[scopes.pop()], 'current');
        }

        emitter.emit(events.end);

        throw events.end;
    }

    function error (actual, expected, positionKey) {
        emitter.emit(
            events.error,
            errors.create(
                actual,
                expected,
                position[positionKey].line,
                position[positionKey].column
            )
        );
    }

    function character () {
        return json[position.index];
    }

    function array () {
        scope(events.array, value);
    }

    function scope (event, contentHandler) {
        emitter.emit(event);
        scopes.push(event);
        if (!endScope(event)) {
            defer(contentHandler);
        }
    }

    function object () {
        scope(events.object, property);
    }

    function property () {
        ignoreWhitespace();
        checkCharacter(next(), '"');

        walkString(events.property);

        ignoreWhitespace();
        checkCharacter(next(), ':');

        defer(value);
    }

    function walkString (event) {
        var quoting, string;

        insideString = true;
        quoting = false;
        string = '';

        while (quoting || character() !== '"') {
            if (quoting) {
                quoting = false;
                string += escape(next());
            } else if (character() === '\\') {
                quoting = true;
                next();
            } else {
                string += next();
            }
        }

        insideString = false;

        emitter.emit(event, string);
    }

    function escape (character) {
        if (escapes[character]) {
            return escapes[character];
        }

        if (character === 'u') {
            return escapeHex();
        }

        error(character, 'escape character', 'previous');

        return '\\' + character;
    }

    function escapeHex () {
        var hexits, i, character;

        hexits = '';

        for (i = 0; i < 4; i += 1) {
            character = next();
            if (isHexit(character)) {
                hexits += character;
            }
        }

        if (hexits.length === 4) {
            return String.fromCharCode(parseInt(hexits, 16));
        }

        error(character, 'hex digit', 'previous');

        return '\\u' + hexits + character;
    }

    function checkCharacter (character, expected) {
        if (character !== expected) {
            return error(character, expected, 'previous');
        }
    }

    function endScope (scope) {
        if (character() === terminators[scope]) {
            emitter.emit(events.endPrefix + scope);
            scopes.pop();
            next();
            defer(endValue);
            return true;
        }

        return false;
    }

    function endValue () {
        // this will need to be promisified
        ignoreWhitespace();

        if (scopes.length === 0) {
            isEnd().then(function (atEnd) {
                if (!atEnd) {
                    error(character(), 'EOF', 'current');
                    return defer(value);
                }

                step();
            });

            return;
        }

        step();

        function step () {
            var scope = scopes[scopes.length - 1];

            if (!endScope(scope)) {
                checkCharacter(next(), ',');
                defer(handlers[scope]);
            }
        }
    }

    function string () {
        walkString(events.string);
        next();
        defer(endValue);
    }

    function number (firstCharacter) {
        var digits = firstCharacter + walkDigits();

        if (character() === '.') {
            digits += next() + walkDigits();
        }

        if (character() === 'e' || character() === 'E') {
            digits += next();

            if (character() === '+' || character() === '-') {
                digits += next();
            }

            digits += walkDigits();
        }

        emitter.emit(events.number, parseFloat(digits));
        defer(endValue);
    }

    // TODO: promisify usage
    function walkDigits () {
        var digits, resolve;

        digits = ''

        isEnd().then(step);

        return new Promise(function (r) {
            resolve = r;
        });

        function step (atEnd) {
            if (atEnd || !isDigit(character())) {
                return resolve(digits);
            }

            digits += next();
            isEnd().then(step);
        }
    }

    function literalFalse () {
        literal([ 'a', 'l', 's', 'e' ], false);
    }

    function literal (expectedCharacters, value) {
        var actual, expected, invalid;

        isEnd().then(step);

        function step (atEnd) {
            if (expectedCharacters.length === 0 || atEnd) {
                if (invalid) {
                    error(actual, expected, 'previous');
                } else if (expectedCharacters.length > 0) {
                    error('EOF', expectedCharacters.shift(), 'current');
                } else {
                    emitter.emit(events.literal, value);
                }

                return defer(endValue);
            }

            actual = next();
            expected = expectedCharacters.shift();

            if (actual !== expected) {
                invalid = true;
                isEnd().then(step);
            }
        }
    }

    function literalNull () {
        literal([ 'u', 'l', 'l' ], null);
    }

    function literalTrue () {
        literal([ 'r', 'u', 'e' ], true);
    }
}

function JsonStream (write, options) {
    if (!(this instanceof JsonStream)) {
        return new JsonStream();
    }

    this._write = function (chunk, encoding, callback) {
        write(chunk.toString());
    };

    return Writable.call(this);
}

util.inherits(JsonStream, Writable);

function defer (fn) {
    setImmediate(function () {
        try {
            fn();
        } catch (error) {
            /*jshint noempty:false */
        }
    });
}

function isWhitespace (character) {
    switch (character) {
        case ' ':
        case '\t':
        case '\r':
        case '\n':
            return true;
    }

    return false;
}

function isHexit (character) {
    return isDigit(character) || isInRange(character, 'a', 'f');
}

function isDigit (character) {
    return isInRange(character, '0', '9');
}

function isInRange (character, lower, upper) {
    var code = character.charCodeAt(0);

    return code >= lower.charCodeAt(0) && code <= upper.charCodeAt(0);
}

<|endoftext|>