<commit_before>/*
Copyright (c) 2014, Ismaël Héry

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/*
 * Spec for French Porter Stemmer can be found at file:///Users/hery/projects/stemmer/docs/French%20stemming%20algorithm.html
 */

var Stemmer = require('./stemmer_fr');

var PorterStemmer = new Stemmer();
module.exports = PorterStemmer;

/*
 * Exports for test purpose
 */
PorterStemmer.prelude = prelude;
PorterStemmer.step1 = step1;
PorterStemmer.regions = regions;
PorterStemmer.stem = stem;

/**
 * Functions
 */
function stem(token) {
  token = prelude(token);

  var regs = regions(token);
  //console.log('regions:', regs)
  r1_txt = regs.r1;
  r2_txt = regs.r2;
  rv_txt = regs.rv;

  // Step 1
  var beforeStep1 = token;
  var suf, pref2, pref3, letterBefore, letter2Before;

  if ((suf = endsinArr(r2_txt, new Array('ance', 'iqUe', 'isme', 'able', 'iste', 'eux', 'ances', 'iqUes', 'ismes', 'ables', 'istes'))) != '') {
    token = token.slice(0, -suf.length); // delete
  } else if ((suf = endsinArr(token, new Array('atrice', 'ateur', 'ation', 'atrices', 'ateurs', 'ations'))) != '') {
    pref2 = token.slice(suf.length - 3, suf.length - 1);
    if ((sufr2 = endsinArr(r2_txt, new Array('atrice', 'ateur', 'ation', 'atrices', 'ateurs', 'ations'))) != '') {
      token = token.slice(0, -sufr2.length); // delete
    } else if (pref2 === 'ic') {
      token = token.slice(0, -suf.length - 2) + 'iqU'; // replace end with iqU
    }
  } else if ((suf = endsinArr(r2_txt, new Array('logie', 'logies'))) != '') {
    token = token.slice(0, -suf.length) + 'log'; // replace with log
  } else if ((suf = endsinArr(r2_txt, new Array('usion', 'ution', 'usions', 'utions'))) != '') {
    token = token.slice(0, -suf.length) + 'u'; // replace with u
  } else if ((suf = endsinArr(r2_txt, new Array('ence', 'ences'))) != '') {
    token = token.slice(0, -suf.length) + 'ent'; // replace with ent
  } else if ((suf = endsinArr(token, new Array('ement', 'ements'))) != '') {

    if ((suf = endsinArr(rv_txt, new Array('ement', 'ements'))) != '') {
      token = token.slice(0, -suf.length); // delete if in RV
    }

    pref2 = token.slice(suf.length - 3, suf.length - 1);
    pref3 = token.slice(suf.length - 4, suf.length - 1);

    if ((suf = endsinArr(r2_txt, new Array('ement', 'ements'))) != '' && pref2 === 'iv') {
      token = token.slice(0, -suf.length); // delete
      // TODO: (and if further preceded by at, delete if in R2
    } else if ((suf = endsinArr(r2_txt, new Array('ement', 'ements'))) != '' && pref3 === 'eus') {
      token = token.slice(0, -suf.length); // delete
    } else if ((suf = endsinArr(r1_txt, new Array('ement', 'ements'))) != '' && pref3 === 'eus') {
      token = token.slice(0, -suf.length) + 'eux'; // replace by eux
    } else if ((suf = endsinArr(r2_txt, new Array('ement', 'ements'))) != '' && (pref3 === 'abl' || pref3 === 'iqU')) {
      token = token.slice(0, -suf.length); // delete
    }
    //TODO: if preceded by ièr or Ièr, replace by i if in RV
  } else if ((suf = endsinArr(token, new Array('ité', 'ités'))) != '') {
    pref2 = token.slice(suf.length - 3, suf.length - 1);
    pref3 = token.slice(suf.length - 4, suf.length - 1);

    if ((suf = endsinArr(r2_txt, new Array('ement', 'ements'))) != '') {
      token = token.slice(0, -suf.length); // delete if in R2
    } else if (pref3 === 'abil') {
      token = token.slice(0, -suf.length) + 'abl'; // replace by abl
    } else if (pref2 === 'ic') {
      token = token.slice(0, -suf.length) + 'iqU'; // replace by abl
    }
  } else if ((suf = endsinArr(r2_txt, new Array('if', 'ive', 'ifs', 'ives'))) != '') {
    token = token.slice(0, -suf.length); // delete
    //TODO: if preceded by at, delete if in R2 (and if further preceded by ic, delete if in R2, else replace by iqU)
  } else if ((suf = endsinArr(token, new Array('eaux'))) != '') {
    token = token.slice(0, -suf.length) + 'eau'; // replace by eau
  } else if ((suf = endsinArr(r1_txt, new Array('aux'))) != '') {
    token = token.slice(0, -suf.length) + 'al'; // replace by al
  } else if ((suf = endsinArr(r2_txt, new Array('euse', 'euses'))) != '') {
    token = token.slice(0, -suf.length) + 'al'; // delete
  } else if ((suf = endsinArr(r1_txt, new Array('euse', 'euses'))) != '') {
    token = token.slice(0, -suf.length) + 'eux'; // replace by eux
  } else if ((suf = endsinArr(r1_txt, new Array('issement', 'issements'))) != '') {
    if (!isVowel(token[suf.length - 1])) {
      token = token.slice(0, -suf.length); // delete
    }
  } else if ((suf = endsinArr(rv_txt, new Array('amment'))) != '') {
    token = token.slice(0, -suf.length) + 'ant'; // replace by ant
  } else if ((suf = endsinArr(rv_txt, new Array('emment'))) != '') {
    token = token.slice(0, -suf.length) + 'ent'; // replace by ent
  } else if ((suf = endsinArr(rv_txt, new Array('ment', 'ments'))) != '') {
    if (isVowel(token[suf.length - 1])) {
      token = token.slice(0, -suf.length); // delete
    }
  }

  // Step 2a
  var beforeStep2a = token;
  if (beforeStep1 === token || (suf = endsinArr(beforeStep1, new Array('amment', 'emment', 'ment', 'ments'))) != '') {
    if ((suf = endsinArr(rv_txt, new Array('îmes', 'ît', 'îtes', 'i', 'ie', 'ies', 'ir', 'ira', 'irai', 'iraIent', 'irais', 'irait', 'iras', 'irent', 'irez', 'iriez', 'irions', 'irons', 'iront', 'is', 'issaIent', 'issais', 'issait', 'issant', 'issante', 'issantes', 'issants', 'isse', 'issent', 'isses', 'issez', 'issiez', 'issions', 'issons', 'it'))) != '') {
      letterBefore = token[token.length - suf.length - 1];
      if (!isVowel(letterBefore) && endsin(rv_txt, letterBefore + suf))
        token = token.slice(0, -suf.length); // delete
    }
  }

  // Step 2b
  if (token === beforeStep2a) {
    if ((suf = endsinArr(r2_txt, new Array('ions'))) != '') {
      token = token.slice(0, -suf.length); // delete
    }
    if ((suf = endsinArr(token, new Array('é', 'ée', 'ées', 'és', 'èrent', 'er', 'era', 'erai', 'eraIent', 'erais', 'erait', 'eras', 'erez', 'eriez', 'erions', 'erons', 'eront', 'ez', 'iez'))) != '') {
      token = token.slice(0, -suf.length); // delete
    }
    if ((suf = endsinArr(token, new Array('âmes', 'ât', 'âtes', 'a', 'ai', 'aIent', 'ais', 'ait', 'ant', 'ante', 'antes', 'ants', 'as', 'asse', 'assent', 'asses', 'assiez', 'assions'))) != '') {
      token = token.slice(0, -suf.length); // delete

      letterBefore = token[token.length - 1];
      if (letterBefore === 'e' && endsin(rv_txt, letterBefore + suf))
        token.slice(0, -1);
    }

    // Step 3
    if (!(token === beforeStep1)) {
      if (token[token.length - 1] === 'Y')
        token = token.slice(0, -1) + 'i';
      if (token[token.length - 1] === 'ç')
        token = token.slice(0, -1) + 'c';
    } // Step 4
    else {
      letterBefore = token[token.length - 1];
      letter2Before = token[token.length - 2];

      if (letterBefore === 's' && ['a', 'i', 'o', 'u', 'è', 's'].indexOf(letter2Before) == -1)
        token = token.slice(0, -1);

      if ((suf = endsinArr(rv_txt, new Array('ion'))) != '') {
        if ((suf = endsinArr(r2_txt, new Array('ion'))) != '') {
          letterBefore = token[token.length - suf.length - 1];
          if (letterBefore === 's' || letterBefore === 't')
            token = token.slice(0, -suf.length) + 'ent'; // delete
        }
      }

      if ((suf = endsinArr(rv_txt, new Array('ier', 'ière', 'Ier', 'Ière'))) != '') {
        token = token.slice(0, -suf.length) + 'i'; // replace by i
      }
      if ((suf = endsinArr(rv_txt, 'e')) != '') {
        token = token.slice(0, -suf.length); // delete
      }
      if ((suf = endsinArr(rv_txt, 'ë')) != '') {
        if (token.slice(token.length - 3, -1) === 'gu')
          token = token.slice(0, -suf.length); // delete

      }

    }

  }

  return token;

};

function regions(token) {
  var r1 = r2 = len = token.length;
  var rv = '';
  var i;

  token = token.toLowerCase();

  // R1 is the region after the first non-vowel following a vowel,
  for (var i = 0; i < len - 1 && r1 == len; i++) {
    if (isVowel(token[i]) && !isVowel(token[i + 1])) {
      r1 = i + 2;
    }
  }
  // Or is the null region at the end of the word if there is no such non-vowel.

  // R2 is the region after the first non-vowel following a vowel in R1
  for (i = r1; i < len - 1 && r2 == len; i++) {
    if (isVowel(token[i]) && !isVowel(token[i + 1])) {
      r2 = i + 2;
    }
  }
  // Or is the null region at the end of the word if there is no such non-vowel.

  // RV region
  var three = token.slice(0, 3);
  if (three === 'par' || three == 'col' || three === 'tap')
    rv = token.slice(3, len);
  else {
    // two first letters are vowels
    if (isVowel(token[0]) && isVowel(token[1])) {
      rv = token.slice(3, len);
    }
    // the region after the first vowel not at the beginning of the word or null
    else {
      rv = '';
      for (i = 1; i < len && rv === ''; i++) {
        if (isVowel(token[i])) {
          rv = token.slice(i + 1, len);
        }
      }
    }
  }

  return {
    r1: token.substring(r1),
    r2: token.substring(r2),
    rv: rv
  };
};

function prelude(token) {
  token = token.toLowerCase();

  var result = '';
  var i = 0;

  // special case for i = 0 to avoid '-1' index
  if (token[i] === 'y' && isVowel(token[i + 1])) {
    result += token[i].toUpperCase();
  } else {
    result += token[i];
  }

  for (i = 1; i < token.length; i++) {
    if ((token[i] === 'u' || token[i] === 'i') && isVowel(token[i - 1]) && isVowel(token[i + 1])) {
      result += token[i].toUpperCase();
    } else if (token[i] === 'y' && (isVowel(token[i - 1]) || isVowel(token[i + 1]))) {
      result += token[i].toUpperCase();
    } else if (token[i] === 'u' && token[i - 1] === 'q') {
      result += token[i].toUpperCase();
    } else {
      result += token[i];
    }
  }

  return result;
};

function step1(token) {
  return token;
};

function isVowel(letter) {
  return (letter == 'a' || letter == 'e' || letter == 'i' || letter == 'o' || letter == 'u' || letter == 'y' || letter == 'â' || letter == 'à' || letter == 'ë' ||
    letter == 'é' || letter == 'ê' || letter == 'è' || letter == 'ï' || letter == 'î' || letter == 'ô' || letter == 'û' || letter == 'ù');
};

function endsin(token, suffix) {
  if (token.length < suffix.length) return false;
  return (token.slice(-suffix.length) == suffix);
};

