<commit_before>(function() {

var kifu_obj;

module('Kifu.Csa', {
  setup: function() {
    kifu_obj = Kifu();
  }
});

test('parse version', 4, function() {
  var kifu = kifu_obj.kifu();
  var info = kifu['info'];

  // version 2
  var line = 'V2';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['version'], '2', line+' info');

  // version 2.2
  var line = 'V2.2';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['version'], '2.2', line+' info');
});

test('parse player', 4, function() {
  var kifu = kifu_obj.kifu();
  var info = kifu['info'];

  // black player
  var line = 'N+大山康晴';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['player_black'], '大山康晴', line+' info');

  // white player
  var line = 'N-升田幸三';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['player_white'], '升田幸三', line+' info');
});

test('parse info', 18, function() {
  var kifu = kifu_obj.kifu();
  var info = kifu['info'];

  // EVENT
  var line = '$EVENT:名人戦';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['event'], '名人戦', line+' info');

  // SITE
  var line = '$SITE:陣屋';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['site'], '陣屋', line+' info');

  // START_TIME
  var start_time = new Date(2011, 3, 7, 9, 45, 10);
  var line = '$START_TIME:2011/04/07 09:45:10';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['start_time'], start_time, line+' info');

  // START_TIME 2
  var start_time = new Date(2010, 9, 25);
  var line = '$START_TIME:2010/10/25';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['start_time'], start_time, line+' info');

  // END_TIME
  var end_time = new Date(2011, 3, 8, 10, 20, 30);
  var line = '$END_TIME:2011/04/08 10:20:30';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['end_time'], end_time, line+' info');

  // END_TIME 2
  var end_time = new Date(2010, 9, 26);
  var line = '$END_TIME:2010/10/26';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['end_time'], end_time, line+' info');

  // TIME_LIMIT
  var line = '$TIME_LIMIT:06:00+60';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['time_limit'], {allotted: 360, extra: 60}, line+' info');

  // TIME_LIMIT 2
  var line = '$TIME_LIMIT:00:00+00';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['time_limit'], {allotted: 0, extra: 0}, line+' info');

  // OPENING
  var line = '$OPENING:相矢倉';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['opening'], '相矢倉', line+' info');
});

test('parse initial board hirate', 4, function() {
  var kifu  = kifu_obj.kifu();
  var board = Kifu.Board().hirate();

  // hirate
  var line = 'PI';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, line+' board');

  // hirate komaochi
  kifu['board'] = Kifu.Board();
  board.cellRemove(8, 2, 'HI');
  board.cellRemove(2, 2, 'KA');
  var line = 'PI82HI22KA';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, line+' board');
});

test('parse initial board all', 16, function() {
  var kifu  = kifu_obj.kifu();
  var board = Kifu.Board();

  // 1st line
  board.cellDeploy(9, 1, 'KY', false);
  board.cellDeploy(8, 1, 'KE', false);
  board.cellDeploy(7, 1, 'GI', false);
  board.cellDeploy(6, 1, 'KI', false);
  board.cellDeploy(5, 1, 'OU', false);
  board.cellDeploy(4, 1, 'KI', false);
  board.cellDeploy(3, 1, 'GI', false);
  board.cellDeploy(2, 1, 'KE', false);
  var line = 'P1-KY-KE-GI-KI-OU-KI-GI-KE * ';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, line+' board');

  // 2nd line
  board.cellDeploy(8, 2, 'HI', false);
  var line = 'P2 * -HI *  *  *  *  *  *  * ';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, line+' board');

  // 3rd line
  board.cellDeploy(9, 3, 'FU', false);
  board.cellDeploy(8, 3, 'FU', false);
  board.cellDeploy(7, 3, 'FU', false);
  board.cellDeploy(6, 3, 'FU', false);
  board.cellDeploy(5, 3, 'FU', false);
  board.cellDeploy(4, 3, 'FU', false);
  board.cellDeploy(3, 3, 'FU', false);
  board.cellDeploy(2, 3, 'FU', false);
  board.cellDeploy(1, 3, 'FU', false);
  var line = 'P3-FU-FU-FU-FU-FU-FU-FU-FU-FU';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, line+' board');

  // 4-6 line
  var line = 'P4 *  *  *  *  *  *  *  *  * ';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  var line = 'P5 *  *  *  *  *  *  *  *  * ';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  var line = 'P6 *  *  *  *  *  *  *  *  * ';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, '4-6 line board');

  // 7th line
  board.cellDeploy(9, 7, 'FU', true);
  board.cellDeploy(8, 7, 'FU', true);
  board.cellDeploy(7, 7, 'FU', true);
  board.cellDeploy(6, 7, 'FU', true);
  board.cellDeploy(5, 7, 'FU', true);
  board.cellDeploy(4, 7, 'FU', true);
  board.cellDeploy(3, 7, 'FU', true);
  board.cellDeploy(2, 7, 'FU', true);
  board.cellDeploy(1, 7, 'FU', true);
  var line = 'P7+FU+FU+FU+FU+FU+FU+FU+FU+FU';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, line+' board');

  // 8th line
  board.cellDeploy(8, 8, 'KA', true);
  board.cellDeploy(2, 8, 'HI', true);
  var line = 'P8 * +KA *  *  *  *  * +HI * ';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, line+' board');

  // 9th line
  board.cellDeploy(9, 9, 'KY', true);
  board.cellDeploy(8, 9, 'KE', true);
  board.cellDeploy(7, 9, 'GI', true);
  board.cellDeploy(6, 9, 'KI', true);
  board.cellDeploy(5, 9, 'OU', true);
  board.cellDeploy(4, 9, 'KI', true);
  board.cellDeploy(3, 9, 'GI', true);
  board.cellDeploy(2, 9, 'KE', true);
  board.cellDeploy(1, 9, 'KY', true);
  var line = 'P9+KY+KE+GI+KI+OU+KI+GI+KE+KY';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, line+' board');
});

test('parse initial board each', 8, function() {
  var kifu  = kifu_obj.kifu();
  var board = Kifu.Board();

  // P+63RY00KI
  board.cellDeploy(6, 3, 'RY', true);
  board.standDeploy('KI', true);
  ok(Kifu.Csa.parseByLine('P+63RY00KI', kifu), 'P+63RY00KI');
  same(kifu['board'], board, 'P+63RY00KI board');

  // P+00KI
  board.standDeploy('KI', true);
  ok(Kifu.Csa.parseByLine('P+00KI', kifu), 'P+00KI');
  same(kifu['board'], board, 'P+00KI board');

  // P-42OU33GI22KI23FU
  board.cellDeploy(4, 2, 'OU', false);
  board.cellDeploy(3, 3, 'GI', false);
  board.cellDeploy(2, 2, 'KI', false);
  board.cellDeploy(2, 3, 'FU', false);
  var line = 'P-42OU33GI22KI23FU';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, line+' board');

  // P-00AL
  board.standDeploy('AL', false);
  var line = 'P-00AL';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, line+' board');
});

})();

/* vim: set expandtab tabstop=2 shiftwidth=2 softtabstop=2: */
<commit_msg>added tests for start player<commit_after>(function() {

var kifu_obj;

module('Kifu.Csa', {
  setup: function() {
    kifu_obj = Kifu();
  }
});

test('parse version', 4, function() {
  var kifu = kifu_obj.kifu();
  var info = kifu['info'];

  // version 2
  var line = 'V2';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['version'], '2', line+' info');

  // version 2.2
  var line = 'V2.2';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['version'], '2.2', line+' info');
});

test('parse player', 4, function() {
  var kifu = kifu_obj.kifu();
  var info = kifu['info'];

  // black player
  var line = 'N+大山康晴';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['player_black'], '大山康晴', line+' info');

  // white player
  var line = 'N-升田幸三';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['player_white'], '升田幸三', line+' info');
});

test('parse info', 18, function() {
  var kifu = kifu_obj.kifu();
  var info = kifu['info'];

  // EVENT
  var line = '$EVENT:名人戦';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['event'], '名人戦', line+' info');

  // SITE
  var line = '$SITE:陣屋';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['site'], '陣屋', line+' info');

  // START_TIME
  var start_time = new Date(2011, 3, 7, 9, 45, 10);
  var line = '$START_TIME:2011/04/07 09:45:10';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['start_time'], start_time, line+' info');

  // START_TIME 2
  var start_time = new Date(2010, 9, 25);
  var line = '$START_TIME:2010/10/25';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['start_time'], start_time, line+' info');

  // END_TIME
  var end_time = new Date(2011, 3, 8, 10, 20, 30);
  var line = '$END_TIME:2011/04/08 10:20:30';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['end_time'], end_time, line+' info');

  // END_TIME 2
  var end_time = new Date(2010, 9, 26);
  var line = '$END_TIME:2010/10/26';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['end_time'], end_time, line+' info');

  // TIME_LIMIT
  var line = '$TIME_LIMIT:06:00+60';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['time_limit'], {allotted: 360, extra: 60}, line+' info');

  // TIME_LIMIT 2
  var line = '$TIME_LIMIT:00:00+00';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['time_limit'], {allotted: 0, extra: 0}, line+' info');

  // OPENING
  var line = '$OPENING:相矢倉';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['opening'], '相矢倉', line+' info');
});

test('parse initial board hirate', 4, function() {
  var kifu  = kifu_obj.kifu();
  var board = Kifu.Board().hirate();

  // hirate
  var line = 'PI';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, line+' board');

  // hirate komaochi
  kifu['board'] = Kifu.Board();
  board.cellRemove(8, 2, 'HI');
  board.cellRemove(2, 2, 'KA');
  var line = 'PI82HI22KA';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, line+' board');
});

test('parse initial board all', 16, function() {
  var kifu  = kifu_obj.kifu();
  var board = Kifu.Board();

  // 1st line
  board.cellDeploy(9, 1, 'KY', false);
  board.cellDeploy(8, 1, 'KE', false);
  board.cellDeploy(7, 1, 'GI', false);
  board.cellDeploy(6, 1, 'KI', false);
  board.cellDeploy(5, 1, 'OU', false);
  board.cellDeploy(4, 1, 'KI', false);
  board.cellDeploy(3, 1, 'GI', false);
  board.cellDeploy(2, 1, 'KE', false);
  var line = 'P1-KY-KE-GI-KI-OU-KI-GI-KE * ';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, line+' board');

  // 2nd line
  board.cellDeploy(8, 2, 'HI', false);
  var line = 'P2 * -HI *  *  *  *  *  *  * ';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, line+' board');

  // 3rd line
  board.cellDeploy(9, 3, 'FU', false);
  board.cellDeploy(8, 3, 'FU', false);
  board.cellDeploy(7, 3, 'FU', false);
  board.cellDeploy(6, 3, 'FU', false);
  board.cellDeploy(5, 3, 'FU', false);
  board.cellDeploy(4, 3, 'FU', false);
  board.cellDeploy(3, 3, 'FU', false);
  board.cellDeploy(2, 3, 'FU', false);
  board.cellDeploy(1, 3, 'FU', false);
  var line = 'P3-FU-FU-FU-FU-FU-FU-FU-FU-FU';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, line+' board');

  // 4-6 line
  var line = 'P4 *  *  *  *  *  *  *  *  * ';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  var line = 'P5 *  *  *  *  *  *  *  *  * ';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  var line = 'P6 *  *  *  *  *  *  *  *  * ';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, '4-6 line board');

  // 7th line
  board.cellDeploy(9, 7, 'FU', true);
  board.cellDeploy(8, 7, 'FU', true);
  board.cellDeploy(7, 7, 'FU', true);
  board.cellDeploy(6, 7, 'FU', true);
  board.cellDeploy(5, 7, 'FU', true);
  board.cellDeploy(4, 7, 'FU', true);
  board.cellDeploy(3, 7, 'FU', true);
  board.cellDeploy(2, 7, 'FU', true);
  board.cellDeploy(1, 7, 'FU', true);
  var line = 'P7+FU+FU+FU+FU+FU+FU+FU+FU+FU';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, line+' board');

  // 8th line
  board.cellDeploy(8, 8, 'KA', true);
  board.cellDeploy(2, 8, 'HI', true);
  var line = 'P8 * +KA *  *  *  *  * +HI * ';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, line+' board');

  // 9th line
  board.cellDeploy(9, 9, 'KY', true);
  board.cellDeploy(8, 9, 'KE', true);
  board.cellDeploy(7, 9, 'GI', true);
  board.cellDeploy(6, 9, 'KI', true);
  board.cellDeploy(5, 9, 'OU', true);
  board.cellDeploy(4, 9, 'KI', true);
  board.cellDeploy(3, 9, 'GI', true);
  board.cellDeploy(2, 9, 'KE', true);
  board.cellDeploy(1, 9, 'KY', true);
  var line = 'P9+KY+KE+GI+KI+OU+KI+GI+KE+KY';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, line+' board');
});