function endsinArr(token, suffixes) {
  for (var i = 0; i < suffixes.length; i++) {
    if (endsin(token, suffixes[i])) return suffixes[i];
  }
  return '';
};
<commit_msg>more cases<commit_after>/*
Copyright (c) 2014, Ismaël Héry

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/*
 * Spec for French Porter Stemmer can be found at file:///Users/hery/projects/stemmer/docs/French%20stemming%20algorithm.html
 */

var Stemmer = require('./stemmer_fr');

var PorterStemmer = new Stemmer();
module.exports = PorterStemmer;

/*
 * Exports for test purpose
 */
PorterStemmer.prelude = prelude;
PorterStemmer.step1 = step1;
PorterStemmer.regions = regions;
PorterStemmer.stem = stem;

/**
 * Functions
 */
function stem(token) {
  token = prelude(token);

  var regs = regions(token);
  //console.log('regions:', regs)
  r1_txt = regs.r1;
  r2_txt = regs.r2;
  rv_txt = regs.rv;

  // Step 1
  var beforeStep1 = token;
  var suf, pref2, pref3, letterBefore, letter2Before;

  if ((suf = endsinArr(r2_txt, new Array('ance', 'iqUe', 'isme', 'able', 'iste', 'eux', 'ances', 'iqUes', 'ismes', 'ables', 'istes'))) != '') {
    token = token.slice(0, -suf.length); // delete
  } else if ((suf = endsinArr(token, new Array('atrice', 'ateur', 'ation', 'atrices', 'ateurs', 'ations'))) != '') {
    pref2 = token.slice(suf.length - 3, suf.length - 1);
    if ((sufr2 = endsinArr(r2_txt, new Array('atrice', 'ateur', 'ation', 'atrices', 'ateurs', 'ations'))) != '') {
      token = token.slice(0, -sufr2.length); // delete
    } else if (pref2 === 'ic') {
      token = token.slice(0, -suf.length - 2) + 'iqU'; // replace end with iqU
    }
  } else if ((suf = endsinArr(r2_txt, new Array('logie', 'logies'))) != '') {
    token = token.slice(0, -suf.length) + 'log'; // replace with log
  } else if ((suf = endsinArr(r2_txt, new Array('usion', 'ution', 'usions', 'utions'))) != '') {
    token = token.slice(0, -suf.length) + 'u'; // replace with u
  } else if ((suf = endsinArr(r2_txt, new Array('ence', 'ences'))) != '') {
    token = token.slice(0, -suf.length) + 'ent'; // replace with ent
  } else if ((suf = endsinArr(token, new Array('ement', 'ements'))) != '') {

    if ((suf = endsinArr(rv_txt, new Array('ement', 'ements'))) != '') {
      token = token.slice(0, -suf.length); // delete if in RV
    }

    pref2 = token.slice(suf.length - 3, suf.length - 1);
    pref3 = token.slice(suf.length - 4, suf.length - 1);

    if ((suf = endsinArr(r2_txt, new Array('ement', 'ements'))) != '' && pref2 === 'iv') {
      token = token.slice(0, -suf.length); // delete
      // TODO: (and if further preceded by at, delete if in R2
    } else if ((suf = endsinArr(r2_txt, new Array('ement', 'ements'))) != '' && pref3 === 'eus') {
      token = token.slice(0, -suf.length); // delete
    } else if ((suf = endsinArr(r1_txt, new Array('ement', 'ements'))) != '' && pref3 === 'eus') {
      token = token.slice(0, -suf.length) + 'eux'; // replace by eux
    } else if ((suf = endsinArr(r2_txt, new Array('ement', 'ements'))) != '' && (pref3 === 'abl' || pref3 === 'iqU')) {
      token = token.slice(0, -suf.length); // delete
    }
    //TODO: if preceded by ièr or Ièr, replace by i if in RV
  } else if ((suf = endsinArr(token, new Array('ité', 'ités'))) != '') {
    pref2 = token.slice(suf.length - 3, suf.length - 1);
    pref3 = token.slice(suf.length - 4, suf.length - 1);

    if ((suf = endsinArr(r2_txt, new Array('ement', 'ements'))) != '') {
      token = token.slice(0, -suf.length); // delete if in R2
    } else if (pref3 === 'abil') {
      token = token.slice(0, -suf.length) + 'abl'; // replace by abl
    } else if (pref2 === 'ic') {
      token = token.slice(0, -suf.length) + 'iqU'; // replace by abl
    }
  } else if ((suf = endsinArr(r2_txt, new Array('if', 'ive', 'ifs', 'ives'))) != '') {
    token = token.slice(0, -suf.length); // delete
    //TODO: if preceded by at, delete if in R2 (and if further preceded by ic, delete if in R2, else replace by iqU)
  } else if ((suf = endsinArr(token, new Array('eaux'))) != '') {
    token = token.slice(0, -suf.length) + 'eau'; // replace by eau
  } else if ((suf = endsinArr(r1_txt, new Array('aux'))) != '') {
    token = token.slice(0, -suf.length) + 'al'; // replace by al
  } else if ((suf = endsinArr(r2_txt, new Array('euse', 'euses'))) != '') {
    token = token.slice(0, -suf.length) + 'al'; // delete
  } else if ((suf = endsinArr(r1_txt, new Array('euse', 'euses'))) != '') {
    token = token.slice(0, -suf.length) + 'eux'; // replace by eux
  } else if ((suf = endsinArr(r1_txt, new Array('issement', 'issements'))) != '') {
    if (!isVowel(token[suf.length - 1])) {
      token = token.slice(0, -suf.length); // delete
    }
  } else if ((suf = endsinArr(rv_txt, new Array('amment'))) != '') {
    token = token.slice(0, -suf.length) + 'ant'; // replace by ant
  } else if ((suf = endsinArr(rv_txt, new Array('emment'))) != '') {
    token = token.slice(0, -suf.length) + 'ent'; // replace by ent
  } else if ((suf = endsinArr(rv_txt, new Array('ment', 'ments'))) != '') {
    if (isVowel(token[suf.length - 1])) {
      token = token.slice(0, -suf.length); // delete
    }
  }

  // Step 2a
  var beforeStep2a = token;
  if (beforeStep1 === token || (suf = endsinArr(beforeStep1, new Array('amment', 'emment', 'ment', 'ments'))) != '') {
    if ((suf = endsinArr(rv_txt, new Array('îmes', 'ît', 'îtes', 'i', 'ie', 'ies', 'ir', 'ira', 'irai', 'iraIent', 'irais', 'irait', 'iras', 'irent', 'irez', 'iriez', 'irions', 'irons', 'iront', 'is', 'issaIent', 'issais', 'issait', 'issant', 'issante', 'issantes', 'issants', 'isse', 'issent', 'isses', 'issez', 'issiez', 'issions', 'issons', 'it'))) != '') {
      letterBefore = token[token.length - suf.length - 1];
      if (!isVowel(letterBefore) && endsin(rv_txt, letterBefore + suf))
        token = token.slice(0, -suf.length); // delete
    }
  }

  // Step 2b
  if (token === beforeStep2a) {
    if ((suf = endsinArr(r2_txt, new Array('ions'))) != '') {
      token = token.slice(0, -suf.length); // delete
    }
    if ((suf = endsinArr(token, new Array('é', 'ée', 'ées', 'és', 'èrent', 'er', 'era', 'erai', 'eraIent', 'erais', 'erait', 'eras', 'erez', 'eriez', 'erions', 'erons', 'eront', 'ez', 'iez'))) != '') {
      token = token.slice(0, -suf.length); // delete
    }
    if ((suf = endsinArr(token, new Array('âmes', 'ât', 'âtes', 'a', 'ai', 'aIent', 'ais', 'ait', 'ant', 'ante', 'antes', 'ants', 'as', 'asse', 'assent', 'asses', 'assiez', 'assions'))) != '') {
      token = token.slice(0, -suf.length); // delete

      letterBefore = token[token.length - 1];
      if (letterBefore === 'e' && endsin(rv_txt, letterBefore + suf))
        token.slice(0, -1);
    }
  }

  // Step 3
  if (!(token === beforeStep1)) {
    if (token[token.length - 1] === 'Y')
      token = token.slice(0, -1) + 'i';
    if (token[token.length - 1] === 'ç')
      token = token.slice(0, -1) + 'c';
  } // Step 4
  else {
    letterBefore = token[token.length - 1];
    letter2Before = token[token.length - 2];

    if (letterBefore === 's' && ['a', 'i', 'o', 'u', 'è', 's'].indexOf(letter2Before) == -1)
      token = token.slice(0, -1);
    if ((suf = endsinArr(rv_txt, new Array('ion'))) != '') {
      if ((suf = endsinArr(r2_txt, new Array('ion'))) != '') {
        letterBefore = token[token.length - suf.length - 1];
        if (letterBefore === 's' || letterBefore === 't')
          token = token.slice(0, -suf.length) + 'ent'; // delete
      }
    }
    if ((suf = endsinArr(rv_txt, new Array('ier', 'ière', 'Ier', 'Ière'))) != '') {
      token = token.slice(0, -suf.length) + 'i'; // replace by i
    }
    if ((suf = endsinArr(rv_txt, 'e')) != '') {
      token = token.slice(0, -suf.length); // delete
    }
    if ((suf = endsinArr(rv_txt, 'ë')) != '') {
      if (token.slice(token.length - 3, -1) === 'gu')
        token = token.slice(0, -suf.length); // delete
    }
  }

  // Step 5
  if ((suf = endsinArr(token, new Array('enn', 'onn', 'ett', 'ell', 'eill'))) != '') {
    token = token.slice(0, -1); // delete last letter
  }

  return token.toLowerCase();

};

function regions(token) {
  var r1 = r2 = len = token.length;
  var rv = '';
  var i;

  token = token.toLowerCase();

  // R1 is the region after the first non-vowel following a vowel,
  for (var i = 0; i < len - 1 && r1 == len; i++) {
    if (isVowel(token[i]) && !isVowel(token[i + 1])) {
      r1 = i + 2;
    }
  }
  // Or is the null region at the end of the word if there is no such non-vowel.

  // R2 is the region after the first non-vowel following a vowel in R1
  for (i = r1; i < len - 1 && r2 == len; i++) {
    if (isVowel(token[i]) && !isVowel(token[i + 1])) {
      r2 = i + 2;
    }
  }
  // Or is the null region at the end of the word if there is no such non-vowel.

  // RV region
  var three = token.slice(0, 3);
  if (three === 'par' || three == 'col' || three === 'tap')
    rv = token.slice(3, len);
  else {
    // two first letters are vowels
    if (isVowel(token[0]) && isVowel(token[1])) {
      rv = token.slice(3, len);
    }
    // the region after the first vowel not at the beginning of the word or null
    else {
      rv = '';
      for (i = 1; i < len && rv === ''; i++) {
        if (isVowel(token[i])) {
          rv = token.slice(i + 1, len);
        }
      }
    }
  }

  return {
    r1: token.substring(r1),
    r2: token.substring(r2),
    rv: rv
  };
};

function prelude(token) {
  token = token.toLowerCase();

  var result = '';
  var i = 0;

  // special case for i = 0 to avoid '-1' index
  if (token[i] === 'y' && isVowel(token[i + 1])) {
    result += token[i].toUpperCase();
  } else {
    result += token[i];
  }

  for (i = 1; i < token.length; i++) {
    if ((token[i] === 'u' || token[i] === 'i') && isVowel(token[i - 1]) && isVowel(token[i + 1])) {
      result += token[i].toUpperCase();
    } else if (token[i] === 'y' && (isVowel(token[i - 1]) || isVowel(token[i + 1]))) {
      result += token[i].toUpperCase();
    } else if (token[i] === 'u' && token[i - 1] === 'q') {
      result += token[i].toUpperCase();
    } else {
      result += token[i];
    }
  }

  return result;
};

function step1(token) {
  return token;
};

function isVowel(letter) {
  return (letter == 'a' || letter == 'e' || letter == 'i' || letter == 'o' || letter == 'u' || letter == 'y' || letter == 'â' || letter == 'à' || letter == 'ë' ||
    letter == 'é' || letter == 'ê' || letter == 'è' || letter == 'ï' || letter == 'î' || letter == 'ô' || letter == 'û' || letter == 'ù');
};

function endsin(token, suffix) {
  if (token.length < suffix.length) return false;
  return (token.slice(-suffix.length) == suffix);
};

function endsinArr(token, suffixes) {
  for (var i = 0; i < suffixes.length; i++) {
    if (endsin(token, suffixes[i])) return suffixes[i];
  }
  return '';
};
<|endoftext|>


<commit_before>/**
 * grunt-npm-validate
 * https://github.com/joshuaspence/grunt-npm-validate
 *
 * Copyright (c) 2014 Joshua Spence
 * Licensed under the MIT license.
 */

'use strict';

var chalk = require('chalk'),
    PJV = require('package-json-validator').PJV;

function unary(fn) {
    return function(first) {
        return fn(first);
    };
}

module.exports = function(grunt) {
    grunt.registerTask('npm-validate', 'Opinionated package.json validator', function() {
        var options = this.options({
            file: grunt.config('pkgFile') || 'package.json'
        });

        var pkg = grunt.file.read(options.file);
        var result = PJV.validate(pkg);

        if (result.errors && result.errors.length) {
            grunt.log.subhead(chalk.bold(chalk.red('Errors:')));
            result.errors.forEach(unary(grunt.log.error));
        }

        if (result.warnings && result.warnings.length) {
            grunt.log.subhead(chalk.bold(chalk.yellow('Warnings:')));
            result.warnings.forEach(unary(grunt.log.warn));
        }

        if (result.recommendations && result.recommendations.length) {
            grunt.log.subhead(chalk.bold(chalk.yellow('Recommendations:')));
            result.recommendations.forEach(unary(grunt.log.warn));
        }

        return result.errors || result.warnings;
    });
};
<commit_msg>Add some `grunt.log` calls.<commit_after>/**
 * grunt-npm-validate
 * https://github.com/joshuaspence/grunt-npm-validate
 *
 * Copyright (c) 2014 Joshua Spence
 * Licensed under the MIT license.
 */

'use strict';

var chalk = require('chalk'),
    PJV = require('package-json-validator').PJV;

function unary(fn) {
    return function(first) {
        return fn(first);
    };
}

module.exports = function(grunt) {
    grunt.registerTask('npm-validate', 'Opinionated package.json validator', function() {
        var options = this.options({
            file: grunt.config('pkgFile') || 'package.json'
        });

        var pkg = grunt.file.read(options.file);

        grunt.log.write('Validating ' + options.file + '...');
        var result = PJV.validate(pkg);
        if (result.errors || result.warnings) {
            grunt.log.error();
        } else {
            grunt.log.ok();
        }

        if (result.errors && result.errors.length) {
            grunt.log.subhead(chalk.bold(chalk.red('Errors:')));
            result.errors.forEach(unary(grunt.log.error));
        }

        if (result.warnings && result.warnings.length) {
            grunt.log.subhead(chalk.bold(chalk.yellow('Warnings:')));
            result.warnings.forEach(unary(grunt.log.warn));
        }

        if (result.recommendations && result.recommendations.length) {
            grunt.log.subhead(chalk.bold(chalk.yellow('Recommendations:')));
            result.recommendations.forEach(unary(grunt.log.warn));
        }

        return result.errors || result.warnings;
    });
};
<|endoftext|>


<commit_before>(function() {
  'use strict';

  angular.module('stream', [])
    .factory('stream', ['$window', function(window){
      if (window.streams === undefined) {
        window.streams = {};
      }

      return function($scope, url, callback) {
        if (window.streams[url]) {
          // console.log('[Stream] Closing connection to ' + url);
          window.streams[url].close();
        }
        // console.log('[Stream] Initiating connection to ' + url);

        window.streams[url] = new EventSource(url + '?_=' + new Date().getTime());
        window.streams[url].onopen = function(e) {
          // console.log('[Stream] Connection opened to ' + url);
        };

        $scope.$on("$destroy", function() {
          // console.log('[Stream] Closing connection to ' + url);
          window.streams[url].close();
          delete window.streams[url];
        });

        return {
          subscribe: function(event, callback){
            window.streams[url].addEventListener(event, function(e) {
              var data = $.parseJSON(e.data);
              callback(data);
            }, false);
          }
        };
      };
    }]);
})();
<commit_msg>Re-enable console logging for streams<commit_after>(function(console) {
  'use strict';

  angular.module('stream', [])
    .factory('stream', ['$window', function(window){
      if (window.streams === undefined) {
        window.streams = {};
      }

      return function($scope, url, callback) {
        if (window.streams[url]) {
          console.log('[Stream] Closing connection to ' + url);
          window.streams[url].close();
        }
        console.log('[Stream] Initiating connection to ' + url);

        window.streams[url] = new EventSource(url + '?_=' + new Date().getTime());
        window.streams[url].onopen = function(e) {
          console.log('[Stream] Connection opened to ' + url);
        };

        $scope.$on("$destroy", function() {
          console.log('[Stream] Closing connection to ' + url);
          window.streams[url].close();
          delete window.streams[url];
        });

        return {
          subscribe: function(event, callback){
            window.streams[url].addEventListener(event, function(e) {
              var data = $.parseJSON(e.data);
              callback(data);
            }, false);
          }
        };
      };
    }]);
})(console);
<|endoftext|>


<commit_before>/*
 * grunt
 * https://github.com/cowboy/grunt
 *
 *
 * Copyright (c) 2012 "Cowboy" Ben Alman
 * Licensed under the MIT license.
 * http://benalman.com/about/license/
 *
 * Simple Watch task
 * Copyright (c) 2012 Amir Souchami
 * This file is based on the grunt/tasks/watch.js written by "Cowboy" Ben Alman
 * changes where made to get rid of the problematic use of fs.watch because sadly it did not respond on my server setup
 *
 * Licensed under the MIT license.
 * http://benalman.com/about/license/
 */

module.exports = function(grunt) {
	"use strict";
	// Nodejs libs.
	var fs = require('fs');
	var path = require('path');

	// ==========================================================================
	// TASKS
	// ==========================================================================

	// Keep track of last modified times of files, in case files are reported to
	// have changed incorrectly.
	var mtimes = {};

	grunt.registerTask('simple-watch', 'Run predefined tasks whenever watched files change.', function(target) {
		this.requiresConfig('watch');
		// Build an array of files/tasks objects.
		var watch = grunt.config('watch');
		var targets = target ? [target] : Object.keys(watch).filter(function(key) {
			return typeof watch[key] !== 'string' && !Array.isArray(watch[key]);
		});
		targets = targets.map(function(target) {
			// Fail if any required config properties have been omitted.
			target = ['watch', target];
			this.requiresConfig(target.concat('files'), target.concat('tasks'));
			return grunt.config(target);
		}, this);

		// Allow "basic" non-target format.
		if (typeof watch.files === 'string' || Array.isArray(watch.files)) {
			targets.push({files: watch.files, tasks: watch.tasks});
		}

		grunt.log.writeln('Simple Watch, Waiting...');

		// This task is asynchronous.
		var taskDone = this.async();
		// Get a list of files to be watched.
		var patterns = grunt.util._.chain(targets).pluck('files').flatten().uniq().value();
		var getFiles = grunt.file.expand.bind(grunt.file, patterns);

		// The tasks to be run.
		var tasks = []; //grunt.config(tasksProp);
		// This task's name + optional args, in string format.
		var nameArgs = this.nameArgs;
		// An ID by which the setInterval can be canceled.
		var intervalId;
		// Files that are being watched.
		var watchedFiles = {};
		// File changes to be logged.
		var changedFiles = {};

		// Define an alternate fail "warn" behavior.
		grunt.fail.warnAlternate = function() {
			grunt.task.clearQueue({untilMarker: true}).run(nameArgs);
		};

		// Cleanup when files have changed. This is debounced to handle situations
		// where editors save multiple files "simultaneously" and should wait until
		// all the files are saved.
		var done = grunt.util._.debounce(function() {
			// Clear the files-added setInterval.
			clearInterval(intervalId);
			// Ok!
			grunt.log.ok();
			var fileArray = Object.keys(changedFiles);
			fileArray.forEach(function(filepath) {
				// Log which file has changed, and how.
				grunt.log.ok('File "' + filepath + '" ' + changedFiles[filepath] + '.');
				// Clear the modified file's cached require data.
				// Removed: Grunt 0.4 does not support this anymore
				// grunt.file.clearRequireCache(filepath);
			});
			// Unwatch all watched files.
			Object.keys(watchedFiles).forEach(unWatchFile);
			// For each specified target, test to see if any files matching that
			// target's file patterns were modified.
			targets.forEach(function(target) {
				var files = grunt.file.expand(target.files);
				var intersection = grunt.util._.intersection(fileArray, files);
				// Enqueue specified tasks if a matching file was found.
				if (intersection.length > 0 && target.tasks) {
					grunt.task.run(target.tasks).mark();
				}
			});
			// Enqueue the watch task, so that it loops.
			grunt.task.run(nameArgs);
			// Continue task queue.
			taskDone();
		}, 250);

		// Handle file changes.
		function fileChanged(status, filepath) {
			// If file was deleted and then re-added, consider it changed.
			if (changedFiles[filepath] === 'deleted' && status === 'added') {
				status = 'changed';
			}
			// Emit watch events if anyone is listening
			if (grunt.event.listeners('watch').length > 0) {
				grunt.event.emit('watch', status, filepath);
			}
			// Keep track of changed status for later.
			changedFiles[filepath] = status;
			// Execute debounced done function.
			done();
		}

		// Watch a file.
		function watchFile(filepath) {
			if (!watchedFiles[filepath]) {
				// add a new file to watched files
				watchedFiles[filepath] = fs.statSync(filepath);
				mtimes[filepath] = +watchedFiles[filepath].mtime;
			}
		}

		// Unwatch a file.
		function unWatchFile(filepath) {
			if (watchedFiles[filepath]) {
				// Remove from watched files.
				delete watchedFiles[filepath];
			}
		}

		// Watch all currently existing files for changes.
		getFiles().forEach(watchFile);

		// Watch for files to be added.
		intervalId = setInterval(function() {
			var currFiles = getFiles();
			var lastWatched = Object.keys(watchedFiles);

			// Files that have been added since last interval execution.
			var added = grunt.util._.difference(currFiles, lastWatched);
			added.forEach(function(filepath) {
				// This file has been added.
				fileChanged('added', filepath);
				// Watch this file.
				watchFile(filepath);
			});

			// Files that have been deleted since last interval execution.
			var deleted = grunt.util._.difference(lastWatched,currFiles);
			deleted.forEach(function(filepath) {
				// This file has been deleted.
				fileChanged('deleted', filepath);
				// UN-Watch this file.
				unWatchFile(filepath);
			});

			currFiles.forEach(function(filepath){
				// Get last modified time of file.
				var mtime = +fs.statSync(filepath).mtime;
				// If same as stored mtime, the file hasn't changed.
				if (mtime === mtimes[filepath]) { return; }
				// Otherwise it has, store mtime for later use.
				mtimes[filepath] = mtime;
				// the file has been changed
				fileChanged('changed', filepath);
			});
		}, 200);
	});

};<commit_msg>handle stat sync error<commit_after>/*
 * grunt
 * https://github.com/cowboy/grunt
 *
 *
 * Copyright (c) 2012 "Cowboy" Ben Alman
 * Licensed under the MIT license.
 * http://benalman.com/about/license/
 *
 * Simple Watch task
 * Copyright (c) 2012 Amir Souchami
 * This file is based on the grunt/tasks/watch.js written by "Cowboy" Ben Alman
 * changes where made to get rid of the problematic use of fs.watch because sadly it did not respond on my server setup
 *
 * Licensed under the MIT license.
 * http://benalman.com/about/license/
 */