test('parse initial board each', 8, function() {
  var kifu  = kifu_obj.kifu();
  var board = Kifu.Board();

  // P+63RY00KI
  board.cellDeploy(6, 3, 'RY', true);
  board.standDeploy('KI', true);
  ok(Kifu.Csa.parseByLine('P+63RY00KI', kifu), 'P+63RY00KI');
  same(kifu['board'], board, 'P+63RY00KI board');

  // P+00KI
  board.standDeploy('KI', true);
  ok(Kifu.Csa.parseByLine('P+00KI', kifu), 'P+00KI');
  same(kifu['board'], board, 'P+00KI board');

  // P-42OU33GI22KI23FU
  board.cellDeploy(4, 2, 'OU', false);
  board.cellDeploy(3, 3, 'GI', false);
  board.cellDeploy(2, 2, 'KI', false);
  board.cellDeploy(2, 3, 'FU', false);
  var line = 'P-42OU33GI22KI23FU';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, line+' board');

  // P-00AL
  board.standDeploy('AL', false);
  var line = 'P-00AL';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(kifu['board'], board, line+' board');
});

test('parse start player', 5, function() {
  var kifu = kifu_obj.kifu();
  var info = kifu['info'];

  // -
  var line = '-';
  same(info['player_start'], 'black', 'first status');
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['player_start'], 'white', line+' info');

  // +
  var line = '+';
  ok(Kifu.Csa.parseByLine(line, kifu), line);
  same(info['player_start'], 'black', line+' info');
});

})();

/* vim: set expandtab tabstop=2 shiftwidth=2 softtabstop=2: */
<|endoftext|>


<commit_before>root = document.getElementById("main_div");
root.innerHTML = `

<input id="searchBox" type="text" onkeyup="updateSearch(event)"
       placeholder="Search for requests and types…" />

        Exact match:

    Methods (0)

    Types (0)

    Constructors (0)

` + root.innerHTML + "
";

// HTML modified, now load documents
contentDiv = document.getElementById("contentDiv");
searchDiv = document.getElementById("searchDiv");
searchBox = document.getElementById("searchBox");

// Search lists
methodsDetails = document.getElementById("methods");
methodsList = document.getElementById("methodsList");
methodsCount = document.getElementById("methodsCount");

typesDetails = document.getElementById("types");
typesList = document.getElementById("typesList");
typesCount = document.getElementById("typesCount");

constructorsDetails = document.getElementById("constructors");
constructorsList = document.getElementById("constructorsList");
constructorsCount = document.getElementById("constructorsCount");

// Exact match
exactMatch = document.getElementById("exactMatch");
exactList = document.getElementById("exactList");

try {
    requests = [{request_names}];
    types = [{type_names}];
    constructors = [{constructor_names}];

    requestsu = [{request_urls}];
    typesu = [{type_urls}];
    constructorsu = [{constructor_urls}];
} catch (e) {
    requests = [];
    types = [];
    constructors = [];
    requestsu = [];
    typesu = [];
    constructorsu = [];
}

if (typeof prependPath !== 'undefined') {
    for (var i = 0; i != requestsu.length; ++i) {
        requestsu[i] = prependPath + requestsu[i];
    }
    for (var i = 0; i != typesu.length; ++i) {
        typesu[i] = prependPath + typesu[i];
    }
    for (var i = 0; i != constructorsu.length; ++i) {
        constructorsu[i] = prependPath + constructorsu[i];
    }
}

// Assumes haystack has no whitespace and both are lowercase.
//
// Returns the penalty for finding the needle in the haystack
// or -1 if the needle wasn't found at all.
function find(haystack, needle) {
    if (needle.length == 0) {
        return true;
    }
    var hi = 0;
    var ni = 0;
    var penalty = 0;
    var started = false;
    while (true) {
        while (needle[ni] < 'a' || needle[ni] > 'z') {
            ++ni;
            if (ni == needle.length) {
                return penalty;
            }
        }
        while (haystack[hi] != needle[ni]) {
            ++hi;
            if (started) {
                ++penalty;
            }
            if (hi == haystack.length) {
                return -1;
            }
        }
        ++hi;
        ++ni;
        started = true;
        if (ni == needle.length) {
            return penalty;
        }
        if (hi == haystack.length) {
            return -1;
        }
    }
}

// Given two input arrays "original" and "original urls" and a query,
// return a pair of arrays with matching "query" elements from "original".
//
// TODO Perhaps return an array of pairs instead a pair of arrays (for cache).
function getSearchArray(original, originalu, query) {
    var destination = [];
    var destinationu = [];

    for (var i = 0; i < original.length; ++i) {
        var penalty = find(original[i].toLowerCase(), query);
        if (penalty > -1 && penalty < original[i].length / 3) {
            destination.push(original[i]);
            destinationu.push(originalu[i]);
        }
    }

    return [destination, destinationu];
}

// Modify "countSpan" and "resultList" accordingly based on the elements
// given as [[elements], [element urls]] (both with the same length)
function buildList(countSpan, resultList, foundElements) {
    var result = "";
    for (var i = 0; i < foundElements[0].length; ++i) {
        result += '
';
        result += '';
        result += foundElements[0][i];
        result += '
';
    }

    if (countSpan) {
        countSpan.innerHTML = "" + foundElements[0].length;
    }
    resultList.innerHTML = result;
}

function updateSearch(event) {
    var query = searchBox.value.toLowerCase();
    if (!query) {
        contentDiv.style.display = "";
        searchDiv.style.display = "none";
        return;
    }

    contentDiv.style.display = "none";
    searchDiv.style.display = "";

    var foundRequests = getSearchArray(requests, requestsu, query);
    var foundTypes = getSearchArray(types, typesu, query);
    var foundConstructors = getSearchArray(constructors, constructorsu, query);

    if (event && event.keyCode == 13) {
        if (methodsDetails.open && foundRequests[1].length) {
            window.location = foundRequests[1][0];
        } else if (typesDetails.open && foundTypes[1].length) {
            window.location = foundTypes[1][0];
        } else if (constructorsDetails.open && foundConstructors[1].length) {
            window.location = foundConstructors[1][0];
        }
        return;
    }

    buildList(methodsCount, methodsList, foundRequests);
    buildList(typesCount, typesList, foundTypes);
    buildList(constructorsCount, constructorsList, foundConstructors);

    // Now look for exact matches
    var original = requests.concat(constructors);
    var originalu = requestsu.concat(constructorsu);
    var destination = [];
    var destinationu = [];

    for (var i = 0; i < original.length; ++i) {
        if (original[i].toLowerCase().replace("request", "") == query) {
            destination.push(original[i]);
            destinationu.push(originalu[i]);
        }
    }

    if (destination.length == 0) {
        exactMatch.style.display = "none";
    } else {
        exactMatch.style.display = "";
        buildList(null, exactList, [destination, destinationu]);
        return destinationu[0];
    }
}

function getQuery(name) {
    var query = window.location.search.substring(1);
    var vars = query.split("&");
    for (var i = 0; i != vars.length; ++i) {
        var pair = vars[i].split("=");
        if (pair[0] == name)
            return decodeURI(pair[1]);
    }
}

var query = getQuery('q');
if (query) {
    searchBox.value = query;
}

var exactUrl = updateSearch();
var redirect = getQuery('redirect');
if (exactUrl && redirect != 'no') {
    window.location = exactUrl;
}
<commit_msg>Support any of /sS to focus docs search<commit_after>root = document.getElementById("main_div");
root.innerHTML = `

<input id="searchBox" type="text" onkeyup="updateSearch(event)"
       placeholder="Search for requests and types…" />

        Exact match:

    Methods (0)

    Types (0)

    Constructors (0)

` + root.innerHTML + "
";

// HTML modified, now load documents
contentDiv = document.getElementById("contentDiv");
searchDiv = document.getElementById("searchDiv");
searchBox = document.getElementById("searchBox");

// Search lists
methodsDetails = document.getElementById("methods");
methodsList = document.getElementById("methodsList");
methodsCount = document.getElementById("methodsCount");

typesDetails = document.getElementById("types");
typesList = document.getElementById("typesList");
typesCount = document.getElementById("typesCount");

constructorsDetails = document.getElementById("constructors");
constructorsList = document.getElementById("constructorsList");
constructorsCount = document.getElementById("constructorsCount");

// Exact match
exactMatch = document.getElementById("exactMatch");
exactList = document.getElementById("exactList");

try {
    requests = [{request_names}];
    types = [{type_names}];
    constructors = [{constructor_names}];

    requestsu = [{request_urls}];
    typesu = [{type_urls}];
    constructorsu = [{constructor_urls}];
} catch (e) {
    requests = [];
    types = [];
    constructors = [];
    requestsu = [];
    typesu = [];
    constructorsu = [];
}

if (typeof prependPath !== 'undefined') {
    for (var i = 0; i != requestsu.length; ++i) {
        requestsu[i] = prependPath + requestsu[i];
    }
    for (var i = 0; i != typesu.length; ++i) {
        typesu[i] = prependPath + typesu[i];
    }
    for (var i = 0; i != constructorsu.length; ++i) {
        constructorsu[i] = prependPath + constructorsu[i];
    }
}

// Assumes haystack has no whitespace and both are lowercase.
//
// Returns the penalty for finding the needle in the haystack
// or -1 if the needle wasn't found at all.
function find(haystack, needle) {
    if (needle.length == 0) {
        return true;
    }
    var hi = 0;
    var ni = 0;
    var penalty = 0;
    var started = false;
    while (true) {
        while (needle[ni] < 'a' || needle[ni] > 'z') {
            ++ni;
            if (ni == needle.length) {
                return penalty;
            }
        }
        while (haystack[hi] != needle[ni]) {
            ++hi;
            if (started) {
                ++penalty;
            }
            if (hi == haystack.length) {
                return -1;
            }
        }
        ++hi;
        ++ni;
        started = true;
        if (ni == needle.length) {
            return penalty;
        }
        if (hi == haystack.length) {
            return -1;
        }
    }
}