module.exports = function(grunt) {
	"use strict";
	// Nodejs libs.
	var fs = require('fs');
	var path = require('path');

	// ==========================================================================
	// TASKS
	// ==========================================================================

	// Keep track of last modified times of files, in case files are reported to
	// have changed incorrectly.
	var mtimes = {};

	grunt.registerTask('simple-watch', 'Run predefined tasks whenever watched files change.', function(target) {
		this.requiresConfig('watch');
		// Build an array of files/tasks objects.
		var watch = grunt.config('watch');
		var targets = target ? [target] : Object.keys(watch).filter(function(key) {
			return typeof watch[key] !== 'string' && !Array.isArray(watch[key]);
		});
		targets = targets.map(function(target) {
			// Fail if any required config properties have been omitted.
			target = ['watch', target];
			this.requiresConfig(target.concat('files'), target.concat('tasks'));
			return grunt.config(target);
		}, this);

		// Allow "basic" non-target format.
		if (typeof watch.files === 'string' || Array.isArray(watch.files)) {
			targets.push({files: watch.files, tasks: watch.tasks});
		}

		grunt.log.writeln('Simple Watch, Waiting...');

		// This task is asynchronous.
		var taskDone = this.async();
		// Get a list of files to be watched.
		var patterns = grunt.util._.chain(targets).pluck('files').flatten().uniq().value();
		var getFiles = grunt.file.expand.bind(grunt.file, patterns);

		// The tasks to be run.
		var tasks = []; //grunt.config(tasksProp);
		// This task's name + optional args, in string format.
		var nameArgs = this.nameArgs;
		// An ID by which the setInterval can be canceled.
		var intervalId;
		// Files that are being watched.
		var watchedFiles = {};
		// File changes to be logged.
		var changedFiles = {};

		// Define an alternate fail "warn" behavior.
		grunt.fail.warnAlternate = function() {
			grunt.task.clearQueue({untilMarker: true}).run(nameArgs);
		};

		// Cleanup when files have changed. This is debounced to handle situations
		// where editors save multiple files "simultaneously" and should wait until
		// all the files are saved.
		var done = grunt.util._.debounce(function() {
			// Clear the files-added setInterval.
			clearInterval(intervalId);
			// Ok!
			grunt.log.ok();
			var fileArray = Object.keys(changedFiles);
			fileArray.forEach(function(filepath) {
				// Log which file has changed, and how.
				grunt.log.ok('File "' + filepath + '" ' + changedFiles[filepath] + '.');
				// Clear the modified file's cached require data.
				// Removed: Grunt 0.4 does not support this anymore
				// grunt.file.clearRequireCache(filepath);
			});
			// Unwatch all watched files.
			Object.keys(watchedFiles).forEach(unWatchFile);
			// For each specified target, test to see if any files matching that
			// target's file patterns were modified.
			targets.forEach(function(target) {
				var files = grunt.file.expand(target.files);
				var intersection = grunt.util._.intersection(fileArray, files);
				// Enqueue specified tasks if a matching file was found.
				if (intersection.length > 0 && target.tasks) {
					grunt.task.run(target.tasks).mark();
				}
			});
			// Enqueue the watch task, so that it loops.
			grunt.task.run(nameArgs);
			// Continue task queue.
			taskDone();
		}, 250);

		// Handle file changes.
		function fileChanged(status, filepath) {
			// If file was deleted and then re-added, consider it changed.
			if (changedFiles[filepath] === 'deleted' && status === 'added') {
				status = 'changed';
			}
			// Emit watch events if anyone is listening
			if (grunt.event.listeners('watch').length > 0) {
				grunt.event.emit('watch', status, filepath);
			}
			// Keep track of changed status for later.
			changedFiles[filepath] = status;
			// Execute debounced done function.
			done();
		}

		// Watch a file.
		function watchFile(filepath) {
			if (!watchedFiles[filepath]) {
				// add a new file to watched files
				var statStructure = null;
				try {
					statStructure = fs.statSync(filepath);
				} catch (e) { // StatSync can throw an error if the file has dissapeared in between
					return;
				}

				watchedFiles[filepath] = statStructure;
				mtimes[filepath] = +watchedFiles[filepath].mtime;
			}
		}

		// Unwatch a file.
		function unWatchFile(filepath) {
			if (watchedFiles[filepath]) {
				// Remove from watched files.
				delete watchedFiles[filepath];
			}
		}

		// Watch all currently existing files for changes.
		getFiles().forEach(watchFile);

		// Watch for files to be added.
		intervalId = setInterval(function() {
			var currFiles = getFiles();
			var lastWatched = Object.keys(watchedFiles);

			// Files that have been added since last interval execution.
			var added = grunt.util._.difference(currFiles, lastWatched);
			added.forEach(function(filepath) {
				// This file has been added.
				fileChanged('added', filepath);
				// Watch this file.
				watchFile(filepath);
			});

			// Files that have been deleted since last interval execution.
			var deleted = grunt.util._.difference(lastWatched,currFiles);
			deleted.forEach(function(filepath) {
				// This file has been deleted.
				fileChanged('deleted', filepath);
				// UN-Watch this file.
				unWatchFile(filepath);
			});

			currFiles.forEach(function(filepath){
				// Get last modified time of file.
				var mtime = +fs.statSync(filepath).mtime;
				// If same as stored mtime, the file hasn't changed.
				if (mtime === mtimes[filepath]) { return; }
				// Otherwise it has, store mtime for later use.
				mtimes[filepath] = mtime;
				// the file has been changed
				fileChanged('changed', filepath);
			});
		}, 200);
	});

};<|endoftext|>


<commit_before>;
define(['timemap', 'lib/knockout', 'epl/Settings', 'timemap/Environment', 'timemap/map/StoryPin', 'lib/seedrandom', 'lib/jquery.hammer'], function (timemap, ko, Settings, Environment, StoryPin) {

return (function () {

	//The list of displayed content types
	var contentTypes = {
		text : {index: 0, color: 'yellow', displayTitle: "Text",
			iconURL: Environment.routes.staticDirectory + '/images/text_icon_disabled_crop.png'},
		link : {index: 1, color: 'green', displayTitle: "Link",
			iconURL: Environment.routes.staticDirectory + '/images/link_icon_disabled_crop.png'},
		image : {index: 2, color: 'pink', displayTitle: "Image",
			iconURL: Environment.routes.staticDirectory + '/images/image_icon_disabled_crop.png'},
		pdf : {index: 3, color: 'purple', displayTitle: "PDF",
			iconURL: Environment.routes.staticDirectory + '/images/pdf_icon_disabled_crop.png'},
		audio : {index: 4, color: 'blue', displayTitle: "Audio",
			iconURL: Environment.routes.staticDirectory + '/images/audio_icon_disabled_crop.png'},
		video : {index: 5, color: 'gray', displayTitle: "Video",
			iconURL: Environment.routes.staticDirectory + '/images/video_icon_disabled_crop.png'}
	};

	var numCols = 3; //The number of columns to display icons within

	//Generate an enumerable list of the above content types, of the form:
	// ['text', 'link', ... ]
	var contentTypesList = (function () {
		var i = 0;
		var types = [];
		for(type in contentTypes) {
			types[i] = type;
			i++;
		}
		return types;
	})();

	var Branch = function (viewport) {
		var self = this;
		this.viewport = $(viewport);
		this.storySelector = viewport.find('#story-selector');
		this.floorplanUrl = ko.observable('');
		this.floorplanElement = this.viewport.find('[data-role=floorplan]');
		this.branchHeaderElement = this.viewport.find('[data-role=branch-header]');
		this.branchID = '';
		this.branchName = ko.observable('');
		this.branchDesc = ko.observable();
		this.branchStartDate = ko.observable();
		this.branchEndDate = ko.observable();
		this.dimensions = new (function () {
			var dimensions = this;

			this.numCols = numCols;
			this.numRows = Math.ceil(contentTypesList.length / this.numCols);
			this.viewerWidth = ko.observable(Environment.display.viewportWidth());
			this.viewerHeight = ko.observable(Environment.display.viewportHeight());
			this.cellDimensions = ko.computed(function () {
				return {
					width: Math.floor(dimensions.viewerWidth() / dimensions.numCols),
					height: Math.floor(dimensions.viewerHeight() / dimensions.numRows)
				};
			});
		})();

		this.typeCoordinates = {};
		this.storyData = {};
		this.selectedStoryType = ko.observable();
		this.allBranches = ko.observableArray([]);

		//Create and dynamically update the positions of the icons based on the viewport dimensions,
		//and initialize story data for each type
		for(type in contentTypes) {
			this.typeCoordinates[type] = ko.observable(
				this.pinCoordinates({
					type: type,
					id : self.branchID,
					title : self.branchName()
				})
			);

			this.storyData[type] = ko.observableArray([]);
		}

		this.dimensions.cellDimensions.subscribe(function (dimensions) {
			for(type in contentTypes) {
				self.typeCoordinates[type](
					self.pinCoordinates({
						type: type,
						id : self.branchID,
						title : self.branchName()
					})
				);
			}
		});

		ko.applyBindings({
			Environment : Environment,
			dimensions : this.dimensions,
			typeCoordinates : this.typeCoordinates,
			storyData : this.storyData,
			contentTypesList : contentTypesList,
			contentTypes : contentTypes,
			floorplanUrl : this.floorplanUrl,
			selectedStoryType : this.selectedStoryType,
			branchName : this.branchName,
			branchDesc : this.branchDesc,
			branchStartDate : this.branchStartDate,
			branchEndDate : this.branchEndDate,
			allBranches : this.allBranches,
			openStorySelector : function (type, event) {
				self.showStorySelector(type);
				event.stopPropagation(); //Otherwise the story selector will hide as soon as it's displayed
			},
			closeBranchView : function () {
				window.top.location = "#";
			}
		}, viewport[0]);

		//React to the changed floorplan when its image is properly loaded
		this.floorplanElement.load(function () {
			self.configureFloorplan();
		});

		//Hide story lists when clicking outside of them
		$(window).bind('click tap touchstart', function () {
			self.hideStorySelector();
		});
	};

	Branch.prototype.setYear = function (year) {
		timemap.updateQuest({
			year : year,
			onMap : false,
			branch : this.branchID
		});
	}

	Branch.prototype.showStorySelector = function (type) {
		this.selectedStoryType(type);
		this.storySelector.show().css('left', Environment.display.mouseX()).css('top', Environment.display.mouseY());
	};

	Branch.prototype.hideStorySelector = function () {
		this.storySelector.hide();
	};

	Branch.prototype.pinCoordinates = function (pin) {
		var self = this,
			col = contentTypes[pin.type].index % this.dimensions.numCols,
			row = Math.floor(contentTypes[pin.type].index / this.dimensions.numCols);

		return {
			root : cellRoot(col, row),
			random : cellRandom(col, row)
		}

		//Compute the cell's top-left root coordinates
		function cellRoot (col, row) {
			// Since the image is centered, the pins need to be shifted over to be centered too
			var centeringAdjustment = (Environment.display.viewportWidth() - self.floorplanElement.width()) / 2
			return {
				x : self.dimensions.cellDimensions().width * col + centeringAdjustment,
				y : self.dimensions.cellDimensions().height * row + self.branchHeaderElement.height()
			};
		}

		//Compute the random location for the cell
		function cellRandom (col, row) {
			var centFactor = 0.6;
			Math.seedrandom(pin.title + 'horizontal-direction' + pin.type);
			var xRandom = Math.random() * centFactor;
			Math.seedrandom(pin.title + 'vertical-direction' + pin.type);
			var yRandom = Math.random() * centFactor;

			var cellRootValue = cellRoot(col, row);

			return {
				x : cellRootValue.x +(xRandom * self.dimensions.cellDimensions().width) + (1 - centFactor)/2 * self.dimensions.cellDimensions().width,
				y : cellRootValue.y +(yRandom * self.dimensions.cellDimensions().height) + (1 - centFactor)/2 * self.dimensions.cellDimensions().height,
			};
		}
	};

	Branch.prototype.configureFloorplan = function() {
		var floorplanWidth = this.floorplanElement.width(),
			floorplanHeight = this.floorplanElement.height(),
			headerHeight = this.branchHeaderElement.height(),
			effectiveViewportHeight = Environment.display.viewportHeight() - headerHeight,
			viewportWidth = Environment.display.viewportWidth();

		// Stretch to the full height unless it would cause the width to overflow...
		if ((effectiveViewportHeight / floorplanHeight * floorplanWidth) <= viewportWidth) {
			this.floorplanElement.height(effectiveViewportHeight);
		// ...in which case, stretch to the full width
		} else {
			this.floorplanElement.width(viewportWidth);
		}

		this.dimensions.viewerWidth(this.floorplanElement.width());
		// The height of the icon is ~60px, so 60px is subtracted to ensure the icon fits
		this.dimensions.viewerHeight(this.floorplanElement.height() - 70);
	};

	Branch.prototype.setData = function (branchData) {
		var self = this;
		this.branchID = branchData.id;
		this.branchName(branchData.name);
		this.branchDesc(branchData.description);
		this.branchStartDate(branchData.start_year);
		var endYear = branchData.end_year != null ? branchData.end_year : "Present";
		this.branchEndDate(endYear);
		this.floorplanUrl(branchData.floor_plan);
		// Obtain all the branches for the 'Jump to Branch' drop down
		$.getJSON (Settings.apiBranchUrl, function(data) {
			self.allBranches(data.objects);
			// Remove the current branch from the drop down options
			self.allBranches.remove(function(branch) {
				return branch.id == self.branchID;
			});
		});

		timemap.updateQuest({
			branch : this.branchID,
			onMap : false
		});
	};

	Branch.prototype.showPin = function (pin) {
		var typePins = this.storyData[pin.type](),
			exists = false;
		for(i in typePins) {
			if(typePins[i].id == pin.id) {
				exists = true;
			}
		}
		if(!exists) {
			this.storyData[pin.type].push(pin);
		}
	};

	Branch.prototype.hidePin = function (pin) {
		this.storyData[pin.type].remove(function (item) {
			return item.id == pin.id;
		});
	};

	return Branch;

})();

});<commit_msg>The Branch story selector menu stays on the screen, regardless of where the story pin is located.<commit_after>;
define(['timemap', 'lib/knockout', 'epl/Settings', 'timemap/Environment', 'timemap/map/StoryPin', 'lib/seedrandom', 'lib/jquery.hammer'], function (timemap, ko, Settings, Environment, StoryPin) {

return (function () {

	//The list of displayed content types
	var contentTypes = {
		text : {index: 0, color: 'yellow', displayTitle: "Text",
			iconURL: Environment.routes.staticDirectory + '/images/text_icon_disabled_crop.png'},
		link : {index: 1, color: 'green', displayTitle: "Link",
			iconURL: Environment.routes.staticDirectory + '/images/link_icon_disabled_crop.png'},
		image : {index: 2, color: 'pink', displayTitle: "Image",
			iconURL: Environment.routes.staticDirectory + '/images/image_icon_disabled_crop.png'},
		pdf : {index: 3, color: 'purple', displayTitle: "PDF",
			iconURL: Environment.routes.staticDirectory + '/images/pdf_icon_disabled_crop.png'},
		audio : {index: 4, color: 'blue', displayTitle: "Audio",
			iconURL: Environment.routes.staticDirectory + '/images/audio_icon_disabled_crop.png'},
		video : {index: 5, color: 'gray', displayTitle: "Video",
			iconURL: Environment.routes.staticDirectory + '/images/video_icon_disabled_crop.png'}
	};

	var numCols = 3; //The number of columns to display icons within

	//Generate an enumerable list of the above content types, of the form:
	// ['text', 'link', ... ]
	var contentTypesList = (function () {
		var i = 0;
		var types = [];
		for(type in contentTypes) {
			types[i] = type;
			i++;
		}
		return types;
	})();

	var Branch = function (viewport) {
		var self = this;
		this.viewport = $(viewport);
		this.storySelector = viewport.find('#story-selector');
		this.floorplanUrl = ko.observable('');
		this.floorplanElement = this.viewport.find('[data-role=floorplan]');
		this.branchHeaderElement = this.viewport.find('[data-role=branch-header]');
		this.branchID = '';
		this.branchName = ko.observable('');
		this.branchDesc = ko.observable();
		this.branchStartDate = ko.observable();
		this.branchEndDate = ko.observable();
		this.dimensions = new (function () {
			var dimensions = this;

			this.numCols = numCols;
			this.numRows = Math.ceil(contentTypesList.length / this.numCols);
			this.viewerWidth = ko.observable(Environment.display.viewportWidth());
			this.viewerHeight = ko.observable(Environment.display.viewportHeight());
			this.cellDimensions = ko.computed(function () {
				return {
					width: Math.floor(dimensions.viewerWidth() / dimensions.numCols),
					height: Math.floor(dimensions.viewerHeight() / dimensions.numRows)
				};
			});
		})();

		this.typeCoordinates = {};
		this.storyData = {};
		this.selectedStoryType = ko.observable();
		this.allBranches = ko.observableArray([]);

		//Create and dynamically update the positions of the icons based on the viewport dimensions,
		//and initialize story data for each type
		for(type in contentTypes) {
			this.typeCoordinates[type] = ko.observable(
				this.pinCoordinates({
					type: type,
					id : self.branchID,
					title : self.branchName()
				})
			);

			this.storyData[type] = ko.observableArray([]);
		}

		this.dimensions.cellDimensions.subscribe(function (dimensions) {
			for(type in contentTypes) {
				self.typeCoordinates[type](
					self.pinCoordinates({
						type: type,
						id : self.branchID,
						title : self.branchName()
					})
				);
			}
		});

		ko.applyBindings({
			Environment : Environment,
			dimensions : this.dimensions,
			typeCoordinates : this.typeCoordinates,
			storyData : this.storyData,
			contentTypesList : contentTypesList,
			contentTypes : contentTypes,
			floorplanUrl : this.floorplanUrl,
			selectedStoryType : this.selectedStoryType,
			branchName : this.branchName,
			branchDesc : this.branchDesc,
			branchStartDate : this.branchStartDate,
			branchEndDate : this.branchEndDate,
			allBranches : this.allBranches,
			openStorySelector : function (type, event) {
				self.showStorySelector(type);
				event.stopPropagation(); //Otherwise the story selector will hide as soon as it's displayed
			},
			closeBranchView : function () {
				window.top.location = "#";
			}
		}, viewport[0]);

		//React to the changed floorplan when its image is properly loaded
		this.floorplanElement.load(function () {
			self.configureFloorplan();
		});

		//Hide story lists when clicking outside of them
		$(window).bind('click tap touchstart', function () {
			self.hideStorySelector();
		});
	};

	Branch.prototype.setYear = function (year) {
		timemap.updateQuest({
			year : year,
			onMap : false,
			branch : this.branchID
		});
	}

	Branch.prototype.showStorySelector = function (type) {
		this.selectedStoryType(type);
		var x = Math.min(Environment.display.width() - this.storySelector.width(), Environment.display.mouseX());
		var y = Math.min(Environment.display.height() - this.storySelector.height(), Environment.display.mouseY());
		this.storySelector.show().css('left', x).css('top', y);
	};

	Branch.prototype.hideStorySelector = function () {
		this.storySelector.hide();
	};

	Branch.prototype.pinCoordinates = function (pin) {
		var self = this,
			col = contentTypes[pin.type].index % this.dimensions.numCols,
			row = Math.floor(contentTypes[pin.type].index / this.dimensions.numCols);

		return {
			root : cellRoot(col, row),
			random : cellRandom(col, row)
		}

		//Compute the cell's top-left root coordinates
		function cellRoot (col, row) {
			// Since the image is centered, the pins need to be shifted over to be centered too
			var centeringAdjustment = (Environment.display.viewportWidth() - self.floorplanElement.width()) / 2
			return {
				x : self.dimensions.cellDimensions().width * col + centeringAdjustment,
				y : self.dimensions.cellDimensions().height * row + self.branchHeaderElement.height()
			};
		}

		//Compute the random location for the cell
		function cellRandom (col, row) {
			var centFactor = 0.6;
			Math.seedrandom(pin.title + 'horizontal-direction' + pin.type);
			var xRandom = Math.random() * centFactor;
			Math.seedrandom(pin.title + 'vertical-direction' + pin.type);
			var yRandom = Math.random() * centFactor;

			var cellRootValue = cellRoot(col, row);

			return {
				x : cellRootValue.x +(xRandom * self.dimensions.cellDimensions().width) + (1 - centFactor)/2 * self.dimensions.cellDimensions().width,
				y : cellRootValue.y +(yRandom * self.dimensions.cellDimensions().height) + (1 - centFactor)/2 * self.dimensions.cellDimensions().height,
			};
		}
	};

	Branch.prototype.configureFloorplan = function() {
		var floorplanWidth = this.floorplanElement.width(),
			floorplanHeight = this.floorplanElement.height(),
			headerHeight = this.branchHeaderElement.height(),
			effectiveViewportHeight = Environment.display.viewportHeight() - headerHeight,
			viewportWidth = Environment.display.viewportWidth();

		// Stretch to the full height unless it would cause the width to overflow...
		if ((effectiveViewportHeight / floorplanHeight * floorplanWidth) <= viewportWidth) {
			this.floorplanElement.height(effectiveViewportHeight);
		// ...in which case, stretch to the full width
		} else {
			this.floorplanElement.width(viewportWidth);
		}

		this.dimensions.viewerWidth(this.floorplanElement.width());
		// The height of the icon is ~60px, so 60px is subtracted to ensure the icon fits
		this.dimensions.viewerHeight(this.floorplanElement.height() - 70);
	};

	Branch.prototype.setData = function (branchData) {
		var self = this;
		this.branchID = branchData.id;
		this.branchName(branchData.name);
		this.branchDesc(branchData.description);
		this.branchStartDate(branchData.start_year);
		var endYear = branchData.end_year != null ? branchData.end_year : "Present";
		this.branchEndDate(endYear);
		this.floorplanUrl(branchData.floor_plan);
		// Obtain all the branches for the 'Jump to Branch' drop down
		$.getJSON (Settings.apiBranchUrl, function(data) {
			self.allBranches(data.objects);
			// Remove the current branch from the drop down options
			self.allBranches.remove(function(branch) {
				return branch.id == self.branchID;
			});
		});

		timemap.updateQuest({
			branch : this.branchID,
			onMap : false
		});
	};

	Branch.prototype.showPin = function (pin) {
		var typePins = this.storyData[pin.type](),
			exists = false;
		for(i in typePins) {
			if(typePins[i].id == pin.id) {
				exists = true;
			}
		}
		if(!exists) {
			this.storyData[pin.type].push(pin);
		}
	};

	Branch.prototype.hidePin = function (pin) {
		this.storyData[pin.type].remove(function (item) {
			return item.id == pin.id;
		});
	};

	return Branch;

})();

});<|endoftext|>


<commit_before>module.exports = {
  root: true,
  parserOptions: {
    ecmaVersion: 2017,
    sourceType: 'module'
  },
  extends: 'eslint:recommended',
  env: {
    browser: true
  },
  rules: {
  }
};
<commit_msg>Add globals to .eslintrc<commit_after>module.exports = {
  root: true,
  parserOptions: {
    ecmaVersion: 2017,
    sourceType: 'module'
  },
  extends: 'eslint:recommended',
  env: {
    browser: true
  },
  rules: {
  },
  globals: {
   $: true
  }
};
<|endoftext|>


<commit_before>/**
 * @see https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/naming-convention.md
 */