// Given two input arrays "original" and "original urls" and a query,
// return a pair of arrays with matching "query" elements from "original".
//
// TODO Perhaps return an array of pairs instead a pair of arrays (for cache).
function getSearchArray(original, originalu, query) {
    var destination = [];
    var destinationu = [];

    for (var i = 0; i < original.length; ++i) {
        var penalty = find(original[i].toLowerCase(), query);
        if (penalty > -1 && penalty < original[i].length / 3) {
            destination.push(original[i]);
            destinationu.push(originalu[i]);
        }
    }

    return [destination, destinationu];
}

// Modify "countSpan" and "resultList" accordingly based on the elements
// given as [[elements], [element urls]] (both with the same length)
function buildList(countSpan, resultList, foundElements) {
    var result = "";
    for (var i = 0; i < foundElements[0].length; ++i) {
        result += '
';
        result += '';
        result += foundElements[0][i];
        result += '
';
    }

    if (countSpan) {
        countSpan.innerHTML = "" + foundElements[0].length;
    }
    resultList.innerHTML = result;
}

function updateSearch(event) {
    var query = searchBox.value.toLowerCase();
    if (!query) {
        contentDiv.style.display = "";
        searchDiv.style.display = "none";
        return;
    }

    contentDiv.style.display = "none";
    searchDiv.style.display = "";

    var foundRequests = getSearchArray(requests, requestsu, query);
    var foundTypes = getSearchArray(types, typesu, query);
    var foundConstructors = getSearchArray(constructors, constructorsu, query);

    if (event && event.keyCode == 13) {
        if (methodsDetails.open && foundRequests[1].length) {
            window.location = foundRequests[1][0];
        } else if (typesDetails.open && foundTypes[1].length) {
            window.location = foundTypes[1][0];
        } else if (constructorsDetails.open && foundConstructors[1].length) {
            window.location = foundConstructors[1][0];
        }
        return;
    }

    buildList(methodsCount, methodsList, foundRequests);
    buildList(typesCount, typesList, foundTypes);
    buildList(constructorsCount, constructorsList, foundConstructors);

    // Now look for exact matches
    var original = requests.concat(constructors);
    var originalu = requestsu.concat(constructorsu);
    var destination = [];
    var destinationu = [];

    for (var i = 0; i < original.length; ++i) {
        if (original[i].toLowerCase().replace("request", "") == query) {
            destination.push(original[i]);
            destinationu.push(originalu[i]);
        }
    }

    if (destination.length == 0) {
        exactMatch.style.display = "none";
    } else {
        exactMatch.style.display = "";
        buildList(null, exactList, [destination, destinationu]);
        return destinationu[0];
    }
}

function getQuery(name) {
    var query = window.location.search.substring(1);
    var vars = query.split("&");
    for (var i = 0; i != vars.length; ++i) {
        var pair = vars[i].split("=");
        if (pair[0] == name)
            return decodeURI(pair[1]);
    }
}

document.onkeydown = function (e) {
    if (e.key == '/' || e.key == 's' || e.key == 'S') {
        if (document.activeElement != searchBox) {
            searchBox.focus();
            return false;
        }
    } else if (e.key == '?') {
        alert('Pressing any of: /sS\nWill focus the search bar\n\n' +
              'Pressing: enter\nWill navigate to the first match')
    }
}

var query = getQuery('q');
if (query) {
    searchBox.value = query;
}

var exactUrl = updateSearch();
var redirect = getQuery('redirect');
if (exactUrl && redirect != 'no') {
    window.location = exactUrl;
}
<|endoftext|>