module.exports = {
	env: {
		browser: true,
		es2021: true,
		node: true,
	},
	extends: [
		"plugin:react/recommended",
		"standard-with-typescript",
		"plugin:@typescript-eslint/recommended",
	],
	overrides: [],
	parserOptions: {
		ecmaVersion: "latest",
		sourceType: "module",
		project: ["./tsconfig.json"],
	},
	plugins: ["react", "@typescript-eslint"],
	ignorePatterns: [".eslintrc.js"],
	rules: {
		"@typescript-eslint/restrict-plus-operands": 0, // TEMP: WIP: suppressing for now as chart.ts has s shit ton
		"@typescript-eslint/indent": ["error", "tab"],
		"@typescript-eslint/strict-boolean-expressions": 0,
		"comma-dangle": ["error", "only-multiline"],
		"no-lone-blocks": 0,
		"no-tabs": ["error", { allowIndentationTabs: true }],
		indent: ["error", "tab", { "SwitchCase": 1, "ImportDeclaration": 1 }],
		quotes: ["error", "single"],
		semi: ["error", "never"],
	},
};
<commit_msg>temp rule<commit_after>/**
 * @see https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/naming-convention.md
 */

module.exports = {
	env: {
		browser: true,
		es2021: true,
		node: true,
	},
	extends: [
		"plugin:react/recommended",
		"standard-with-typescript",
		"plugin:@typescript-eslint/recommended",
	],
	overrides: [],
	parserOptions: {
		ecmaVersion: "latest",
		sourceType: "module",
		project: ["./tsconfig.json"],
	},
	plugins: ["react", "@typescript-eslint"],
	ignorePatterns: [".eslintrc.js"],
	rules: {
		"@typescript-eslint/restrict-plus-operands": 0, // TEMP: WIP: suppressing for now as chart.ts has s shit ton
		"@typescript-eslint/indent": ["error", "tab"],
		"@typescript-eslint/strict-boolean-expressions": 0,
		"comma-dangle": ["error", "only-multiline"],
		"no-lone-blocks": 0,
		"no-tabs": 0, // TEMP: WIP: suppressing for now as chart.ts has s shit ton
		//"no-tabs": ["error", { allowIndentationTabs: true }],
		indent: ["error", "tab", { "SwitchCase": 1, "ImportDeclaration": 1 }],
		quotes: ["error", "single"],
		semi: ["error", "never"],
	},
};
<|endoftext|>


<commit_before>module.exports = {
  env: {
    browser: true,
    es6: true
  },
  parser: "babel-eslint",
  extends: "eslint:recommended",
  plugins: [
    "react"
  ],
  rules: {
    "indent": [
      "warn",
      2,
      { "SwitchCase": 1 }
    ],
    "quotes": [
      "warn",
      "double",
      { allowTemplateLiterals: true }
    ],
    "semi": [
      "warn",
      "never"
    ],
    "no-unused-vars": "warn",
    "comma-dangle": "off",
    "no-console": "warn",
    "no-debugger": "warn",
    "react/jsx-uses-react": "error",
    "react/jsx-uses-vars": "error"
  },
  globals: {
    createjs: false
  }
}
<commit_msg>remove createjs global value<commit_after>module.exports = {
  env: {
    browser: true,
    es6: true
  },
  parser: "babel-eslint",
  extends: "eslint:recommended",
  plugins: [
    "react"
  ],
  rules: {
    "indent": [
      "warn",
      2,
      { "SwitchCase": 1 }
    ],
    "quotes": [
      "warn",
      "double",
      { allowTemplateLiterals: true }
    ],
    "semi": [
      "warn",
      "never"
    ],
    "no-unused-vars": "warn",
    "comma-dangle": "off",
    "no-console": "warn",
    "no-debugger": "warn",
    "react/jsx-uses-react": "error",
    "react/jsx-uses-vars": "error"
  }
}
<|endoftext|>


<commit_before>// http://eslint.org/
module.exports = {
    "extends": "eslint:recommended",

    // http://eslint.org/docs/user-guide/configuring#specifying-environments
    "env": {
        "browser": true,
    },

    // http://eslint.org/docs/user-guide/configuring#specifying-globals
    "globals": {
        // false means it shouldn't be overwritten
        "define": false,
        "hqDefine": false,
        "hqImport": false,
        "requirejs": false,
        "gettext": false,
        "ngettext": false,
        "assert": false,
        "sinon": false,
        "$": false,
        "ko": false,
        "_": false,
        "L": true,
        "it": false,
        "describe": false,
        "beforeEach": false,
        "nv": false,
        "d3": false,
    },

    "plugins": [
        "eslint-dimagi",
    ],

    // http://eslint.org/docs/rules/
    // http://eslint.org/docs/user-guide/configuring#configuring-rules
    "rules": {
        // First option can be off, warn, or error
        "camelcase": ["error", {"properties": "never"}],
        "comma-dangle": ["warn", "always-multiline"],
        "eqeqeq": ["error"],
        "indent": ["warn", 4, {"SwitchCase":1}],
        "linebreak-style": ["error", "unix"],
        "semi": ["error", "always"],
        "no-new-object": ["error"],
        "no-unneeded-ternary": ["error"],
        "no-throw-literal": ["error"],
        "no-implicit-globals": ["error"],

        "eslint-dimagi/no-unblessed-new": ["error", ["Date", "Error", "RegExp"]],
    }
};
<commit_msg>Allow<commit_after>// http://eslint.org/
module.exports = {
    "extends": "eslint:recommended",

    // http://eslint.org/docs/user-guide/configuring#specifying-environments
    "env": {
        "browser": true,
    },

    // http://eslint.org/docs/user-guide/configuring#specifying-globals
    "globals": {
        // false means it shouldn't be overwritten
        "define": false,
        "hqDefine": false,
        "hqImport": false,
        "requirejs": false,
        "gettext": false,
        "ngettext": false,
        "assert": false,
        "sinon": false,
        "$": false,
        "ko": false,
        "_": false,
        "L": true,
        "it": false,
        "describe": false,
        "beforeEach": false,
        "nv": false,
        "d3": false,
    },

    "plugins": [
        "eslint-dimagi",
    ],

    // http://eslint.org/docs/rules/
    // http://eslint.org/docs/user-guide/configuring#configuring-rules
    "rules": {
        // First option can be off, warn, or error
        "camelcase": ["error", {"properties": "never"}],
        "comma-dangle": ["warn", "always-multiline"],
        "eqeqeq": ["error"],
        "indent": ["warn", 4, {"SwitchCase":1}],
        "linebreak-style": ["error", "unix"],
        "semi": ["error", "always"],
        "no-new-object": ["error"],
        "no-unneeded-ternary": ["error"],
        "no-throw-literal": ["error"],
        "no-implicit-globals": ["error"],

        "eslint-dimagi/no-unblessed-new": ["error", ["Date", "Error", "RegExp", "Clipboard"]],
    }
};
<|endoftext|>


<commit_before>module.exports = {
  root: true,
  parserOptions: {
    ecmaVersion: 2017
  },
  plugins: [
    'node'
  ],
  extends: [
    'sane',
    'plugin:node/recommended'
  ],
  env: {
    es6: true,
    node: true
  },
  rules: {
  },
  overrides: [
    {
      files: ['bin/*.js'],
      rules: {
        'no-console': 'off'
      }
    },
    {
      files: ['test/**/*-test.js'],
      plugins: [
        'mocha'
      ],
      env: {
        mocha: true
      },
      rules: {
        'mocha/no-exclusive-tests': 'error'
      }
    }
  ]
};
<commit_msg>update ecmaVersion 2018<commit_after>module.exports = {
  root: true,
  parserOptions: {
    ecmaVersion: 2018
  },
  plugins: [
    'node'
  ],
  extends: [
    'sane',
    'plugin:node/recommended'
  ],
  env: {
    es6: true,
    node: true
  },
  rules: {
  },
  overrides: [
    {
      files: ['bin/*.js'],
      rules: {
        'no-console': 'off'
      }
    },
    {
      files: ['test/**/*-test.js'],
      plugins: [
        'mocha'
      ],
      env: {
        mocha: true
      },
      rules: {
        'mocha/no-exclusive-tests': 'error'
      }
    }
  ]
};
<|endoftext|>


<commit_before>module.exports = {
	extends: [
		"giovanni/client",
		"giovanni/library"
	]
};
<commit_msg>Updated ESLint settings<commit_after>module.exports = {
	extends: "giovanni/library"
};
<|endoftext|>


<commit_before>module.exports = {
  extends: '@kenan'
};
<commit_msg>lint: disable `no-process-exit` rule<commit_after>module.exports = {
  extends: '@kenan',
  rules: {
    'no-process-exit': 0
  }
};
<|endoftext|>


<commit_before>module.exports = {
	root: true,
	env: {
	  node: true,
	},
	parser: '@typescript-eslint/parser',
	extends: [
	  'plugin:@typescript-eslint/recommended'
	],
	parserOptions: {
	  ecmaVersion: 2020,
	  sourceType: 'module',
	},
	rules: {
	  'semi': ['error', 'never'],
	},
	ignorePatterns: [ "dist/*" ],
}
<commit_msg>Use underscore for unused variables<commit_after>module.exports = {
	root: true,
	env: {
	  node: true,
	},
	parser: '@typescript-eslint/parser',
	extends: [
	  'plugin:@typescript-eslint/recommended'
	],
	parserOptions: {
	  ecmaVersion: 2020,
	  sourceType: 'module',
	},
	rules: {
	  'semi': ['error', 'never'],
	  '@typescript-eslint/no-unused-vars': ['warn', { 'argsIgnorePattern': '^_', 'varsIgnorePattern': '^_' }],
	},
	ignorePatterns: [ "dist/*" ],
}
<|endoftext|>


<commit_before>module.exports = {
  root: true,
  env: {
  },
  globals: {
  },
  rules: {
    // JSHint "expr"
    'no-unused-expressions': [2, {
      allowShortCircuit: true,
      allowTernary: true,
    }],

    // JSHint "proto", disabled due to warnings
    'no-proto': 0,

    // JSHint "strict", disabled due to warnings
    'strict': [0, 'function'],

    // JSHint "indent", disabled due to warnings
    'indent': [0, 2, {
      'SwitchCase': 0,
      'VariableDeclarator': { 'var': 2, 'let': 2, 'const': 3 }
    }],

    // JSHint "camelcase"
    camelcase: 2,

    // JSHint "boss"
    'no-cond-assign': [2, 'except-parens'],
  },
};
<commit_msg>ESLint: Add "curly" rule<commit_after>module.exports = {
  root: true,
  env: {
  },
  globals: {
  },
  rules: {
    // JSHint "expr"
    'no-unused-expressions': [2, {
      allowShortCircuit: true,
      allowTernary: true,
    }],

    // JSHint "proto", disabled due to warnings
    'no-proto': 0,

    // JSHint "strict", disabled due to warnings
    'strict': [0, 'function'],

    // JSHint "indent", disabled due to warnings
    'indent': [0, 2, {
      'SwitchCase': 0,
      'VariableDeclarator': { 'var': 2, 'let': 2, 'const': 3 }
    }],

    // JSHint "camelcase"
    camelcase: 2,

    // JSHint "boss"
    'no-cond-assign': [2, 'except-parens'],

    // JSHint "curly"
    curly: 2,
  },
};
<|endoftext|>


<commit_before>module.exports = {
    env: {
        es6: true,
        node: true
    },
    extends: 'eslint:recommended',
    parserOptions: {
        ecmaVersion: 7,
        sourceType: 'module'
    },
    rules: {
        'strict': [ 'error', 'global' ],
        'indent': [ 'error', 4 ],
        'linebreak-style': [ 'error', 'unix' ],
        'quotes': [ 'error', 'single' ],
        'semi': [ 'error', 'always' ]
    }
};<commit_msg>Removed Node environment from ESLint config.<commit_after>module.exports = {
    env: {
        es6: true
    },
    extends: 'eslint:recommended',
    parserOptions: {
        ecmaVersion: 7,
        sourceType: 'module'
    },
    rules: {
        'strict': [ 'error', 'global' ],
        'indent': [ 'error', 4 ],
        'linebreak-style': [ 'error', 'unix' ],
        'quotes': [ 'error', 'single' ],
        'semi': [ 'error', 'always' ]
    }
};<|endoftext|>


<commit_before>module.exports = {
  "env": {
    "browser": true,
    "node": true,
    "es6": true
  },
  "extends": "eslint:recommended",
  "parserOptions": {
    "sourceType": "module"
  },
  "rules": {
    "comma-dangle": [
      "error",
      "never"
    ],
    "indent": [
      "error",
      2
    ],
    "linebreak-style": [
      "error",
      "unix"
    ],
    "quotes": [
      "error",
      "double"
    ],
    "semi": [
      "error",
      "always"
    ],
    "no-console": [
      0
    ]
  }
};
<commit_msg>start migrating the var keyword as well<commit_after>module.exports = {
  "env": {
    "browser": true,
    "node": true,
    "es6": true
  },
  "extends": "eslint:recommended",
  "parserOptions": {
    "sourceType": "module"
  },
  "rules": {
    "comma-dangle": [
      "error",
      "never"
    ],
    "indent": [
      "error",
      2
    ],
    "linebreak-style": [
      "error",
      "unix"
    ],
    "quotes": [
      "error",
      "double"
    ],
    "semi": [
      "error",
      "always"
    ],
    "no-console": [
      0
    ],
    "no-var": [
      "error"
    ]
  }
};
<|endoftext|>


<commit_before>module.exports = {
  "parser": "babel-eslint",
  "env": {
    "browser": true,
    "jest": true,
    "node": true,
    "es6": true
  },
  "extends": ["eslint:recommended", "plugin:react/recommended"],
  "parserOptions": {
    "ecmaFeatures": {
      "experimentalObjectRestSpread": true,
      "jsx": true
    },
    "sourceType": "module"
  },
  "plugins": [
    "react", "flowtype"
  ],
  "rules": {
    "flowtype/define-flow-type": 1,
    "flowtype/require-valid-file-annotation": ["error", "always"],

    "react/no-children-prop": ["off"],

    "indent": ["error", 2],
    "react/jsx-indent": ["error", 2],
    "react/jsx-indent-props": ["error", 2],
    "linebreak-style": ["error", "unix"],
    "quotes": ["error", "single", "avoid-escape"],
    "semi": ["error", "always"],
    "no-var": ["error"],
    "brace-style": ["error"],
    "array-bracket-spacing": ["error", "never"],
    "block-spacing": ["error", "always"],
    "no-spaced-func": ["error"],
    "no-whitespace-before-property": ["error"],
    "space-before-blocks": ["error", "always"],
    "keyword-spacing": ["error"],
    "no-unused-vars": ["error", {"argsIgnorePattern": "[iI]gnored"}],
  }
};
<commit_msg>Disable the new stricter React eslint rules for now.<commit_after>module.exports = {
  "parser": "babel-eslint",
  "env": {
    "browser": true,
    "jest": true,
    "node": true,
    "es6": true
  },
  "extends": ["eslint:recommended", "plugin:react/recommended"],
  "parserOptions": {
    "ecmaFeatures": {
      "experimentalObjectRestSpread": true,
      "jsx": true
    },
    "sourceType": "module"
  },
  "plugins": [
    "react", "flowtype"
  ],
  "rules": {
    "flowtype/define-flow-type": 1,
    "flowtype/require-valid-file-annotation": ["error", "always"],

    "react/no-children-prop": ["off"],

    "indent": ["error", 2],
    "react/jsx-indent": ["error", 2],
    "react/jsx-indent-props": ["error", 2],
    "linebreak-style": ["error", "unix"],
    "quotes": ["error", "single", "avoid-escape"],
    "semi": ["error", "always"],
    "no-var": ["error"],
    "brace-style": ["error"],
    "array-bracket-spacing": ["error", "never"],
    "block-spacing": ["error", "always"],
    "no-spaced-func": ["error"],
    "no-whitespace-before-property": ["error"],
    "space-before-blocks": ["error", "always"],
    "keyword-spacing": ["error"],
    "no-unused-vars": ["error", {"argsIgnorePattern": "[iI]gnored"}],

    // TODO remove?
    "react/no-find-dom-node": ["off"],
  }
};
<|endoftext|>


<commit_before>// http://eslint.org/docs/user-guide/configuring

module.exports = {
  root: true,
  parser: 'babel-eslint',
  parserOptions: {
    sourceType: 'module',
  },
  env: {
    browser: true,
  },
  extends: ['airbnb-base', 'prettier'],
  plugins: ['html', 'import', 'prettier'],
  settings: {
    'import/resolver': {
      webpack: {
        config: 'build/webpack.base.conf.js',
      },
    },
  },
  rules: {
    // don't require .vue extension when importing
    'import/extensions': [
      'error',
      'always',
      {
        js: 'never',
        vue: 'never',
        ts: 'never',
      },
    ],
    // allow debugger during development
    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
    'no-console': process.env.NODE_ENV === 'production' ? 1 : 0,
    'max-len': ['error', 100],
    'no-param-reassign': 0,
    // only for use with getter-setters
    'no-underscore-dangle': 0,
    'prettier/prettier': [
      'error',
      { singleQuote: true, trailingComma: 'all', printWidth: 100, tabWidth: 2 },
    ],
  },
};
<commit_msg>fix path to webpack config<commit_after>// http://eslint.org/docs/user-guide/configuring

module.exports = {
  root: true,
  parser: 'babel-eslint',
  parserOptions: {
    sourceType: 'module',
  },
  env: {
    browser: true,
  },
  extends: ['airbnb-base', 'prettier'],
  plugins: ['html', 'import', 'prettier'],
  settings: {
    'import/resolver': {
      webpack: {
        config: 'build-tools/config/webpack/webpack.base.conf.js',
      },
    },
  },
  rules: {
    // don't require .vue extension when importing
    'import/extensions': [
      'error',
      'always',
      {
        js: 'never',
        vue: 'never',
        ts: 'never',
      },
    ],
    // allow debugger during development
    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
    'no-console': process.env.NODE_ENV === 'production' ? 1 : 0,
    'max-len': ['error', 100],
    'no-param-reassign': 0,
    // only for use with getter-setters
    'no-underscore-dangle': 0,
    'prettier/prettier': [
      'error',
      { singleQuote: true, trailingComma: 'all', printWidth: 100, tabWidth: 2 },
    ],
  },
};
<|endoftext|>


<commit_before>module.exports = {
    "env": {
        "browser": true,
        "commonjs": true,
        "es6": true,
        "jasmine": true,
        "jest": true
    },
    "extends": "standard",
    "installedESLint": true,
    "parserOptions": {
        "ecmaFeatures": {
            "experimentalObjectRestSpread": true,
            "jsx": true
        },
        "sourceType": "module"
    },
    "plugins": [
        "react"
    ],
    "rules": {
        "indent": [
            "error",
            2
        ],
        "linebreak-style": [
            "error",
            "unix"
        ],
        "quotes": [
            "error",
            "double"
        ],
        "semi": [
            "error",
            "never"
        ],
        "jsx-quotes": [
            "error",
            "prefer-double"
        ],
        "react/prefer-stateless-function": "error",
        "react/prop-types": "error",
        "react/jsx-indent": ["warn", 2],
        "react/jsx-key": "error",
        "react/jsx-uses-vars": "error",
        "react/jsx-uses-react": "error",
        "react/jsx-no-bind": "error",
        "react/jsx-pascal-case": "warn",
        "react/jsx-closing-bracket-location": "warn",
    }
};
<commit_msg>remove obsolete eslint config<commit_after>module.exports = {
    "env": {
        "browser": true,
        "commonjs": true,
        "es6": true,
        "jasmine": true,
        "jest": true
    },
    "extends": "standard",
    "parserOptions": {
        "ecmaFeatures": {
            "experimentalObjectRestSpread": true,
            "jsx": true
        },
        "sourceType": "module"
    },
    "plugins": [
        "react"
    ],
    "rules": {
        "indent": [
            "error",
            2
        ],
        "linebreak-style": [
            "error",
            "unix"
        ],
        "quotes": [
            "error",
            "double"
        ],
        "semi": [
            "error",
            "never"
        ],
        "jsx-quotes": [
            "error",
            "prefer-double"
        ],
        "react/prefer-stateless-function": "error",
        "react/prop-types": "error",
        "react/jsx-indent": ["warn", 2],
        "react/jsx-key": "error",
        "react/jsx-uses-vars": "error",
        "react/jsx-uses-react": "error",
        "react/jsx-no-bind": "error",
        "react/jsx-pascal-case": "warn",
        "react/jsx-closing-bracket-location": "warn",
    }
};
<|endoftext|>