<commit_before>const ExtractTextPlugin = require("extract-text-webpack-plugin");
const PurifyCSSPlugin = require("purifycss-webpack");
const webpack = require("webpack");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const GitRevisionPlugin = require("git-revision-webpack-plugin");
const BabelWebpackPlugin = require("babel-minify-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const cssnano = require("cssnano");
const HtmlWebpackPlugin = require("html-webpack-plugin");

exports.devServer = ({ host, port } = {}) => ({
  devServer: {
    historyApiFallback: true,
    stats: "errors-only",
    host, // Defaults to `localhost`
    port, // Defaults to 8080
    overlay: {
      errors: true,
      warnings: true,
    },
  },
});

exports.loadCSS = ({ include, exclude } = {}) => ({
  module: {
    rules: [
      {
        test: /\.css$/,
        include,
        exclude,

        use: ["style-loader", "css-loader"],
      },
    ],
  },
});

exports.extractCSS = ({ include, exclude, use }) => {
  // Output extracted CSS to a file
  const plugin = new ExtractTextPlugin({
    filename: "[name].[contenthash:8].css",
  });

  return {
    module: {
      rules: [
        {
          test: /\.css$/,
          include,
          exclude,

          use: plugin.extract({
            use,
            fallback: "style-loader",
          }),
        },
      ],
    },
    plugins: [plugin],
  };
};

exports.autoprefix = () => ({
  loader: "postcss-loader",
  options: {
    plugins: () => [require("autoprefixer")()],
  },
});

exports.purifyCSS = ({ paths }) => ({
  plugins: [new PurifyCSSPlugin({ paths })],
});

exports.loadImages = ({ include, exclude, options } = {}) => ({
  module: {
    rules: [
      {
        test: /\.(png|jpg|svg)$/,
        include,
        exclude,

        use: {
          loader: "url-loader",
          options,
        },
      },
    ],
  },
});

exports.loadFonts = ({ include, exclude, options } = {}) => ({
  module: {
    rules: [
      {
        // Capture eot, ttf, woff, and woff2
        test: /\.(eot|ttf|woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,
        include,
        exclude,

        use: {
          loader: "file-loader",
          options,
        },
      },
    ],
  },
});

exports.loadJavaScript = ({ include, exclude }) => ({
  module: {
    rules: [
      {
        test: /\.js$/,
        include,
        exclude,

        loader: "babel-loader",
        options: {
          // Enable caching for improved performance during
          // development.
          // It uses default OS directory by default. If you need
          // something more custom, pass a path to it.
          // I.e., { cacheDirectory: '<path>' }
          cacheDirectory: true,
        },
      },
    ],
  },
});

exports.generateSourceMaps = ({ type }) => ({
  devtool: type,
});

exports.extractBundles = bundles => ({
  plugins: bundles.map(
    bundle => new webpack.optimize.CommonsChunkPlugin(bundle)
  ),
});

exports.clean = path => ({
  plugins: [new CleanWebpackPlugin([path])],
});

exports.attachRevision = () => ({
  plugins: [
    new webpack.BannerPlugin({
      banner: new GitRevisionPlugin().version(),
    }),
  ],
});

exports.minifyJavaScript = () => ({
  plugins: [new BabelWebpackPlugin()],
});

exports.minifyCSS = ({ options }) => ({
  plugins: [
    new OptimizeCSSAssetsPlugin({
      cssProcessor: cssnano,
      cssProcessorOptions: options,
      canPrint: false,
    }),
  ],
});

exports.setFreeVariable = (key, value) => {
  const env = {};
  env[key] = JSON.stringify(value);

  return {
    plugins: [new webpack.DefinePlugin(env)],
  };
};

exports.page = (
  {
    path = "",
    template = require.resolve("html-webpack-plugin/default_index.ejs"),
    title,
    entry,
    chunks,
  } = {}
) => ({
  entry,
  plugins: [
    new HtmlWebpackPlugin({
      chunks,
      filename: `${path && path + "/"}index.html`,
      template,
      title,
    }),
  ],
});
<commit_msg>chore: Push clean task to the beginning<commit_after>const ExtractTextPlugin = require("extract-text-webpack-plugin");
const PurifyCSSPlugin = require("purifycss-webpack");
const webpack = require("webpack");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const GitRevisionPlugin = require("git-revision-webpack-plugin");
const BabelWebpackPlugin = require("babel-minify-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const cssnano = require("cssnano");
const HtmlWebpackPlugin = require("html-webpack-plugin");

exports.clean = path => ({
  plugins: [new CleanWebpackPlugin([path])],
});

exports.devServer = ({ host, port } = {}) => ({
  devServer: {
    historyApiFallback: true,
    stats: "errors-only",
    host, // Defaults to `localhost`
    port, // Defaults to 8080
    overlay: {
      errors: true,
      warnings: true,
    },
  },
});

exports.loadCSS = ({ include, exclude } = {}) => ({
  module: {
    rules: [
      {
        test: /\.css$/,
        include,
        exclude,

        use: ["style-loader", "css-loader"],
      },
    ],
  },
});

exports.extractCSS = ({ include, exclude, use }) => {
  // Output extracted CSS to a file
  const plugin = new ExtractTextPlugin({
    filename: "[name].[contenthash:8].css",
  });

  return {
    module: {
      rules: [
        {
          test: /\.css$/,
          include,
          exclude,

          use: plugin.extract({
            use,
            fallback: "style-loader",
          }),
        },
      ],
    },
    plugins: [plugin],
  };
};

exports.autoprefix = () => ({
  loader: "postcss-loader",
  options: {
    plugins: () => [require("autoprefixer")()],
  },
});

exports.purifyCSS = ({ paths }) => ({
  plugins: [new PurifyCSSPlugin({ paths })],
});

exports.loadImages = ({ include, exclude, options } = {}) => ({
  module: {
    rules: [
      {
        test: /\.(png|jpg|svg)$/,
        include,
        exclude,

        use: {
          loader: "url-loader",
          options,
        },
      },
    ],
  },
});

exports.loadFonts = ({ include, exclude, options } = {}) => ({
  module: {
    rules: [
      {
        // Capture eot, ttf, woff, and woff2
        test: /\.(eot|ttf|woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,
        include,
        exclude,

        use: {
          loader: "file-loader",
          options,
        },
      },
    ],
  },
});

exports.loadJavaScript = ({ include, exclude }) => ({
  module: {
    rules: [
      {
        test: /\.js$/,
        include,
        exclude,

        loader: "babel-loader",
        options: {
          // Enable caching for improved performance during
          // development.
          // It uses default OS directory by default. If you need
          // something more custom, pass a path to it.
          // I.e., { cacheDirectory: '<path>' }
          cacheDirectory: true,
        },
      },
    ],
  },
});

exports.generateSourceMaps = ({ type }) => ({
  devtool: type,
});

exports.extractBundles = bundles => ({
  plugins: bundles.map(
    bundle => new webpack.optimize.CommonsChunkPlugin(bundle)
  ),
});

exports.attachRevision = () => ({
  plugins: [
    new webpack.BannerPlugin({
      banner: new GitRevisionPlugin().version(),
    }),
  ],
});

exports.minifyJavaScript = () => ({
  plugins: [new BabelWebpackPlugin()],
});

exports.minifyCSS = ({ options }) => ({
  plugins: [
    new OptimizeCSSAssetsPlugin({
      cssProcessor: cssnano,
      cssProcessorOptions: options,
      canPrint: false,
    }),
  ],
});

exports.setFreeVariable = (key, value) => {
  const env = {};
  env[key] = JSON.stringify(value);

  return {
    plugins: [new webpack.DefinePlugin(env)],
  };
};

exports.page = (
  {
    path = "",
    template = require.resolve("html-webpack-plugin/default_index.ejs"),
    title,
    entry,
    chunks,
  } = {}
) => ({
  entry,
  plugins: [
    new HtmlWebpackPlugin({
      chunks,
      filename: `${path && path + "/"}index.html`,
      template,
      title,
    }),
  ],
});
<|endoftext|>


<commit_before>'use strict';

var { solReader } = require('../../io');
var React = require('react');
var Display = require('../Display');
var getBoundingBox = require('../getBoundingBox');
var FPSStats = require('react-stats').FPSStats;
require('buffer');

var { Track, OldTrack } = require('../../core');

var DEBUG = false;

var defaultLines = [
  {
    x1: 15,
    y1: 180,
    x2: 190,
    y2: 190,
    extended: 0,
    flipped: false,
    leftLine: null,
    rightLine: null,
    id: 0,
    type: 0
  }
];
var App = React.createClass({

  getInitialState() {
    return {
      tracks: [],
      track: new Track(defaultLines, {x: 0, y: 0}, DEBUG),
      selected: '',
      playing: false,
      frame: 0,
      maxFrame: 0,
      grid: false,
      slowmo: false,
      floor: false,
      accArrow: false,
      snapDot: false,
      color: false,
      boundingBox: [0, 0, 200, 200],
      initPanx: 100,
      initPany: 100,
      initZoom: 2,
      panx: 0,
      pany: 0,
      zoom: 1,
      skipFrames: false,
      framesSkipped: 0,
      width: window.innerWidth || 1 // sometimes it's zero????
    };
  },

  componentDidMount() {
    this.time = null;
    window.addEventListener('resize', this.onResize);
    this.onResize(true);
  },

  onResize(force) {
    if (window.innerWidth === 0) {
      console.log('innerWidth is zero, getting it again')
      setTimeout(() => this.onResize(force), 0);
      return;
    }
    if (this.state.width !== window.innerWidth || force) {
      this.setState({
        width: window.innerWidth || 1
      });
      this.setInitCamera();
    }
  },

  onSelectTrack(e) {
    let trackData = this.state.tracks[e.target.value];
    let startPos = { x: trackData.startPosition[0], y: trackData.startPosition[1] };
    let version = trackData.version;
    let VersionedTrack = Track;
    if (version === '6.1') {
      VersionedTrack = OldTrack;
    }
    let track = new VersionedTrack(trackData.lines, startPos, DEBUG);
    track.label = trackData.label;
    let box = getBoundingBox(track.lines.concat([{
      x1: startPos.x - 10,
      y1: startPos.y - 10,
      x2: startPos.x + 10,
      y2: startPos.y + 10
    }]));
    this.setState({
      track: track,
      selected: e.target.value,
      boundingBox: box,
      panx: 0,
      pany: 0,
      zoom: 1
    });
    this.stopPlayback();
    this.setState({ maxFrame: 0 });
    this.setInitCamera(box);
  },

  setInitCamera(box = this.state.boundingBox) {
    let [x1, y1, x2, y2] = box;
    [x1, y1, x2, y2] = [x1 - 10, y1 - 10, x2 + 10, y2 + 10];
    let [w, h] = [x2 - x1, y2 - y1];
    let [cx, cy] = [x1 + w / 2, y1 + h / 2];
    this.setState({
      initPanx: cx,
      initPany: cy,
      initZoom: w / this.state.width
    });
  },

  onTogglePlayback() {
    if (!this.state.playing) {
      this.setState({ playing: true, framesSkipped: 0, fps: this.getFPS() });
      this.prevTime = Date.now();
      this.prevPan = this.getRider().points[0].pos.clone();
      var step = () => {
        let dt = Date.now() - this.prevTime;
        let fps = this.getFPS();
        let framesElapsed = Math.floor(dt / 1000 * fps);

        if (framesElapsed > 0) {
          this.prevTime += framesElapsed / fps * 1000;
          let nextFrame = this.state.frame + (this.state.skipFrames ? framesElapsed : 1);
          this.setState({
            frame: nextFrame,
            maxFrame: Math.max(this.state.maxFrame, nextFrame),
            framesSkipped: this.state.framesSkipped + framesElapsed - 1
          });
        }
        this.timer = requestAnimationFrame(step);
      };

      step();

    } else {
      this.stopPlayback();
    }
  },

  stopPlayback() {
    cancelAnimationFrame(this.timer);
    this.setState({ playing: false, frame: 0 });
  },

  onPause() {
    cancelAnimationFrame(this.timer);
    this.setState({ playing: false });
  },

  onToggle(key) {
    return () => {
      let nextState = {};
      nextState[key] = !this.state[key];
      this.setState(nextState);
    };
  },

  onFileInput(e) {
    var reader = new FileReader();
    var file = e.target.files[0];
    if (!file) {
      return;
    }

    reader.onload = (upload) => {
      try {
        this.setState({
          tracks: solReader(new Buffer(new Uint8Array(upload.target.result))),
          track: null,
          selected: ''
        });
        this.stopPlayback();
      } catch (e) {
        alert(`There is something wrong with this .sol!\n${e}`);
      }
    };

    reader.readAsArrayBuffer(file);
  },

  getRider() {
    return this.state.track.getRiderAtFrame(this.state.frame);
  },

  getFPS() {
    let fps = 40;
    // let fps = 60;
    return this.state.slowmo ? fps / 8 : fps;
  },

  getPan() {
    if (this.state.playing) {
      let rider = this.getRider();
      let p = rider.points[0];
      let min = 0.1;
      let k = (1 - Math.exp(-0.000004 * this.prevPan.distanceSq(p) / Math.pow(this.state.zoom, 2)) + min) / (1 + min);
      // console.log(k)
      this.prevPan.lerp(p, k);
      return {x: this.prevPan.x, y: this.prevPan.y };
    }
    return {
      x: this.state.initPanx + this.state.panx,
      y: this.state.initPany + this.state.pany
    };
  },

  getZoom() {
    if (this.state.playing) {
      return this.state.zoom;
    }
    return this.state.initZoom * this.state.zoom;
  },

  getHeight() {
    let [x1, y1, x2, y2] = this.state.boundingBox;
    let [w, h] = [x2 - x1, y2 - y1];
    return Math.round(h / w * this.state.width);
  },

  getViewBox() {
    let {x, y} = this.getPan();
    let z = this.getZoom();
    let w = this.state.width;
    let h = this.getHeight();
    return [
      x - w / 2 * z,
      y - h / 2 * z,
      w * z,
      h * z
    ];
  },

  getLines() {
    let [x1, y1, w, h] = this.getViewBox();
    // console.log(x1, y1, x1 + w, y1 + h);
    return this.state.track.getLinesInBox(x1, y1, x1 + w, y1 + h);
  },

  renderToggle(key) {
    if (this.state[key] === undefined) {
      throw new Error('Key does not exist in state, cannot toggle: ', key);
    }
    return (

        {key}: <input type="checkbox" checked={this.state[key]} onChange={this.onToggle(key)} />

    );
  },

  render() {
    let [x1, y1, x2, y2] = this.state.boundingBox;
    let [w, h] = [x2 - x1, y2 - y1];
    return (

Input a .sol file to view your tracks.

<input type="file" onChange={this.onFileInput} />

          {
            this.state.tracks.length > 0 ?
              <select value={this.state.selected} onChange={this.onSelectTrack}>
                <option key="-1" value="" disabled>Select a track to render...</option>
                {
                  this.state.tracks.map((track, i) =>
                    <option key={i} value={i}>{track.label}</option>
                  )
                }
              </select>
              : null
          }

        {
          this.state.selected ?

            Track name: { this.state.tracks[this.state.selected].label }

            Version: { this.state.tracks[this.state.selected].version }

            Line count: { this.state.track.lines.length }

          : null
        }
        { ['grid', 'color'].map(this.renderToggle) }
        {
          this.state.color ?
            ['floor', 'accArrow', 'snapDot'].map(this.renderToggle)
          : null
        }
        {
          this.state.track ?

              <FPSStats isActive={true}/>

{this.state.frame} {this.state.framesSkipped}

                pan x: <input type='range' min={-w} max={w} value={this.state.panx} onChange={e => this.setState({panx: Number(e.target.value)})}/>

                pan y: <input type='range' min={-h} max={h} value={this.state.pany} onChange={e => this.setState({pany: Number(e.target.value)})}/>

                zoom: <input type='range' min={-3} max={1} value={Math.log2(this.state.zoom)} onChange={e => this.setState({zoom: Math.pow(2, Number(e.target.value))})} step={1 / 144}/>

                frame: <input type='range' min={0} max={this.state.maxFrame} value={this.state.frame} onChange={e => this.setState({frame: parseInt(e.target.value)})}/>

              { this.renderToggle('skipFrames') }
              { this.renderToggle('slowmo') }
              <button onClick={() => {console.log(this.state.track.lines)}}>Print lines</button>
              <button onClick={this.onTogglePlayback}>{ this.state.playing ? 'Stop' : 'Play'}</button>
              <button onClick={this.onPause}>Pause</button>
              <button onClick={() => this.setState({ frame: this.state.frame + 1 })}>Step forward</button>
              <button onClick={() => this.setState({ frame: Math.max(0, this.state.frame - 1) })}>Step backward</button>

            : null
        }
        {
          this.state.track ?
            <Display
              {...this.state}
              label={this.state.tracks[this.state.selected] ? (this.state.tracks[this.state.selected].label + this.state.selected) : null}
              rider={this.getRider()}
              pan={this.getPan()}
              zoom={this.getZoom()}
              lines={this.getLines()}
              width={this.state.width}
              height={this.getHeight()} />
            : null
        }

    );
  }

});

module.exports = App;
<commit_msg>keep FPSStats always active<commit_after>'use strict';

var { solReader } = require('../../io');
var React = require('react');
var Display = require('../Display');
var getBoundingBox = require('../getBoundingBox');
var FPSStats = require('react-stats').FPSStats;
require('buffer');

var { Track, OldTrack } = require('../../core');

var DEBUG = false;

var defaultLines = [
  {
    x1: 15,
    y1: 180,
    x2: 190,
    y2: 190,
    extended: 0,
    flipped: false,
    leftLine: null,
    rightLine: null,
    id: 0,
    type: 0
  }
];
var App = React.createClass({

  getInitialState() {
    return {
      tracks: [],
      track: new Track(defaultLines, {x: 0, y: 0}, DEBUG),
      selected: '',
      playing: false,
      frame: 0,
      maxFrame: 0,
      grid: false,
      slowmo: false,
      floor: false,
      accArrow: false,
      snapDot: false,
      color: false,
      boundingBox: [0, 0, 200, 200],
      initPanx: 100,
      initPany: 100,
      initZoom: 2,
      panx: 0,
      pany: 0,
      zoom: 1,
      skipFrames: false,
      framesSkipped: 0,
      width: window.innerWidth || 1 // sometimes it's zero????
    };
  },

  componentDidMount() {
    this.time = null;
    window.addEventListener('resize', this.onResize);
    this.onResize(true);
  },

  onResize(force) {
    if (window.innerWidth === 0) {
      console.log('innerWidth is zero, getting it again')
      setTimeout(() => this.onResize(force), 0);
      return;
    }
    if (this.state.width !== window.innerWidth || force) {
      this.setState({
        width: window.innerWidth || 1
      });
      this.setInitCamera();
    }
  },

  onSelectTrack(e) {
    let trackData = this.state.tracks[e.target.value];
    let startPos = { x: trackData.startPosition[0], y: trackData.startPosition[1] };
    let version = trackData.version;
    let VersionedTrack = Track;
    if (version === '6.1') {
      VersionedTrack = OldTrack;
    }
    let track = new VersionedTrack(trackData.lines, startPos, DEBUG);
    track.label = trackData.label;
    let box = getBoundingBox(track.lines.concat([{
      x1: startPos.x - 10,
      y1: startPos.y - 10,
      x2: startPos.x + 10,
      y2: startPos.y + 10
    }]));
    this.setState({
      track: track,
      selected: e.target.value,
      boundingBox: box,
      panx: 0,
      pany: 0,
      zoom: 1
    });
    this.stopPlayback();
    this.setState({ maxFrame: 0 });
    this.setInitCamera(box);
  },

  setInitCamera(box = this.state.boundingBox) {
    let [x1, y1, x2, y2] = box;
    [x1, y1, x2, y2] = [x1 - 10, y1 - 10, x2 + 10, y2 + 10];
    let [w, h] = [x2 - x1, y2 - y1];
    let [cx, cy] = [x1 + w / 2, y1 + h / 2];
    this.setState({
      initPanx: cx,
      initPany: cy,
      initZoom: w / this.state.width
    });
  },

  onTogglePlayback() {
    if (!this.state.playing) {
      this.setState({ playing: true, framesSkipped: 0, fps: this.getFPS() });
      this.prevTime = Date.now();
      this.prevPan = this.getRider().points[0].pos.clone();
      var step = () => {
        let dt = Date.now() - this.prevTime;
        let fps = this.getFPS();
        let framesElapsed = Math.floor(dt / 1000 * fps);

        if (framesElapsed > 0) {
          this.prevTime += framesElapsed / fps * 1000;
          let nextFrame = this.state.frame + (this.state.skipFrames ? framesElapsed : 1);
          this.setState({
            frame: nextFrame,
            maxFrame: Math.max(this.state.maxFrame, nextFrame),
            framesSkipped: this.state.framesSkipped + framesElapsed - 1
          });
        }
        this.timer = requestAnimationFrame(step);
      };

      step();

    } else {
      this.stopPlayback();
    }
  },

  stopPlayback() {
    cancelAnimationFrame(this.timer);
    this.setState({ playing: false, frame: 0 });
  },

  onPause() {
    cancelAnimationFrame(this.timer);
    this.setState({ playing: false });
  },

  onToggle(key) {
    return () => {
      let nextState = {};
      nextState[key] = !this.state[key];
      this.setState(nextState);
    };
  },

  onFileInput(e) {
    var reader = new FileReader();
    var file = e.target.files[0];
    if (!file) {
      return;
    }

    reader.onload = (upload) => {
      try {
        this.setState({
          tracks: solReader(new Buffer(new Uint8Array(upload.target.result))),
          track: null,
          selected: ''
        });
        this.stopPlayback();
      } catch (e) {
        alert(`There is something wrong with this .sol!\n${e}`);
      }
    };

    reader.readAsArrayBuffer(file);
  },

  getRider() {
    return this.state.track.getRiderAtFrame(this.state.frame);
  },

  getFPS() {
    let fps = 40;
    // let fps = 60;
    return this.state.slowmo ? fps / 8 : fps;
  },

  getPan() {
    if (this.state.playing) {
      let rider = this.getRider();
      let p = rider.points[0];
      let min = 0.1;
      let k = (1 - Math.exp(-0.000004 * this.prevPan.distanceSq(p) / Math.pow(this.state.zoom, 2)) + min) / (1 + min);
      // console.log(k)
      this.prevPan.lerp(p, k);
      return {x: this.prevPan.x, y: this.prevPan.y };
    }
    return {
      x: this.state.initPanx + this.state.panx,
      y: this.state.initPany + this.state.pany
    };
  },

  getZoom() {
    if (this.state.playing) {
      return this.state.zoom;
    }
    return this.state.initZoom * this.state.zoom;
  },

  getHeight() {
    let [x1, y1, x2, y2] = this.state.boundingBox;
    let [w, h] = [x2 - x1, y2 - y1];
    return Math.round(h / w * this.state.width);
  },

  getViewBox() {
    let {x, y} = this.getPan();
    let z = this.getZoom();
    let w = this.state.width;
    let h = this.getHeight();
    return [
      x - w / 2 * z,
      y - h / 2 * z,
      w * z,
      h * z
    ];
  },

  getLines() {
    let [x1, y1, w, h] = this.getViewBox();
    // console.log(x1, y1, x1 + w, y1 + h);
    return this.state.track.getLinesInBox(x1, y1, x1 + w, y1 + h);
  },

  renderToggle(key) {
    if (this.state[key] === undefined) {
      throw new Error('Key does not exist in state, cannot toggle: ', key);
    }
    return (

        {key}: <input type="checkbox" checked={this.state[key]} onChange={this.onToggle(key)} />

    );
  },

  render() {
    let [x1, y1, x2, y2] = this.state.boundingBox;
    let [w, h] = [x2 - x1, y2 - y1];
    return (

        <FPSStats isActive={true}/>

Input a .sol file to view your tracks.

<input type="file" onChange={this.onFileInput} />

          {
            this.state.tracks.length > 0 ?
              <select value={this.state.selected} onChange={this.onSelectTrack}>
                <option key="-1" value="" disabled>Select a track to render...</option>
                {
                  this.state.tracks.map((track, i) =>
                    <option key={i} value={i}>{track.label}</option>
                  )
                }
              </select>
              : null
          }

        {
          this.state.selected ?

            Track name: { this.state.tracks[this.state.selected].label }

            Version: { this.state.tracks[this.state.selected].version }

            Line count: { this.state.track.lines.length }

          : null
        }
        { ['grid', 'color'].map(this.renderToggle) }
        {
          this.state.color ?
            ['floor', 'accArrow', 'snapDot'].map(this.renderToggle)
          : null
        }
        {
          this.state.track ?

{this.state.frame} {this.state.framesSkipped}

                pan x: <input type='range' min={-w} max={w} value={this.state.panx} onChange={e => this.setState({panx: Number(e.target.value)})}/>

                pan y: <input type='range' min={-h} max={h} value={this.state.pany} onChange={e => this.setState({pany: Number(e.target.value)})}/>

                zoom: <input type='range' min={-3} max={1} value={Math.log2(this.state.zoom)} onChange={e => this.setState({zoom: Math.pow(2, Number(e.target.value))})} step={1 / 144}/>

                frame: <input type='range' min={0} max={this.state.maxFrame} value={this.state.frame} onChange={e => this.setState({frame: parseInt(e.target.value)})}/>

              { this.renderToggle('skipFrames') }
              { this.renderToggle('slowmo') }
              <button onClick={() => {console.log(this.state.track.lines)}}>Print lines</button>
              <button onClick={this.onTogglePlayback}>{ this.state.playing ? 'Stop' : 'Play'}</button>
              <button onClick={this.onPause}>Pause</button>
              <button onClick={() => this.setState({ frame: this.state.frame + 1 })}>Step forward</button>
              <button onClick={() => this.setState({ frame: Math.max(0, this.state.frame - 1) })}>Step backward</button>

            : null
        }
        {
          this.state.track ?
            <Display
              {...this.state}
              label={this.state.tracks[this.state.selected] ? (this.state.tracks[this.state.selected].label + this.state.selected) : null}
              rider={this.getRider()}
              pan={this.getPan()}
              zoom={this.getZoom()}
              lines={this.getLines()}
              width={this.state.width}
              height={this.getHeight()} />
            : null
        }

    );
  }

});

module.exports = App;
<|endoftext|>


<commit_before>var EventEmitter = require("events").EventEmitter
var ArrowKeys = require("arrow-keys")

module.exports = Player

function Player(paper, relative) {
    var entity = paper.rect(relative.x, relative.y, 10, 10)
    var keys = ArrowKeys()

    entity.attr("fill", "red")

    return keys
}
<commit_msg>animated sprite wizard<commit_after>var EventEmitter = require("events").EventEmitter
var ArrowKeys = require("arrow-keys")

module.exports = Player

function Player(paper, relative) {
    var x = relative.x, y = relative.y
    var w = 86, h = 133
    var sprites = {
        front : [
            paper.image('/wizard_front_0.svg', x, y, w, h).hide(),
            paper.image('/wizard_front_1.svg', x, y, w, h).hide(),
        ],
        back : [
            paper.image('/wizard_back_0.svg', x, y, w, h).hide(),
            paper.image('/wizard_back_1.svg', x, y, w, h).hide(),
        ],
        left : [
            paper.image('/wizard_left_0.svg', x, y, w, h).hide(),
            paper.image('/wizard_left_1.svg', x, y, w, h).hide(),
        ],
        right : [
            paper.image('/wizard_right_0.svg', x, y, w, h).hide(),
            paper.image('/wizard_right_1.svg', x, y, w, h).hide(),
        ],
    }
    var keys = ArrowKeys()
    var direction = 'front'
    var last = Date.now()

    keys.on('change', function (key, value) {
        var d = {
            'x+1' : 'right',
            'x-1' : 'left',
            'y-1' : 'back',
            'y+1' : 'front',
        }[key + (value < 0 ? '' : '+') + value]
        last = Date.now()
        if (direction !== d) animate()
        direction = d
    })

    var animate = (function () {
        var prev = null;
        var ix = 0
        return function () {
            if (Date.now() - last < 100) {
                if (prev) prev.hide()
                prev = sprites[direction][++ix % 2].show()
            }
        }
    })()
    animate()
    setInterval(animate, 100)

    return keys
}
<|endoftext|>


<commit_before>'use strict';

var _         = require('lodash-node'),
    datetime  = require('../utils/datetime');

exports.disruption = function(disruptions) {

  return _.map(disruptions, function(disruption) {

    return {
      'id'          : parseInt(disruption.Id),
      //'priority'    : disruption.Priority, // Not used in the app
      'date'        : datetime.toCET(disruption.DateTime).toISOString(),
      'title'       : disruption.Title.trim(),
      'cause'       : disruption.Cause.trim(),
      'consequence' : disruption.Consequence.trim(),
      'solution'    : disruption.Solution.trim() || null,
      'status'      : disruption.Status
    };

  });

};<commit_msg>Changed status to updated<commit_after>'use strict';

var _         = require('lodash-node'),
    datetime  = require('../utils/datetime');

exports.disruption = function(disruptions) {

  return _.map(disruptions, function(disruption) {

    return {
      'id'          : parseInt(disruption.Id),
      //'priority'    : disruption.Priority, // Not used in the app
      'date'        : datetime.toCET(disruption.DateTime).toISOString(),
      'title'       : disruption.Title.trim(),
      'cause'       : disruption.Cause.trim(),
      'consequence' : disruption.Consequence.trim(),
      'solution'    : disruption.Solution.trim() || null,
      'updated'     : disruption.Status === 1
    };

  });

};<|endoftext|>


<commit_before>/**
 * Created by оо on 21.11.13.
 */

(function(){

    console.log("asd".match(/./)); //true
    console.log("".match(/./)); // null
    console.log("asd".match(/.+/)); // array
    console.log("".match(/.+/));// null
    console.log("asd".match(/.*/));//array
    console.log("".match(/.*/));

    console.log("asd".match(/.?/));
    console.log("".match(/.?/));

})()<commit_msg>правило выолняемое в начале строки ^ циркумфлекс<commit_after>/**
 * Created by оо on 21.11.13.
 */

(function(){
    console.log("\nnew\n12".match(/^./g)); // null
    console.log("\nnew\n12".match(/^./m)); // "1" because m = multiline

})()<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
// maker
//////////////////////////////////////////////////////////////////////////
//
// Main module
//
/* ----------------------------------------------------------------------
                                                    Object Structures
-------------------------------------------------------------------------

*/
//////////////////////////////////////////////////////////////////////////
// Node.js Exports
exports.createMaker = function( separationString ) { return new Maker(separationString); }

//////////////////////////////////////////////////////////////////////////
// Namespace (lol)
var DEBUG = true;

var log = function( text, isImportant ) {
	if(DEBUG && isImportant) {
		console.log("\n******************************************")
		console.log("* " + text)
		console.log("******************************************\n")
	} else if(DEBUG) {
		console.log(text);
	}
};

var pathModule = require("path"),
	basename = require("path").basename,
	traverse = require("traverse"),
	wrench = require("wrench"),
	clone = require("clone"),
	async = require("async"),
	fs = require("fs");

var templateFileExtension = ".tpl";

//////////////////////////////////////////////////////////////////////////
// Constructor
function Maker( separationString ) {
	this.separationString = separationString || "~~";
	this.templates = {};
} // end Maker()

//////////////////////////////////////////////////////////////////////////
// Returns a template object loaded from a file
Maker.prototype.template = function( templateString, contents ) {
	var templateObj = parseTemplate( templateString, this.separationString );

	for( var property in contents ) {
		if( contents.hasOwnProperty(property) ) {

			templateObj[property] = contents[property] || undefined;
		}
	}

	return templateObj;
} // end template()

//////////////////////////////////////////////////////////////////////////
// Retrurns a template object created by processing a file on disk
Maker.prototype.makeTemplate = function( filePath, templateParams ) {
	try {
		var file = fs.readFileSync( filePath, "utf8" );
	} catch( err ) {
		console.log( err );
		return {};
	}

	// Replace all instances of given strings with the given template
	// parameter string within the file
	for( var iParam in templateParams ) {
		if( templateParams.hasOwnProperty(iParam) ) {
			var templateParamString = this.separationString + templateParams[iParam] + this.separationString;
			file = file.replace( new RegExp(iParam, "g"), templateParamString );
		}
	}

	var template = parseTemplate( file, this.separationString );

	this.templates[filePath] = template

	return clone( template );
} // end makeTemplate()

//////////////////////////////////////////////////////////////////////////
// Returns a template
Maker.prototype.getTemplate = function( templateName ) {
	return clone( this.templates[templateName] );
} // end getTemplate()

//////////////////////////////////////////////////////////////////////////
// Returns a template filled with the contents given
Maker.prototype.fillTemplate = function( template, contents ) {
	var templateObj = {};

	if( typeof(template) === "string" )
		templateObj = clone( this.templates[template] );
	else
		templateObj = template;

	for( var property in contents ) {
		if( contents.hasOwnProperty(property) ) {

			templateObj[property] = contents[property] || undefined;
		}
	}

	return templateObj;
} // end fillTemplate()

//////////////////////////////////////////////////////////////////////////
// Creates a file on disk composed of the given templates
Maker.prototype.makeFile = function( path, templates, callback ) {
	log( "Making file " + path );

	// If this is a folder, just return
	if( pathModule.extname(path) == "" )
		return;

	// Convert any templates that are still objects into strings
	for( var iTemplate=0; iTemplate<templates.length; ++iTemplate ) {
		if( typeof(templates[iTemplate]) === "object" ) {
			templates[iTemplate] = this.renderTemplateToString( templates[iTemplate] );
		}
	}

	var fileContents = "";

	// Concatenate all template strings into one big string
	for( var iTemplate=0; iTemplate<templates.length; ++iTemplate ) {
		fileContents += templates[iTemplate];
	}

	var folderPath = pathModule.dirname( path );

	// Create the directory if it didn't exist already
	wrench.mkdirSyncRecursive( folderPath );

	// Write the file to disk
	fs.writeFile( path, fileContents, function(err) {
	    if(err) {
	        console.log(err);
	    }

	    if( callback != undefined )
	    	callback( err );
	});
} // end makeFile()

//////////////////////////////////////////////////////////////////////////
// Renders a template recursively back into a string
Maker.prototype.renderTemplateToString = function( template ) {
	if( typeof(template) === "string" )
		template = this.templates[template];

	// Start with the original template string
	var renderedTemplate = template.__fullTemplateString__,
		matches = template.__templateMatches__;

	for( var iItem in template ) {
		if( iItem == "__fullTemplateString__" || iItem == "__templateMatches__" )
			continue;

		//console.log("item " + iItem + " is of type " + typeof iItem + " with value " + template[iItem] );

		if( typeof template[iItem] == "undefined" || template[iItem] == "undefined" ) {
			template[iItem] = "";
			console.log( "Item '" + iItem + "' is undefined" );
		} else if( typeof template[iItem] === "object" ) {
			// Render this template recursively
			template[iItem] = this.renderTemplateToString( template[iItem] );
		} else if( typeof template[iItem] != "string" ) {
			console.log( "Item '" + iItem + "' is not a string" );
		}

		var stringToReplace = this.separationString + iItem + this.separationString;

		try {
			renderedTemplate = renderedTemplate.replace( new RegExp(stringToReplace, "g"), template[iItem] );
		} catch( err ) {
			console.log( "renderTemplate: " + err );
		}
	}

	return renderedTemplate;
} // end renderTemplate()

//////////////////////////////////////////////////////////////////////////
// Loads all templates inside of a given directory
Maker.prototype.loadTemplateDir = function( templateDir, callback ) {
	var _this = this;
	var templates = {};

	// Walk the folder tree recursively
	wrench.readdirRecursive( templateDir, function(error, files) {
		if( files == null ) {
			log( "Templates loaded from directory " + templateDir );
			_this.templates = templates;
			return callback( templates );
		}

		for( var iFile=0; iFile<files.length; ++iFile ) {
			if( files[iFile].indexOf(".tpl") == -1 )
				continue;

			var path = templateDir + "/" + files[iFile],
				file = fs.readFileSync( path, "utf8" );

			var templateName = basename( path );

			// Trim off the extension
			templateName = templateName.substring( 0, templateName.length - templateFileExtension.length );

			templates[templateName] = _this.template( file );
		}
	});
} // end loadTemplateDir()

//////////////////////////////////////////////////////////////////////////
// Create templates from all files within a directory, and maps their
// filled out versions to a new location
Maker.prototype.makeTemplatesFromDir = function( source, dest, replacementMap, pathReplacementMap, extensions, contents, callback ) {
	log( "Making directory " + source + " into templates and outputting to " + dest, true );

	// Make the pathReplacementMap, extensions, and contents arguments optional
	if( arguments.length == 4 ) {
		callback = extensions;
		pathReplacementMap = {};
		extensions = [];
		contents = {};
	} else if( arguments.length == 5 ) {
		callback = contents;
		contents = {};
		extensions = [];
	} else if( arguments.length == 6 ) {
		callback = contents;
		contents = {};
	}

	if( extensions.length > 0 ) {
		log( "Only templating files with extensions: " + extensions );
	} else {
		log( "Not filtering for extensions" );
		log( arguments );
	}

	var _this = this,
		templates = {},
		numTemplates = 0,
		finishedReading = false,
		finishedTemplating = false;

	// Walk the folder tree recursively
	wrench.readdirRecursive( source, function(error, files) {
		if( files != undefined )
			numTemplates += files.length;

		if( files == null ) {
			log( numTemplates + " files inspected within directory " + source );
			_this.templates = templates;

			finishedReading = true;

			// We have a race condition between reading and templating,
			// so we want to make sure both are finished before calling callback()
			if( finishedTemplating && finishedReading ) {
				callback();
			}
		}

		function iteratorFn( file, finishedCB ) {
			// Make sure this file has a file extension we care about
			//
			// NOTE: extension filtering is optional, so if extensions is an
			// empty array, any file extension will be let through
			var hasValidExtension = extensions.length > 0 ? false : true;
			for( var iExtension = 0; iExtension < extensions.length; ++iExtension ) {
				if( pathModule.extname(file) == extensions[iExtension] )
					hasValidExtension = true;
			}

			// Give up on this round if this file has an invalid extension
			if( !hasValidExtension )
				return finishedCB();

			var path = source + "/" + file;

			var templateObj = _this.makeTemplate( path, replacementMap );

			// Copy over the parameters we're trying to fill in
			for( var property in contents ) {
				if( contents.hasOwnProperty(property) ) {
					templateObj[property] = contents[property] || undefined;
				}
			}

			// Use the path replacement map to modify output locations
			var outputPath = dest + file;
			for( var iItem in pathReplacementMap ) {
				if( pathReplacementMap.hasOwnProperty(iItem) ) {
					outputPath = outputPath.replace( new RegExp(iItem, "g"), pathReplacementMap[iItem] );
				}
			}

			_this.makeFile( outputPath, [templateObj], finishedCB );
		}

		function asyncCallback( error, results ) {
			finishedTemplating = true;

			// We have a race condition between reading and templating,
			// so we want to make sure both are finished before calling callback()
			if( finishedTemplating && finishedReading ) {
				callback();
			}
		}

		if( files != null )
			async.eachSeries( files, iteratorFn, asyncCallback );
	});
} // end makeTemplatesFromDir()

//////////////////////////////////////////////////////////////////////////
// Parses a template string and returns an object of its contents
function parseTemplate( templateString, separationString ) {
	var iPosition = 0,
		matches = [],
		templateObj = {};

	iPosition = templateString.indexOf( separationString, iPosition );

	while( iPosition > 0 ) {
		matches.push( iPosition );

		var newPosition = templateString.indexOf( separationString, iPosition+separationString.length );

		iPosition = newPosition;
	}

	if( matches.length % 2 != 0 ) {
		log( "Error while parsing template: Mismatched separation string" );
	}

	for( var iItem = 0; iItem < matches.length; iItem += 2 ) {
		var strItem = templateString.substring( matches[iItem] + separationString.length, matches[iItem+1] );

		templateObj[strItem] = undefined;
	}

	// Attach the original template string onto the parsed template object, so that
	// we can reconstruct it later
	templateObj.__fullTemplateString__= templateString;
	templateObj.__templateMatches__ = matches;

	return templateObj;
} // end parseTemplate()
<commit_msg>A function to get a list of the params inside of a given template string, excluding the hidden ones we tag on to preserve template contents<commit_after>//////////////////////////////////////////////////////////////////////////
// maker
//////////////////////////////////////////////////////////////////////////
//
// Main module
//
/* ----------------------------------------------------------------------
                                                    Object Structures
-------------------------------------------------------------------------

*/
//////////////////////////////////////////////////////////////////////////
// Node.js Exports
exports.createMaker = function( separationString ) { return new Maker(separationString); }

//////////////////////////////////////////////////////////////////////////
// Namespace (lol)
var DEBUG = true;

var log = function( text, isImportant ) {
	if(DEBUG && isImportant) {
		console.log("\n******************************************")
		console.log("* " + text)
		console.log("******************************************\n")
	} else if(DEBUG) {
		console.log(text);
	}
};

var pathModule = require("path"),
	basename = require("path").basename,
	traverse = require("traverse"),
	wrench = require("wrench"),
	clone = require("clone"),
	async = require("async"),
	fs = require("fs");

var templateFileExtension = ".tpl";

//////////////////////////////////////////////////////////////////////////
// Constructor
function Maker( separationString ) {
	this.separationString = separationString || "~~";
	this.templates = {};
} // end Maker()

//////////////////////////////////////////////////////////////////////////
// Returns a template object loaded from a file
Maker.prototype.template = function( templateString, contents ) {
	var templateObj = parseTemplate( templateString, this.separationString );

	for( var property in contents ) {
		if( contents.hasOwnProperty(property) ) {

			templateObj[property] = contents[property] || undefined;
		}
	}

	return templateObj;
} // end template()

//////////////////////////////////////////////////////////////////////////
// Returns an array of the template params within a template string
Maker.prototype.getTemplateParams = function( templateString, contents ) {
	var templateObj = parseTemplate( templateString, this.separationString ),
		params = [];

	for( var property in templateObj ) {
		if( templateObj.hasOwnProperty(property) && property != "__fullTemplateString__" && property != "__templateMatches__" ) {
			params.push( property );
		}
	}

	return params;
} // end getTemplateParams()

//////////////////////////////////////////////////////////////////////////
// Retrurns a template object created by processing a file on disk
Maker.prototype.makeTemplate = function( filePath, templateParams ) {
	try {
		var file = fs.readFileSync( filePath, "utf8" );
	} catch( err ) {
		console.log( err );
		return {};
	}

	// Replace all instances of given strings with the given template
	// parameter string within the file
	for( var iParam in templateParams ) {
		if( templateParams.hasOwnProperty(iParam) ) {
			var templateParamString = this.separationString + templateParams[iParam] + this.separationString;
			file = file.replace( new RegExp(iParam, "g"), templateParamString );
		}
	}

	var template = parseTemplate( file, this.separationString );

	this.templates[filePath] = template

	return clone( template );
} // end makeTemplate()

//////////////////////////////////////////////////////////////////////////
// Returns a template
Maker.prototype.getTemplate = function( templateName ) {
	return clone( this.templates[templateName] );
} // end getTemplate()

//////////////////////////////////////////////////////////////////////////
// Returns a template filled with the contents given
Maker.prototype.fillTemplate = function( template, contents ) {
	var templateObj = {};

	if( typeof(template) === "string" )
		templateObj = clone( this.templates[template] );
	else
		templateObj = template;

	for( var property in contents ) {
		if( contents.hasOwnProperty(property) ) {

			templateObj[property] = contents[property] || undefined;
		}
	}

	return templateObj;
} // end fillTemplate()

//////////////////////////////////////////////////////////////////////////
// Creates a file on disk composed of the given templates
Maker.prototype.makeFile = function( path, templates, callback ) {
	log( "Making file " + path );

	// If this is a folder, just return
	if( pathModule.extname(path) == "" )
		return;

	// Convert any templates that are still objects into strings
	for( var iTemplate=0; iTemplate<templates.length; ++iTemplate ) {
		if( typeof(templates[iTemplate]) === "object" ) {
			templates[iTemplate] = this.renderTemplateToString( templates[iTemplate] );
		}
	}

	var fileContents = "";

	// Concatenate all template strings into one big string
	for( var iTemplate=0; iTemplate<templates.length; ++iTemplate ) {
		fileContents += templates[iTemplate];
	}

	var folderPath = pathModule.dirname( path );

	// Create the directory if it didn't exist already
	wrench.mkdirSyncRecursive( folderPath );

	// Write the file to disk
	fs.writeFile( path, fileContents, function(err) {
	    if(err) {
	        console.log(err);
	    }

	    if( callback != undefined )
	    	callback( err );
	});
} // end makeFile()

//////////////////////////////////////////////////////////////////////////
// Renders a template recursively back into a string
Maker.prototype.renderTemplateToString = function( template ) {
	if( typeof(template) === "string" )
		template = this.templates[template];

	// Start with the original template string
	var renderedTemplate = template.__fullTemplateString__,
		matches = template.__templateMatches__;

	for( var iItem in template ) {
		if( iItem == "__fullTemplateString__" || iItem == "__templateMatches__" )
			continue;

		//console.log("item " + iItem + " is of type " + typeof iItem + " with value " + template[iItem] );

		if( typeof template[iItem] == "undefined" || template[iItem] == "undefined" ) {
			template[iItem] = "";
			console.log( "Item '" + iItem + "' is undefined" );
		} else if( typeof template[iItem] === "object" ) {
			// Render this template recursively
			template[iItem] = this.renderTemplateToString( template[iItem] );
		} else if( typeof template[iItem] != "string" ) {
			console.log( "Item '" + iItem + "' is not a string" );
		}

		var stringToReplace = this.separationString + iItem + this.separationString;

		try {
			renderedTemplate = renderedTemplate.replace( new RegExp(stringToReplace, "g"), template[iItem] );
		} catch( err ) {
			console.log( "renderTemplate: " + err );
		}
	}

	return renderedTemplate;
} // end renderTemplate()

//////////////////////////////////////////////////////////////////////////
// Loads all templates inside of a given directory
Maker.prototype.loadTemplateDir = function( templateDir, callback ) {
	var _this = this;
	var templates = {};

	// Walk the folder tree recursively
	wrench.readdirRecursive( templateDir, function(error, files) {
		if( files == null ) {
			log( "Templates loaded from directory " + templateDir );
			_this.templates = templates;
			return callback( templates );
		}

		for( var iFile=0; iFile<files.length; ++iFile ) {
			if( files[iFile].indexOf(".tpl") == -1 )
				continue;

			var path = templateDir + "/" + files[iFile],
				file = fs.readFileSync( path, "utf8" );

			var templateName = basename( path );

			// Trim off the extension
			templateName = templateName.substring( 0, templateName.length - templateFileExtension.length );

			templates[templateName] = _this.template( file );
		}
	});
} // end loadTemplateDir()

//////////////////////////////////////////////////////////////////////////
// Create templates from all files within a directory, and maps their
// filled out versions to a new location
Maker.prototype.makeTemplatesFromDir = function( source, dest, replacementMap, pathReplacementMap, extensions, contents, callback ) {
	log( "Making directory " + source + " into templates and outputting to " + dest, true );

	// Make the pathReplacementMap, extensions, and contents arguments optional
	if( arguments.length == 4 ) {
		callback = extensions;
		pathReplacementMap = {};
		extensions = [];
		contents = {};
	} else if( arguments.length == 5 ) {
		callback = contents;
		contents = {};
		extensions = [];
	} else if( arguments.length == 6 ) {
		callback = contents;
		contents = {};
	}

	if( extensions.length > 0 ) {
		log( "Only templating files with extensions: " + extensions );
	} else {
		log( "Not filtering for extensions" );
		log( arguments );
	}

	var _this = this,
		templates = {},
		numTemplates = 0,
		finishedReading = false,
		finishedTemplating = false;

	// Walk the folder tree recursively
	wrench.readdirRecursive( source, function(error, files) {
		if( files != undefined )
			numTemplates += files.length;

		if( files == null ) {
			log( numTemplates + " files inspected within directory " + source );
			_this.templates = templates;

			finishedReading = true;

			// We have a race condition between reading and templating,
			// so we want to make sure both are finished before calling callback()
			if( finishedTemplating && finishedReading ) {
				callback();
			}
		}

		function iteratorFn( file, finishedCB ) {
			// Make sure this file has a file extension we care about
			//
			// NOTE: extension filtering is optional, so if extensions is an
			// empty array, any file extension will be let through
			var hasValidExtension = extensions.length > 0 ? false : true;
			for( var iExtension = 0; iExtension < extensions.length; ++iExtension ) {
				if( pathModule.extname(file) == extensions[iExtension] )
					hasValidExtension = true;
			}

			// Give up on this round if this file has an invalid extension
			if( !hasValidExtension )
				return finishedCB();

			var path = source + "/" + file;

			var templateObj = _this.makeTemplate( path, replacementMap );

			// Copy over the parameters we're trying to fill in
			for( var property in contents ) {
				if( contents.hasOwnProperty(property) ) {
					templateObj[property] = contents[property] || undefined;
				}
			}

			// Use the path replacement map to modify output locations
			var outputPath = dest + file;
			for( var iItem in pathReplacementMap ) {
				if( pathReplacementMap.hasOwnProperty(iItem) ) {
					outputPath = outputPath.replace( new RegExp(iItem, "g"), pathReplacementMap[iItem] );
				}
			}

			_this.makeFile( outputPath, [templateObj], finishedCB );
		}

		function asyncCallback( error, results ) {
			finishedTemplating = true;

			// We have a race condition between reading and templating,
			// so we want to make sure both are finished before calling callback()
			if( finishedTemplating && finishedReading ) {
				callback();
			}
		}

		if( files != null )
			async.eachSeries( files, iteratorFn, asyncCallback );
	});
} // end makeTemplatesFromDir()

//////////////////////////////////////////////////////////////////////////
// Parses a template string and returns an object of its contents
function parseTemplate( templateString, separationString ) {
	var iPosition = 0,
		matches = [],
		templateObj = {};

	iPosition = templateString.indexOf( separationString, iPosition );

	while( iPosition > 0 ) {
		matches.push( iPosition );

		var newPosition = templateString.indexOf( separationString, iPosition+separationString.length );

		iPosition = newPosition;
	}

	if( matches.length % 2 != 0 ) {
		log( "Error while parsing template: Mismatched separation string" );
	}

	for( var iItem = 0; iItem < matches.length; iItem += 2 ) {
		var strItem = templateString.substring( matches[iItem] + separationString.length, matches[iItem+1] );

		templateObj[strItem] = undefined;
	}

	// Attach the original template string onto the parsed template object, so that
	// we can reconstruct it later
	templateObj.__fullTemplateString__= templateString;
	templateObj.__templateMatches__ = matches;

	return templateObj;
} // end parseTemplate()
<|endoftext|>


<commit_before>/* global: Promise */

const logger = require('winston');
const MongoDB = require('mongodb');
const BPromise = require('bluebird');

const DELAY = 0;

class Worker {
  constructor(github, database, mailer) {
    this.githubIssuesApi = github.issues;
    this.subscriptionsCollection = database.collection('subscriptions');
    this.deliveriesCollection = database.collection('deliveries');
    this.mailer = mailer;
  }

  run(subscription) {
    if (!!subscription.is_enabled) {
      return this.makeGithubRequest(subscription)
        .then((response) => this.processGithubResponse(subscription, response))
        .catch((err) => logger.error(err));
    }

    return BPromise.resolve();
  }

  /**
  * Every subscription in the database goes through
  * this function. Checks against GH for new
  * issues
  */
  makeGithubRequest(subscription) {
    const [owner, repo] = subscription.repo.split('/');

    const headers = {};
    if (subscription.etag) {
      headers['If-None-Match'] = subscription.etag;
    }

    const options = {
      headers: headers,
      owner: owner,
      repo: repo,
      labels: subscription.label,
      direction: 'desc'
    };

    if (subscription.since) {
      options.since = subscription.since;
    }

    return this.githubIssuesApi.getForRepo(options);
  }

  /**
   * Process GH response. Update DB
   * accordingly and send new mails
   */
  processGithubResponse(subscription, response) {
    return new Promise(resolve => {
      logger.debug(response);

      const subscriptionId = new MongoDB.ObjectID(subscription._id);
      const responseLength = response.length;
      const responseETag = response.meta.etag;
      const issues = response;
      const updateSubscriptionPayload = {
        'etag': responseETag
      };

      if (responseLength) {
        const d = new Date(issues[0].created_at); // most recent item first
        d.setSeconds(d.getSeconds() + 1);
        updateSubscriptionPayload.since = d.toISOString();

        return this.subscriptionsCollection.update({
          _id: subscriptionId
        }, {
          $set: updateSubscriptionPayload
        })
        .then(() => this.deliveriesCollection.find({
          subscription_id: subscriptionId,
          issue_number: {
            $in: issues.map(issue => issue.number)
          }
        }).toArray())
        .then(results => this.filterSentIssues(issues, results))
        .then(filteredIssues => this.filterOutdatedIssues(issues))
        .then(filteredIssues => this.sendEmails(subscription, filteredIssues))
        .catch(error => logger.error(error))
        .then(() => resolve());
      }

      return this.subscriptionsCollection.update({
        _id: subscriptionId
      }, {
        $set: updateSubscriptionPayload
      })
        .then(() => resolve());
    });
  }

  /**
  * Remove those from issues that exists in sent
  */
  filterSentIssues(issues, sent) {
    return issues.filter(issue => sent.map(item => item.issue_number).indexOf(issue.number) === -1);
  }

/**
  * Remove older issues
  */
  filterOutdatedIssues(issues) {
    return issues.filter(issue => new Date(issue.created_at) > new Date().setHours(0, 0, 0));
  }

  sendEmails(subscription, issues) {
    if (issues.length) {
      return this.mailer.sendEmail(subscription, issues)
        .then(body => this.storeDeliveries(issues, subscription._id, body.id));
    }

    return true;
  }

  storeDeliveries(issues, subscriptionId, emailId) {
    return BPromise.all([
      issues.map(issue => this.deliveriesCollection.insert({
        subscription_id: subscriptionId,
        issue_number: issue.number,
        message_id: emailId
      }))
    ]);
  }
}

module.exports = (github, database, mailer) => new Worker(github, database, mailer);
<commit_msg>fix filtering issues<commit_after>/* global: Promise */

const logger = require('winston');
const MongoDB = require('mongodb');
const BPromise = require('bluebird');

const DELAY = 0;

class Worker {
  constructor(github, database, mailer) {
    this.githubIssuesApi = github.issues;
    this.subscriptionsCollection = database.collection('subscriptions');
    this.deliveriesCollection = database.collection('deliveries');
    this.mailer = mailer;
  }

  run(subscription) {
    if (!!subscription.is_enabled) {
      return this.makeGithubRequest(subscription)
        .then((response) => this.processGithubResponse(subscription, response))
        .catch((err) => logger.error(err));
    }

    return BPromise.resolve();
  }

  /**
  * Every subscription in the database goes through
  * this function. Checks against GH for new
  * issues
  */
  makeGithubRequest(subscription) {
    const [owner, repo] = subscription.repo.split('/');

    const headers = {};
    if (subscription.etag) {
      headers['If-None-Match'] = subscription.etag;
    }

    const options = {
      headers: headers,
      owner: owner,
      repo: repo,
      labels: subscription.label,
      direction: 'desc'
    };

    if (subscription.since) {
      options.since = subscription.since;
    }

    return this.githubIssuesApi.getForRepo(options);
  }

  /**
   * Process GH response. Update DB
   * accordingly and send new mails
   */
  processGithubResponse(subscription, response) {
    return new Promise(resolve => {
      logger.debug(response);

      const subscriptionId = new MongoDB.ObjectID(subscription._id);
      const responseLength = response.length;
      const responseETag = response.meta.etag;
      const issues = response;
      const updateSubscriptionPayload = {
        'etag': responseETag
      };

      if (responseLength) {
        const d = new Date(issues[0].created_at); // most recent item first
        d.setSeconds(d.getSeconds() + 1);
        updateSubscriptionPayload.since = d.toISOString();

        return this.subscriptionsCollection.update({
          _id: subscriptionId
        }, {
          $set: updateSubscriptionPayload
        })
        .then(() => this.deliveriesCollection.find({
          subscription_id: subscriptionId,
          issue_number: {
            $in: issues.map(issue => issue.number)
          }
        }).toArray())
        .then(results => this.filterSentIssues(issues, results))
        .then(notSendIssues => this.filterOutdatedIssues(notSendIssues))
        .then(toSendIssues => this.sendEmails(subscription, toSendIssues))
        .catch(error => logger.error(error))
        .then(() => resolve());
      }

      return this.subscriptionsCollection.update({
        _id: subscriptionId
      }, {
        $set: updateSubscriptionPayload
      })
        .then(() => resolve());
    });
  }

  /**
  * Remove those from issues that exists in sent
  */
  filterSentIssues(issues, sent) {
    return issues.filter(issue => sent.map(item => item.issue_number).indexOf(issue.number) === -1);
  }

/**
  * Remove older issues
  */
  filterOutdatedIssues(issues) {
    return issues.filter(issue => new Date(issue.created_at) > new Date().setHours(0, 0, 0));
  }

  sendEmails(subscription, issues) {
    if (issues.length) {
      return this.mailer.sendEmail(subscription, issues)
        .then(body => this.storeDeliveries(issues, subscription._id, body.id));
    }

    return true;
  }

  storeDeliveries(issues, subscriptionId, emailId) {
    return BPromise.all([
      issues.map(issue => this.deliveriesCollection.insert({
        subscription_id: subscriptionId,
        issue_number: issue.number,
        message_id: emailId
      }))
    ]);
  }
}

module.exports = (github, database, mailer) => new Worker(github, database, mailer);
<|endoftext|>


<commit_before>/* global describe, it */

var $require = require('proxyquire');
var expect = require('chai').expect;
var sinon = require('sinon');
var factory = require('../../../../com/authorize/http/response/code');

describe('http/authorize/response/code', function() {

  it('should be annotated', function() {
    expect(factory['@implements']).to.equal('http://i.authnomicon.org/oauth2/authorization/http/ResponseType');
    expect(factory['@type']).to.equal('code');
  });

  it('should create response type without response modes', function(done) {
    var container = new Object();
    container.components = sinon.stub();
    container.components.withArgs('http://i.authnomicon.org/oauth2/authorization/http/ResponseMode').returns([]);
    var acs = new Object();
    acs.issue = sinon.stub().yieldsAsync(null, 'SplxlOBeZQQYbYS6WxSbIA');

    var codeSpy = sinon.stub();
    var factory = $require('../../../../com/authorize/http/response/code', {
      'oauth2orize': {
        grant: { code: codeSpy }
      }
    });

    factory(acs, undefined, container)
      .then(function(type) {
        expect(codeSpy).to.be.calledOnce;
        expect(codeSpy).to.be.calledWith({ modes: {} });
        done();
      })
      .catch(done);
  }); // should create response type without response modes

  describe('issue', function() {
    var container = new Object();
    container.components = sinon.stub()
    container.components.withArgs('http://i.authnomicon.org/oauth2/authorization/http/ResponseMode').returns([]);
    var acs = new Object();
    acs.issue = sinon.stub().yieldsAsync(null, 'SplxlOBeZQQYbYS6WxSbIA');

    var codeSpy = sinon.stub();
    var factory = $require('../../../../com/authorize/http/response/code', {
      'oauth2orize': {
        grant: { code: codeSpy }
      }
    });

    var issue;

    before(function(done) {
      factory(acs, null, container)
        .then(function(type) {
          issue = codeSpy.getCall(0).args[1];
          done();
        })
        .catch(done);
    });

    it('should issue authorization code with redirect URI', function(done) {
      var client = {
        id: 's6BhdRkqt3',
        name: 'My Example Client'
      };
      var user = {
        id: '248289761001',
        displayName: 'Jane Doe'
      };
      var ares = {
        allow: true,
        scope: [ 'profile', 'email' ]
      }
      var areq = {
        type: 'code',
        clientID: 's6BhdRkqt3',
        redirectURI: 'https://client.example.com/cb',
        state: 'af0ifjsldkj'
      }

      issue(client, 'https://client.example.org/cb', user, ares, areq, {}, function(err, code) {
        if (err) { return done(err); }

        expect(acs.issue.callCount).to.equal(1);
        expect(acs.issue.getCall(0).args[0]).to.deep.equal({
          client: {
            id: 's6BhdRkqt3',
            name: 'My Example Client'
          },
          redirectURI: 'https://client.example.org/cb',
          user: {
            id: '248289761001',
            displayName: 'Jane Doe'
          },
          grant: {
            allow: true,
            scope: [ 'profile', 'email' ]
          }
        });

        expect(code).to.equal('SplxlOBeZQQYbYS6WxSbIA');

        done();
      });
    }); // should issue authorization code with redirect URI

  }); // issue

  // TODO: createing grant with response modes

});
<commit_msg>Update tests.<commit_after>/* global describe, it */

var $require = require('proxyquire');
var expect = require('chai').expect;
var sinon = require('sinon');
var factory = require('../../../../com/authorize/http/response/code');

describe('http/authorize/response/code', function() {

  it('should be annotated', function() {
    expect(factory['@implements']).to.equal('http://i.authnomicon.org/oauth2/authorization/http/ResponseType');
    expect(factory['@type']).to.equal('code');
  });

  it('should create response type without response modes', function(done) {
    var container = new Object();
    container.components = sinon.stub();
    container.components.withArgs('http://i.authnomicon.org/oauth2/authorization/http/ResponseMode').returns([]);
    var acs = new Object();
    acs.issue = sinon.stub().yieldsAsync(null, 'SplxlOBeZQQYbYS6WxSbIA');

    var codeSpy = sinon.stub();
    var factory = $require('../../../../com/authorize/http/response/code', {
      'oauth2orize': {
        grant: { code: codeSpy }
      }
    });

    factory(acs, undefined, container)
      .then(function(type) {
        expect(codeSpy).to.be.calledOnce;
        expect(codeSpy).to.be.calledWith({ modes: {} });
        done();
      })
      .catch(done);
  }); // should create response type without response modes

  describe('issue', function() {
    var container = new Object();
    container.components = sinon.stub()
    container.components.withArgs('http://i.authnomicon.org/oauth2/authorization/http/ResponseMode').returns([]);
    var acs = new Object();
    acs.issue = sinon.stub().yieldsAsync(null, 'SplxlOBeZQQYbYS6WxSbIA');

    var codeSpy = sinon.stub();
    var factory = $require('../../../../com/authorize/http/response/code', {
      'oauth2orize': {
        grant: { code: codeSpy }
      }
    });

    var issue;

    before(function(done) {
      factory(acs, null, container)
        .then(function(type) {
          issue = codeSpy.getCall(0).args[1];
          done();
        })
        .catch(done);
    });

    it('should issue authorization code without locals', function(done) {
      var client = {
        id: 's6BhdRkqt3',
        name: 'My Example Client'
      };
      var user = {
        id: '248289761001',
        displayName: 'Jane Doe'
      };
      var ares = {
        allow: true,
        scope: [ 'profile', 'email' ]
      }
      var areq = {
        type: 'code',
        clientID: 's6BhdRkqt3',
        redirectURI: 'https://client.example.com/cb',
        state: 'af0ifjsldkj'
      }

      issue(client, 'https://client.example.org/cb', user, ares, areq, {}, function(err, code) {
        if (err) { return done(err); }

        expect(acs.issue.callCount).to.equal(1);
        expect(acs.issue.getCall(0).args[0]).to.deep.equal({
          client: {
            id: 's6BhdRkqt3',
            name: 'My Example Client'
          },
          redirectURI: 'https://client.example.org/cb',
          user: {
            id: '248289761001',
            displayName: 'Jane Doe'
          },
          grant: {
            allow: true,
            scope: [ 'profile', 'email' ]
          }
        });

        expect(code).to.equal('SplxlOBeZQQYbYS6WxSbIA');

        done();
      });
    }); // should issue authorization code without locals

  }); // issue

  // TODO: createing grant with response modes

});
<|endoftext|>