<commit_before>/**
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

var assert = require('assert');
var async = require('async');
var Dataset = require('../lib/bigquery/dataset');
var Table = require('../lib/bigquery/table');
var env = require('./env');
var fs = require('fs');
var Job = require('../lib/bigquery/job');
var uuid = require('node-uuid');

var gcloud = require('../lib')(env);
var bigquery = gcloud.bigquery();
var storage = gcloud.storage();

describe('BigQuery', function() {
  var DATASET_ID = ('gcloud_test_dataset_temp' + uuid.v1()).replace(/-/g, '_');
  var dataset = bigquery.dataset(DATASET_ID);
  var TABLE_ID = 'myKittens';
  var table = dataset.table(TABLE_ID);
  var BUCKET_NAME = 'gcloud-test-bucket-temp-' + uuid.v1();
  var bucket;

  var query = 'SELECT url FROM [publicdata:samples.github_nested] LIMIT 100';

  before(function(done) {
    async.series([
      // Create the test dataset.
      function(next) {
        dataset.create(next);
      },

      // Create the test table.
      function(next) {
        table.create({ schema: 'id:integer,breed,name,dob:timestamp' }, next);
      },

      // Create a Bucket.
      function(next) {
        storage.createBucket(BUCKET_NAME, function(err, bucket_) {
          if (err) {
            next(err);
            return;
          }

          bucket = bucket_;
          next();
        });
      }
    ], done);
  });

  after(function(done) {
    async.parallel([
      // Delete the bucket we used.
      function(next) {
        bucket.getFiles(function(err, files) {
          if (err) {
            next(err);
            return;
          }

          async.map(files, function(file, onComplete) {
            file.delete(onComplete);
          }, function(err) {
            if (err) {
              next(err);
              return;
            }

            bucket.delete(next);
          });
        });
      },

      // Delete the test dataset.
      function(next) {
        dataset.delete({ force: true }, next);
      }
    ], done);
  });

  it('should get a list of datasets', function(done) {
    bigquery.getDatasets(function(err, datasets) {
      assert(datasets.length > 0);
      assert(datasets[0] instanceof Dataset);
      done();
    });
  });

  it('should list datasets as a stream', function(done) {
    var datasetEmitted = false;

    bigquery.getDatasets()
      .on('error', done)
      .on('data', function(dataset) {
        datasetEmitted = dataset instanceof Dataset;
      })
      .on('end', function() {
        assert.strictEqual(datasetEmitted, true);
        done();
      });
  });

  it('should run a query job, then get results', function(done) {
    bigquery.startQuery(query, function(err, job) {
      assert.ifError(err);
      assert(job instanceof Job);

      job.getQueryResults(function(err, rows) {
        assert.ifError(err);
        assert.equal(rows.length, 100);
        assert.equal(typeof rows[0].url, 'string');
        done();
      });
    });
  });

  it('should get query results as a stream', function(done) {
    bigquery.startQuery(query, function(err, job) {
      assert.ifError(err);

      var rowsEmitted = [];

      job.getQueryResults()
        .on('error', done)
        .on('data', function(row) {
          rowsEmitted.push(row);
        })
        .on('end', function() {
          assert.equal(rowsEmitted.length, 100);
          assert.equal(typeof rowsEmitted[0].url, 'string');
          done();
        });
    });
  });

  it('should query as a stream', function(done) {
    var rowsEmitted = 0;

    bigquery.query(query)
      .on('data', function(row) {
        rowsEmitted++;
        assert.equal(typeof row.url, 'string');
      })
      .on('error', done)
      .on('end', function() {
        assert.equal(rowsEmitted, 100);
        done();
      });
  });

  it('should query', function(done) {
    bigquery.query(query, function(err, rows) {
      assert.ifError(err);
      assert.equal(rows.length, 100);
      done();
    });
  });

  it('should allow querying in series', function(done) {
    bigquery.query({
      query: query,
      maxResults: 10
    }, function(err, rows, nextQuery) {
      assert.ifError(err);
      assert.equal(rows.length, 10);
      assert.equal(typeof nextQuery.pageToken, 'string');
      done();
    });
  });

  it('should get a list of jobs', function(done) {
    bigquery.getJobs(function(err, jobs) {
      assert.ifError(err);
      assert(jobs[0] instanceof Job);
      done();
    });
  });

  it('should list jobs as a stream', function(done) {
    var jobEmitted = false;

    bigquery.getJobs()
      .on('error', done)
      .on('data', function(job) {
        jobEmitted = job instanceof Job;
      })
      .on('end', function() {
        assert.strictEqual(jobEmitted, true);
        done();
      });
  });

  describe('BigQuery/Dataset', function() {
    it('should set & get metadata', function(done) {
      dataset.setMetadata({
        description: 'yay description'
      }, function(err) {
        assert.ifError(err);

        dataset.getMetadata(function(err, metadata) {
          assert.ifError(err);
          assert.equal(metadata.description, 'yay description');
          done();
        });
      });
    });

    it('should get tables', function(done) {
      dataset.getTables(function(err, tables) {
        assert.ifError(err);
        assert(tables[0] instanceof Table);
        done();
      });
    });

    it('should get tables as a stream', function(done) {
      var tableEmitted = false;

      dataset.getTables()
        .on('error', done)
        .on('data', function(table) {
          tableEmitted = table instanceof Table;
        })
        .on('end', function() {
          assert.strictEqual(tableEmitted, true);
          done();
        });
    });
  });

  describe('BigQuery/Table', function() {
    var TEST_DATA_JSON_PATH = require.resolve('./data/kitten-test-data.json');

    it('should have created the correct schema', function() {
      assert.deepEqual(table.metadata.schema, {
        fields: [
          { name: 'id', type: 'INTEGER' },
          { name: 'breed', type: 'STRING' },
          { name: 'name', type: 'STRING' },
          { name: 'dob', type: 'TIMESTAMP' }
        ]
      });
    });

    it('should get the rows in a table', function(done) {
      table.getRows(function(err, rows) {
        assert.ifError(err);
        assert(Array.isArray(rows));
        done();
      });
    });

    it('should get the rows in a table via stream', function(done) {
      table.getRows()
        .on('error', done)
        .on('data', function() {})
        .on('end', done);
    });

    it('should insert rows via stream', function(done) {
      fs.createReadStream(TEST_DATA_JSON_PATH)
        .pipe(table.createWriteStream('json'))
        .on('error', done)
        .on('complete', function() {
          done();
        });
    });

    it('should set & get metadata', function(done) {
      table.setMetadata({
        description: 'catsandstuff'
      }, function(err) {
        assert.ifError(err);

        table.getMetadata(function(err, metadata) {
          assert.ifError(err);
          assert.equal(metadata.description, 'catsandstuff');
          done();
        });
      });
    });

    it('should import data from a file in your bucket', function(done) {
      bucket.upload(TEST_DATA_JSON_PATH, function(err, file) {
        assert.ifError(err);

        table.import(file, function(err, job) {
          assert.ifError(err);
          assert(job instanceof Job);
          done();
        });
      });
    });

    it('should export data to a file in your bucket', function(done) {
      table.export(bucket.file('kitten-test-data-backup.json'), done);
    });
  });
});
<commit_msg>bigquery: retain data types when querying<commit_after>/**
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

var assert = require('assert');
var async = require('async');
var Dataset = require('../lib/bigquery/dataset');
var Table = require('../lib/bigquery/table');
var env = require('./env');
var fs = require('fs');
var Job = require('../lib/bigquery/job');
var uuid = require('node-uuid');

var gcloud = require('../lib')(env);
var bigquery = gcloud.bigquery();
var storage = gcloud.storage();

describe('BigQuery', function() {
  var DATASET_ID = ('gcloud_test_dataset_temp' + uuid.v1()).replace(/-/g, '_');
  var dataset = bigquery.dataset(DATASET_ID);
  var TABLE_ID = 'myKittens';
  var table = dataset.table(TABLE_ID);
  var BUCKET_NAME = 'gcloud-test-bucket-temp-' + uuid.v1();
  var bucket = storage.bucket(BUCKET_NAME);

  var query = 'SELECT url FROM [publicdata:samples.github_nested] LIMIT 100';

  before(function(done) {
    async.series([
      // Create the test dataset.
      function(next) {
        dataset.create(next);
      },

      // Create the test table.
      function(next) {
        table.create({ schema: 'id:integer,breed,name,dob:timestamp' }, next);
      },

      // Create a Bucket.
      function(next) {
        bucket.create(next);
      }
    ], done);
  });

  after(function(done) {
    async.parallel([
      // Delete the bucket we used.
      function(next) {
        bucket.getFiles(function(err, files) {
          if (err) {
            next(err);
            return;
          }

          async.map(files, function(file, onComplete) {
            file.delete(onComplete);
          }, function(err) {
            if (err) {
              next(err);
              return;
            }

            bucket.delete(next);
          });
        });
      },

      // Delete the test dataset.
      function(next) {
        dataset.delete({ force: true }, next);
      }
    ], done);
  });

  it('should get a list of datasets', function(done) {
    bigquery.getDatasets(function(err, datasets) {
      assert(datasets.length > 0);
      assert(datasets[0] instanceof Dataset);
      done();
    });
  });

  it('should list datasets as a stream', function(done) {
    var datasetEmitted = false;

    bigquery.getDatasets()
      .on('error', done)
      .on('data', function(dataset) {
        datasetEmitted = dataset instanceof Dataset;
      })
      .on('end', function() {
        assert.strictEqual(datasetEmitted, true);
        done();
      });
  });

  it('should run a query job, then get results', function(done) {
    bigquery.startQuery(query, function(err, job) {
      assert.ifError(err);
      assert(job instanceof Job);

      job.getQueryResults(function(err, rows) {
        assert.ifError(err);
        assert.equal(rows.length, 100);
        assert.equal(typeof rows[0].url, 'string');
        done();
      });
    });
  });

  it('should get query results as a stream', function(done) {
    bigquery.startQuery(query, function(err, job) {
      assert.ifError(err);

      var rowsEmitted = [];

      job.getQueryResults()
        .on('error', done)
        .on('data', function(row) {
          rowsEmitted.push(row);
        })
        .on('end', function() {
          assert.equal(rowsEmitted.length, 100);
          assert.equal(typeof rowsEmitted[0].url, 'string');
          done();
        });
    });
  });

  it('should query as a stream', function(done) {
    var rowsEmitted = 0;

    bigquery.query(query)
      .on('data', function(row) {
        rowsEmitted++;
        assert.equal(typeof row.url, 'string');
      })
      .on('error', done)
      .on('end', function() {
        assert.equal(rowsEmitted, 100);
        done();
      });
  });

  it('should query', function(done) {
    bigquery.query(query, function(err, rows) {
      assert.ifError(err);
      assert.equal(rows.length, 100);
      done();
    });
  });

  it('should allow querying in series', function(done) {
    bigquery.query({
      query: query,
      maxResults: 10
    }, function(err, rows, nextQuery) {
      assert.ifError(err);
      assert.equal(rows.length, 10);
      assert.equal(typeof nextQuery.pageToken, 'string');
      done();
    });
  });

  it('should get a list of jobs', function(done) {
    bigquery.getJobs(function(err, jobs) {
      assert.ifError(err);
      assert(jobs[0] instanceof Job);
      done();
    });
  });

  it('should list jobs as a stream', function(done) {
    var jobEmitted = false;

    bigquery.getJobs()
      .on('error', done)
      .on('data', function(job) {
        jobEmitted = job instanceof Job;
      })
      .on('end', function() {
        assert.strictEqual(jobEmitted, true);
        done();
      });
  });

  describe('BigQuery/Dataset', function() {
    it('should set & get metadata', function(done) {
      dataset.setMetadata({
        description: 'yay description'
      }, function(err) {
        assert.ifError(err);

        dataset.getMetadata(function(err, metadata) {
          assert.ifError(err);
          assert.equal(metadata.description, 'yay description');
          done();
        });
      });
    });

    it('should get tables', function(done) {
      dataset.getTables(function(err, tables) {
        assert.ifError(err);
        assert(tables[0] instanceof Table);
        done();
      });
    });

    it('should get tables as a stream', function(done) {
      var tableEmitted = false;

      dataset.getTables()
        .on('error', done)
        .on('data', function(table) {
          tableEmitted = table instanceof Table;
        })
        .on('end', function() {
          assert.strictEqual(tableEmitted, true);
          done();
        });
    });
  });

  describe('BigQuery/Table', function() {
    var TEST_DATA_JSON_PATH = require.resolve('./data/kitten-test-data.json');

    it('should have created the correct schema', function() {
      assert.deepEqual(table.metadata.schema, {
        fields: [
          { name: 'id', type: 'INTEGER' },
          { name: 'breed', type: 'STRING' },
          { name: 'name', type: 'STRING' },
          { name: 'dob', type: 'TIMESTAMP' }
        ]
      });
    });

    it('should get the rows in a table', function(done) {
      table.getRows(function(err, rows) {
        assert.ifError(err);
        assert(Array.isArray(rows));
        done();
      });
    });

    it('should get the rows in a table via stream', function(done) {
      table.getRows()
        .on('error', done)
        .on('data', function() {})
        .on('end', done);
    });

    it('should insert rows via stream', function(done) {
      fs.createReadStream(TEST_DATA_JSON_PATH)
        .pipe(table.createWriteStream('json'))
        .on('error', done)
        .on('complete', function() {
          done();
        });
    });

    it('should set & get metadata', function(done) {
      table.setMetadata({
        description: 'catsandstuff'
      }, function(err) {
        assert.ifError(err);

        table.getMetadata(function(err, metadata) {
          assert.ifError(err);
          assert.equal(metadata.description, 'catsandstuff');
          done();
        });
      });
    });

    describe('importing & exporting', function() {
      var file = bucket.file('kitten-test-data-backup.json');

      before(function(done) {
        fs.createReadStream(TEST_DATA_JSON_PATH)
          .pipe(file.createWriteStream())
          .on('error', done)
          .on('finish', done);
      });

      after(function(done) {
        file.delete(done);
      });

      it('should import data from a file in your bucket', function(done) {
        table.import(file, function(err, job) {
          assert.ifError(err);
          assert(job instanceof Job);
          done();
        });
      });

      it('should convert values to their schema types', function(done) {
        var now = new Date();

        var data = {
          name: 'dave',
          breed: 'british shorthair',
          id: 99,
          dob: now.toJSON()
        };

        table.insert(data, function(err, insertErrors) {
          assert.ifError(err);

          if (insertErrors.length > 0) {
            done(insertErrors[0].errors[0]);
            return;
          }

          table.query('SELECT * FROM ' + TABLE_ID + ' WHERE id = ' + data.id)
            .on('error', done)
            .once('data', function(row) {
              assert.strictEqual(row.name, data.name);
              assert.strictEqual(row.breed, data.breed);
              assert.strictEqual(row.id, data.id);
              assert.deepEqual(row.dob, now);
              done();
            });
        });
      });

      it('should export data to a file in your bucket', function(done) {
        table.export(bucket.file('kitten-test-data-backup.json'), done);
      });
    });
  });
});
<|endoftext|>