<commit_before>/*
 * Url module. Required for resolving relative paths.
 */

var url = require("url");

/*
 * Regexp from origin Arc90 Readability.
 */

var regexps = {
  unlikelyCandidatesRe: /combx|pager|comment|disqus|foot|header|menu|meta|nav|rss|shoutbox|sidebar|sponsor|share|bookmark|social|advert|leaderboard|instapaper_ignore|entry-unrelated/i,
  okMaybeItsACandidateRe: /and|article|body|column|main/i,
  positiveRe: /article|body|content|entry|hentry|page|pagination|post|text/i,
  negativeRe: /combx|comment|captcha|contact|foot|footer|footnote|link|media|meta|promo|related|scroll|shoutbox|sponsor|utility|tags|widget/i,
  divToPElementsRe: /<(a|blockquote|dl|div|img|ol|p|pre|table|ul)/i,
  replaceBrsRe: /(
]*>[ \n\r\t]*){2,}/gi,
  replaceFontsRe: /<(\/?)font[^>]*>/gi,
  trimRe: /^\s+|\s+$/g,
  normalizeRe: /\s{2,}/g,
  killBreaksRe: /(
(\s| ?)*){1,}/g,
  videoRe: /http:\/\/(www\.)?(youtube|vimeo|youku|tudou|56|yinyuetai)\.com/i
};

/**
 * Node Types and their classification
 **/

var nodeTypes = {
  'mostPositive': ['div'],
  'positive': ['pre', 'td', 'blockquote'],
  'negative': ['address', 'ol', 'ul', 'dl', 'dd', 'dt', 'li'],
  'mostNegative': ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'th']
}

/**
 * We're getting only the readable content + images, no other nodes are needed.
 **/

var trashNodes = 'meta,iframe,noscript,style,aside,object,form,script';

/**
 * Select the TopCandidate from all possible candidates
 **/

function getArticle(candidates, $, options) {
  var topCandidate = null;

  candidates.forEach(function(elem) {
    var linkDensity = getLinkDensity(elem, $);
    var score = elem.data('readabilityScore');
    // actually say, we can't score node by children length
    // e.g.: sometimes, the comments of an article have lots of children,
    // such as: like, dislike, follow, print, star+/-...
    // but most of them worthless.
    // var siblings = elem.children().length;

    elem.data('readabilityScore', /*Math.max(2, siblings) * */ score * (1 - linkDensity));
    if (!topCandidate || elem.data('readabilityScore') > topCandidate.data('readabilityScore')) {
      topCandidate = elem;
    }
  });
  /**
   * If we still have no top candidate, just use the body as a last resort.
   * We also have to copy the body node so it is something we can modify.
   **/
  if (topCandidate === null) {
    // With no top candidate, bail out if no body tag exists as last resort.
    if (!$('body')) return new Error("No body tag was found.");
    return $('body');
  }
  // Perhaps the topCandidate is the parent?
  var parent;
  if (!(parent = topCandidate.parent()) || parent.length == 0 || topCandidate.children().length > 5) {
    return filterCandidates(topCandidate, topCandidate.children(), $);
  } else {
    return filterCandidates(topCandidate, parent.children(), $);
  }
}

/**
 * Filter TopCandidate Siblings (Children) based on their Link Density, and readabilityScore
 * Append the nodes to articleContent
 **/

function filterCandidates(topCandidate, siblings, $) {
  var articleContent = $("

");
  var siblingScoreThreshold = Math.max(10, topCandidate.data('readabilityScore') * 0.2);
  siblings.each(function(index, elem) {
    var sibling = $(this);
    var append = false;
    var type = sibling.get(0).name;
    var score = sibling.data('readabilityScore');
    var children = siblings.contents().length;
    if (sibling === topCandidate || score > siblingScoreThreshold) {
      append = true;
    }
    if (children > 0) {
      siblings.contents().each(function(index, elem) {
        if (elem.name == "img") append = true;
      });
    }

    if (!append && type == 'p') {
      var linkDensity = getLinkDensity(sibling, $);
      var len = sibling.text().length;
      if (len < 3) return;

      if (len > 80 && linkDensity < 0.25) {
        append = true;
      } else if (len < 80 && linkDensity == 0 && sibling.text().replace(regexps.trimRe, "")) {
        append = true;
      }
    }
    if (append) {
      articleContent.append(sibling);
    }
  });
  return articleContent;
}

/**
 * Traverse all Nodes and remove unlikely Candidates.
 **/

function getCandidates($, base, options) {

  $(trashNodes).remove();
  // Candidates Array
  var candidates = [];

  // Iterate over all Nodes in body
  $('*', 'body').each(function(index, element) {
    var node = $(this);

    // If node is null, return, otherwise Illegal Access Error
    if (!node || node.length == 0) return;
    var nodeType = node.get(0).name;

    // Remove Unlikely Candidates
    var classAndID = (node.attr('class') || "") + (node.attr('id') || "");
    if (classAndID.search(regexps.unlikelyCandidatesRe) !== -1 && classAndID.search(regexps.okMaybeItsACandidateRe) == -1) {
      node.remove();
      return;
    }

    // Remove Elements that have no children and have no content
    if (nodeType == "div" && node.children().length < 1 && node.text().trim().length < 1) {
      node.remove();
      return;
    }
    // Remove Style
    node.removeAttr('style');

    // turn all divs that don't have children block level elements into p's
    if (nodeType === "div" && options.considerDIVs) {
      if (node.html().search(regexps.divToPElementsRe) === -1) {
        node.replaceWith('
' + node.html() + '
');
      } else {
        node.contents().each(function(index, element){
          var child = $(this), childEntity;
          if(!child || !(childEntity = child.get(0))){
            return;
          }
          if(childEntity.type == 'text' && childEntity.data && childEntity.data.replace(regexps.trimRe, '').length > 0){
            child.replaceWith('
' + childEntity.data + '
');
          }
        });
      }
    }

    // score paragraphs.
    if (nodeType == "p") {
      calculateNodeScore(node, candidates);
      return;
    }

    // Resolve URLs
    if (base) {
      if (nodeType == "img" && typeof node.attr('href') != "undefined") {
        node.attr('src', url.resolve(base, node.attr('src')));
      }
      if (nodeType == "a" && typeof node.attr('href') != "undefined") {
        node.attr('href', url.resolve(base, node.attr('href')));
      }
    }

    // Clean the headers
    if (["h1", "h2", "h3", "h4", "h5", "h6"].indexOf(nodeType) !== -1) {
      var weight = getClassWeight(node, $);
      var density = getLinkDensity(node, $);
      if (weight < 0 || density > 0.3) {
        node.remove();
      }
    }

  });
  // calculate scores of `P`s that were turned from DIV by us.
  $('p.node-read-div2p', 'body').each(function(){
    calculateNodeScore($(this), candidates);
  });
  return candidates;
}

/**
 * save score datas to nodes need score.
 * @param node
 * @param contentScore
 * @param candidates
 */
function scoreCandidate(node, contentScore, candidates) {
  var score;
  if (typeof node.data('readabilityScore') == "undefined") {
    score = initializeNode(node);
    candidates.push(node);
  } else {
    score = node.data('readabilityScore') || 0;
  }
  node.data('readabilityScore', score + contentScore)
}

/**
 * calculate score of specified node.
 * @param node
 * @param candidates
 */
function calculateNodeScore(node, candidates){
  var txt = node.text();
  // Ignore too small nodes
  if (txt.length < 25) return;

  var contentScore = 0;

  // Add a point for the paragraph itself as a base.
  ++contentScore;

  // Add points for any commas within this paragraph
  // support Chinese commas.
  var commas = txt.match(/[,，.。;；?？、]/g);
  if (commas && commas.length) {
    contentScore += commas.length;
  }

  // For every 100 characters in this paragraph, add another point. Up to 3 points.
  contentScore += Math.min(Math.floor(txt.length / 100), 3);

  // Initialize Parent and Grandparent
  // First initialize the parent node with contentScore / 1, then grandParentNode with contentScore / 2
  var parent = node.parent();

  if (parent && parent.length > 0) {
    scoreCandidate(parent, contentScore, candidates);
    var grandParent = parent.parent();
    if (grandParent && grandParent.length > 0) {
      scoreCandidate(grandParent, contentScore / 2, candidates);
    }
  }
}

/**
 * Check the type of node, and get its Weight
 **/

function initializeNode(node) {
  if (!node || node.length == 0) return 0;
  var tag = node.get(0).name;
  if (nodeTypes['mostPositive'].indexOf(tag)) return 5 + getClassWeight(node);
  if (nodeTypes['positive'].indexOf(tag)) return 3 + getClassWeight(node);
  if (nodeTypes['negative'].indexOf(tag)) return -3 + getClassWeight(node);
  if (nodeTypes['mostNegative'].indexOf(tag)) return -5 + getClassWeight(node);
}

/**
 * Node Weight is calculated based on className and ID of the node.
 **/

function getClassWeight(node) {
  if (node == null || node.length == 0) return 0;
  var classAndID = (node.attr('class') || "") + (node.attr('id') || "");
  var weight = 0;

  if (node.get(0).name == "article") weight += 25;
  if (classAndID.search(regexps.negativeRe) !== -1) weight -= 25;
  if (classAndID.search(regexps.positiveRe) !== -1) weight += 25;

  return weight;
}

/**
 * Get Link density of this node.
 * Total length of link text in this node divided by the total text of the node.
 * Relative links are not included.
 **/

function getLinkDensity(node, $) {
  var links = node.find('a');
  var textLength = node.text().length;
  var linkLength = 0;
  links.each(function(index, elem) {
    var href = $(this).attr('href');
    if (!href || (href.length > 0 && href[0] === '#')) return;
    linkLength += $(this).text().length;
  });
  return (linkLength / textLength) || 0;
}

/**
 * Main method
 * If the first run does not succeed, try the body element;
 **/

module.exports.extract = function($, base, options) {
  var candidates = getCandidates($, base, options);
  article = getArticle(candidates, $, options);
  if (article.length < 1) {
    article = getArticle([$('body')], $)
  }
  return article;
}<commit_msg>negativeRe: tip, dialog<commit_after>/*
 * Url module. Required for resolving relative paths.
 */

var url = require("url");

/*
 * Regexp from origin Arc90 Readability.
 */

var regexps = {
  unlikelyCandidatesRe: /combx|pager|comment|disqus|foot|header|menu|meta|nav|rss|shoutbox|sidebar|sponsor|share|bookmark|social|advert|leaderboard|instapaper_ignore|entry-unrelated/i,
  okMaybeItsACandidateRe: /and|article|body|column|main/i,
  positiveRe: /article|body|content|entry|hentry|page|pagination|post|text/i,
  negativeRe: /combx|comment|captcha|contact|foot|footer|footnote|link|media|meta|promo|related|scroll|shoutbox|sponsor|utility|tags|widget|tip|dialog/i,
  divToPElementsRe: /<(a|blockquote|dl|div|img|ol|p|pre|table|ul)/i,
  replaceBrsRe: /(
]*>[ \n\r\t]*){2,}/gi,
  replaceFontsRe: /<(\/?)font[^>]*>/gi,
  trimRe: /^\s+|\s+$/g,
  normalizeRe: /\s{2,}/g,
  killBreaksRe: /(
(\s| ?)*){1,}/g,
  videoRe: /http:\/\/(www\.)?(youtube|vimeo|youku|tudou|56|yinyuetai)\.com/i
};

/**
 * Node Types and their classification
 **/

var nodeTypes = {
  'mostPositive': ['div'],
  'positive': ['pre', 'td', 'blockquote'],
  'negative': ['address', 'ol', 'ul', 'dl', 'dd', 'dt', 'li'],
  'mostNegative': ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'th']
}

/**
 * We're getting only the readable content + images, no other nodes are needed.
 **/

var trashNodes = 'meta,iframe,noscript,style,aside,object,form,script';

/**
 * Select the TopCandidate from all possible candidates
 **/

function getArticle(candidates, $, options) {
  var topCandidate = null;

  candidates.forEach(function(elem) {
    var linkDensity = getLinkDensity(elem, $);
    var score = elem.data('readabilityScore');
    // actually say, we can't score node by children length
    // e.g.: sometimes, the comments of an article have lots of children,
    // such as: like, dislike, follow, print, star+/-...
    // but most of them worthless.
    // var siblings = elem.children().length;

    elem.data('readabilityScore', /*Math.max(2, siblings) * */ score * (1 - linkDensity));
    if (!topCandidate || elem.data('readabilityScore') > topCandidate.data('readabilityScore')) {
      topCandidate = elem;
    }
  });
  /**
   * If we still have no top candidate, just use the body as a last resort.
   * We also have to copy the body node so it is something we can modify.
   **/
  if (topCandidate === null) {
    // With no top candidate, bail out if no body tag exists as last resort.
    if (!$('body')) return new Error("No body tag was found.");
    return $('body');
  }
  // Perhaps the topCandidate is the parent?
  var parent;
  if (!(parent = topCandidate.parent()) || parent.length == 0 || topCandidate.children().length > 5) {
    return filterCandidates(topCandidate, topCandidate.children(), $);
  } else {
    return filterCandidates(topCandidate, parent.children(), $);
  }
}

/**
 * Filter TopCandidate Siblings (Children) based on their Link Density, and readabilityScore
 * Append the nodes to articleContent
 **/

function filterCandidates(topCandidate, siblings, $) {
  var articleContent = $("

");
  var siblingScoreThreshold = Math.max(10, topCandidate.data('readabilityScore') * 0.2);
  siblings.each(function(index, elem) {
    var sibling = $(this);
    var append = false;
    var type = sibling.get(0).name;
    var score = sibling.data('readabilityScore');
    var children = siblings.contents().length;
    if (sibling === topCandidate || score > siblingScoreThreshold) {
      append = true;
    }
    if (children > 0) {
      siblings.contents().each(function(index, elem) {
        if (elem.name == "img") append = true;
      });
    }

    if (!append && type == 'p') {
      var linkDensity = getLinkDensity(sibling, $);
      var len = sibling.text().length;
      if (len < 3) return;

      if (len > 80 && linkDensity < 0.25) {
        append = true;
      } else if (len < 80 && linkDensity == 0 && sibling.text().replace(regexps.trimRe, "")) {
        append = true;
      }
    }
    if (append) {
      articleContent.append(sibling);
    }
  });
  return articleContent;
}

/**
 * Traverse all Nodes and remove unlikely Candidates.
 **/

function getCandidates($, base, options) {

  $(trashNodes).remove();
  // Candidates Array
  var candidates = [];

  // Iterate over all Nodes in body
  $('*', 'body').each(function(index, element) {
    var node = $(this);

    // If node is null, return, otherwise Illegal Access Error
    if (!node || node.length == 0) return;
    var nodeType = node.get(0).name;

    // Remove Unlikely Candidates
    var classAndID = (node.attr('class') || "") + (node.attr('id') || "");
    if (classAndID.search(regexps.unlikelyCandidatesRe) !== -1 && classAndID.search(regexps.okMaybeItsACandidateRe) == -1) {
      node.remove();
      return;
    }

    // Remove Elements that have no children and have no content
    if (nodeType == "div" && node.children().length < 1 && node.text().trim().length < 1) {
      node.remove();
      return;
    }
    // Remove Style
    node.removeAttr('style');

    // turn all divs that don't have children block level elements into p's
    if (nodeType === "div" && options.considerDIVs) {
      if (node.html().search(regexps.divToPElementsRe) === -1) {
        node.replaceWith('
' + node.html() + '
');
      } else {
        node.contents().each(function(index, element){
          var child = $(this), childEntity;
          if(!child || !(childEntity = child.get(0))){
            return;
          }
          if(childEntity.type == 'text' && childEntity.data && childEntity.data.replace(regexps.trimRe, '').length > 0){
            child.replaceWith('
' + childEntity.data + '
');
          }
        });
      }
    }

    // score paragraphs.
    if (nodeType == "p") {
      calculateNodeScore(node, candidates);
      return;
    }

    // Resolve URLs
    if (base) {
      if (nodeType == "img" && typeof node.attr('href') != "undefined") {
        node.attr('src', url.resolve(base, node.attr('src')));
      }
      if (nodeType == "a" && typeof node.attr('href') != "undefined") {
        node.attr('href', url.resolve(base, node.attr('href')));
      }
    }

    // Clean the headers
    if (["h1", "h2", "h3", "h4", "h5", "h6"].indexOf(nodeType) !== -1) {
      var weight = getClassWeight(node, $);
      var density = getLinkDensity(node, $);
      if (weight < 0 || density > 0.3) {
        node.remove();
      }
    }

  });
  // calculate scores of `P`s that were turned from DIV by us.
  $('p.node-read-div2p', 'body').each(function(){
    calculateNodeScore($(this), candidates);
  });
  return candidates;
}

/**
 * save score datas to nodes need score.
 * @param node
 * @param contentScore
 * @param candidates
 */
function scoreCandidate(node, contentScore, candidates) {
  var score;
  if (typeof node.data('readabilityScore') == "undefined") {
    score = initializeNode(node);
    candidates.push(node);
  } else {
    score = node.data('readabilityScore') || 0;
  }
  node.data('readabilityScore', score + contentScore)
}

/**
 * calculate score of specified node.
 * @param node
 * @param candidates
 */
function calculateNodeScore(node, candidates){
  var txt = node.text();
  // Ignore too small nodes
  if (txt.length < 25) return;

  var contentScore = 0;

  // Add a point for the paragraph itself as a base.
  ++contentScore;

  // Add points for any commas within this paragraph
  // support Chinese commas.
  var commas = txt.match(/[,，.。;；?？、]/g);
  if (commas && commas.length) {
    contentScore += commas.length;
  }

  // For every 100 characters in this paragraph, add another point. Up to 3 points.
  contentScore += Math.min(Math.floor(txt.length / 100), 3);

  // Initialize Parent and Grandparent
  // First initialize the parent node with contentScore / 1, then grandParentNode with contentScore / 2
  var parent = node.parent();

  if (parent && parent.length > 0) {
    scoreCandidate(parent, contentScore, candidates);
    var grandParent = parent.parent();
    if (grandParent && grandParent.length > 0) {
      scoreCandidate(grandParent, contentScore / 2, candidates);
    }
  }
}

/**
 * Check the type of node, and get its Weight
 **/

function initializeNode(node) {
  if (!node || node.length == 0) return 0;
  var tag = node.get(0).name;
  if (nodeTypes['mostPositive'].indexOf(tag)) return 5 + getClassWeight(node);
  if (nodeTypes['positive'].indexOf(tag)) return 3 + getClassWeight(node);
  if (nodeTypes['negative'].indexOf(tag)) return -3 + getClassWeight(node);
  if (nodeTypes['mostNegative'].indexOf(tag)) return -5 + getClassWeight(node);
}

/**
 * Node Weight is calculated based on className and ID of the node.
 **/

function getClassWeight(node) {
  if (node == null || node.length == 0) return 0;
  var classAndID = (node.attr('class') || "") + (node.attr('id') || "");
  var weight = 0;

  if (node.get(0).name == "article") weight += 25;
  if (classAndID.search(regexps.negativeRe) !== -1) weight -= 25;
  if (classAndID.search(regexps.positiveRe) !== -1) weight += 25;

  return weight;
}

/**
 * Get Link density of this node.
 * Total length of link text in this node divided by the total text of the node.
 * Relative links are not included.
 **/

function getLinkDensity(node, $) {
  var links = node.find('a');
  var textLength = node.text().length;
  var linkLength = 0;
  links.each(function(index, elem) {
    var href = $(this).attr('href');
    if (!href || (href.length > 0 && href[0] === '#')) return;
    linkLength += $(this).text().length;
  });
  return (linkLength / textLength) || 0;
}

/**
 * Main method
 * If the first run does not succeed, try the body element;
 **/

module.exports.extract = function($, base, options) {
  var candidates = getCandidates($, base, options);
  article = getArticle(candidates, $, options);
  if (article.length < 1) {
    article = getArticle([$('body')], $)
  }
  return article;
}<|endoftext|>


<commit_before>// var assert = require('chai').assert;
// // var should = chai.should();
var Clip = require('../kindle-my-clippings');

// var clip = new Clip();

// describe('Array', function(){

//   describe('#indexOf()', function(){
//     it('should return -1 when the value is not present', function(){
//       assert.equal(-1, [1,2,3].indexOf(5));
//       assert.equal(-1, [1,2,3].indexOf(0));
//     });
//   });

// });

// Require chai.js expect module for assertions
var expect = require('chai').expect;

// Create a new test suite for our Bank Account
suite("Kindle clipping Tests", function() {

    var clip;

    setup(function () {
      clip = new Clip();
    });

    // Define a pending test
    test("should exist", function() {
        expect(clip).to.be.ok;
    });

    test('file reading', function(){
      clip.getFileContent(__dirname + '/' + 'My Clippings.txt', function (data) {
        expect(data).to.be.a('string');
      });
    });

    test('split file contents', function() {
      clip.getFileContent(__dirname + '/' + 'My Clippings.txt', function (data) {
        var output = clip.splitFileIntoRecords(data);
        expect(data).to.be.instanceof(Array);
        // expect(clip).to.be.ok;
      });
    });

});<commit_msg>async test basic<commit_after>// var assert = require('chai').assert;
// // var should = chai.should();
var Clip = require('../kindle-my-clippings');

// var clip = new Clip();

// describe('Array', function(){

//   describe('#indexOf()', function(){
//     it('should return -1 when the value is not present', function(){
//       assert.equal(-1, [1,2,3].indexOf(5));
//       assert.equal(-1, [1,2,3].indexOf(0));
//     });
//   });

// });

// Require chai.js expect module for assertions
var expect = require('chai').expect;

// Create a new test suite for our Bank Account
suite("Kindle clipping Tests", function() {

    var clip;
    var clipData;

    setup(function () {
      clip = new Clip();
    });

    // Define a pending test
    test("should exist", function() {
        expect(clip).to.be.ok;
    });

    test('file reading', function(done){
      clip.getFileContent(__dirname + '/' + 'My Clippings.txt', function (data) {
        clipData = data;
        expect(data).to.be.a('string');
        done();
      });
    });

    test('if split clip data is an array', function() {
      var output = clip.splitFileIntoRecords(clipData);
      expect(output).to.be.instanceof(Array);
    });

});<|endoftext|>


<commit_before>'use strict';

var _ = require('underscore');
var Inherits = require('util').inherits;
var Url = require('url');

function ElsinoreError(msg){
    this.name = 'ElsinoreError';
    this.message = msg;
    this.cause = msg;

    if (message instanceof Error) {
        this.message = message.message;
        this.stack = message.stack;
    }
    else if (Error.captureStackTrace) {
        Error.captureStackTrace(this, this.constructor);
    }

    return error;
}

Inherits(ElsinoreError, Error);

function mergeRecursive(obj1, obj2) {
    for (var p in obj2) {
        if( obj2.hasOwnProperty(p) ){
            if( obj1 === undefined )
                obj1 = {};
            obj1[p] = (typeof obj2[p] === 'object') ? mergeRecursive(obj1[p], obj2[p]) : obj2[p];
        }
    }
    return obj1;
}

//
// Returns an array broken into set lengths
//
function chunk( array, chunkLength ){
    var i,j,temparray;
    var result = [];
    for (i=0,j=array.length; i<j; i+=chunkLength) {
        result.push( array.slice(i,i+chunkLength) );
    }

    return result;
};

// taken from underscore-contrib/underscore.function.predicates
// cannot include directly in node

// A numeric is a variable that contains a numeric value, regardless its type
// It can be a String containing a numeric value, exponential notation, or a Number object
// See here for more discussion: http://stackoverflow.com/questions/18082/validate-numbers-in-javascript-isnumeric/1830844#1830844
function isNumeric(n) {
    return !isNaN(parseFloat(n)) && isFinite(n);
};

// An integer contains an optional minus sign to begin and only the digits 0-9
// Objects that can be parsed that way are also considered ints, e.g. "123"
// Floats that are mathematically equal to integers are considered integers, e.g. 1.0
// See here for more discussion: http://stackoverflow.com/questions/1019515/javascript-test-for-an-integer
function isInteger(i) {
    return !isNaN(parseFloat(i)) && isFinite(i) && i % 1 === 0;
};

/**
 * Calculate a 32 bit FNV-1a hash
 * Found here: https://gist.github.com/vaiorabbit/5657561
 * Ref.: http://isthe.com/chongo/tech/comp/fnv/
 *
 * @param {string} str the input value
 * @param {boolean} [asString=false] set to true to return the hash value as
 *     8-digit hex string instead of an integer
 * @param {integer} [seed] optionally pass the hash of the previous chunk
 * @returns {integer | string}
 */
function hashFnv32a(str, asString, seed) {
    /*jshint bitwise:false */
    var i, l,
        hval = (seed === undefined) ? 0x811c9dc5 : seed;

    for (i = 0, l = str.length; i < l; i++) {
        hval ^= str.charCodeAt(i);
        hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
    }
    if( asString ){
        // Convert to 8 digit hex string
        return ("0000000" + (hval >>> 0).toString(16)).substr(-8);
    }
    return hval >>> 0;
}

function normalizeUri(uri){
    var result;
    if( !uri )
        return null;
    result = Url.parse( uri );
    return result.href;
}

function parseUri( uri ){
    var result;
    // result = require('uri-js').parse( uri );
    result = Url.parse( uri );
    if( result.hash ){
        result.fragment = result.hash.substring(1);
        result.baseUri = result.href.slice(0, result.href.length - result.hash.length);
    }

    return result;
}

function resolveUri( from, to ){
    // log.debug( JSON.stringify( from ) + ', ' + JSON.stringify( to ) );
    return Url.resolve( from, to );
}

function deepClone( obj ){
    return JSON.parse(JSON.stringify(obj));
}

// from: http://www.tuanhuynh.com/blog/2014/unpacking-underscore-clone-and-extend/
function deepExtend( out ){
    var i, len;
    var obj;
    var key;

    out || (out={});

    for (i = 1, len = arguments.length; i < len; i++) {
        obj = arguments[i];

        if (!obj){
            continue;
        }

        for (key in obj) {
            if( !obj.hasOwnProperty(key) ){
                continue;
            }

            if( _.isArray(obj[key] ) ){
                out[key] = deepExtend( out[key] || [], obj[key] );
            }
            else if (typeof obj[key] === 'object'){
                out[key] = deepExtend(out[key], obj[key]);
            }
            else {
                out[key] = obj[key];
            }
        }
    }
    return out;
}

module.exports = {
    ElsinoreError: ElsinoreError,
    mergeRecursive: mergeRecursive,
    chunk: chunk,
    isNumeric: isNumeric,
    isInteger: isInteger,
    hash: hashFnv32a,
    normalizeUri: normalizeUri,
    parseUri: parseUri,
    resolveUri: resolveUri,
    deepClone: deepClone,
    deepExtend: deepExtend
};
<commit_msg>reduceIterator<commit_after>'use strict';

var _ = require('underscore');
var Inherits = require('util').inherits;
var Promise = require('bluebird');
// var Url = require('url');
var Url = require("fast-url-parser");

function ElsinoreError(msg){
    this.name = 'ElsinoreError';
    this.message = msg;
    this.cause = msg;

    if (message instanceof Error) {
        this.message = message.message;
        this.stack = message.stack;
    }
    else if (Error.captureStackTrace) {
        Error.captureStackTrace(this, this.constructor);
    }

    return error;
}

Inherits(ElsinoreError, Error);

function mergeRecursive(obj1, obj2) {
    for (var p in obj2) {
        if( obj2.hasOwnProperty(p) ){
            if( obj1 === undefined )
                obj1 = {};
            obj1[p] = (typeof obj2[p] === 'object') ? mergeRecursive(obj1[p], obj2[p]) : obj2[p];
        }
    }
    return obj1;
}

//
// Returns an array broken into set lengths
//
function chunk( array, chunkLength ){
    var i,j,temparray;
    var result = [];
    for (i=0,j=array.length; i<j; i+=chunkLength) {
        result.push( array.slice(i,i+chunkLength) );
    }

    return result;
};

// taken from underscore-contrib/underscore.function.predicates
// cannot include directly in node

// A numeric is a variable that contains a numeric value, regardless its type
// It can be a String containing a numeric value, exponential notation, or a Number object
// See here for more discussion: http://stackoverflow.com/questions/18082/validate-numbers-in-javascript-isnumeric/1830844#1830844
function isNumeric(n) {
    return !isNaN(parseFloat(n)) && isFinite(n);
};

// An integer contains an optional minus sign to begin and only the digits 0-9
// Objects that can be parsed that way are also considered ints, e.g. "123"
// Floats that are mathematically equal to integers are considered integers, e.g. 1.0
// See here for more discussion: http://stackoverflow.com/questions/1019515/javascript-test-for-an-integer
function isInteger(i) {
    return !isNaN(parseFloat(i)) && isFinite(i) && i % 1 === 0;
};

/**
 * Calculate a 32 bit FNV-1a hash
 * Found here: https://gist.github.com/vaiorabbit/5657561
 * Ref.: http://isthe.com/chongo/tech/comp/fnv/
 *
 * @param {string} str the input value
 * @param {boolean} [asString=false] set to true to return the hash value as
 *     8-digit hex string instead of an integer
 * @param {integer} [seed] optionally pass the hash of the previous chunk
 * @returns {integer | string}
 */
function hashFnv32a(str, asString, seed) {
    /*jshint bitwise:false */
    var i, l,
        hval = (seed === undefined) ? 0x811c9dc5 : seed;

    for (i = 0, l = str.length; i < l; i++) {
        hval ^= str.charCodeAt(i);
        hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
    }
    if( asString ){
        // Convert to 8 digit hex string
        return ("0000000" + (hval >>> 0).toString(16)).substr(-8);
    }
    return hval >>> 0;
}

function normalizeUri(uri){
    var result;
    if( !uri )
        return null;
    result = Url.parse( uri );
    return result.href;
}

function parseUri( uri ){
    var result;
    // result = require('uri-js').parse( uri );
    result = Url.parse( uri );
    if( result.hash ){
        result.fragment = result.hash.substring(1);
        result.baseUri = result.href.slice(0, result.href.length - result.hash.length);
    }

    return result;
}

function resolveUri( from, to ){
    // log.debug( JSON.stringify( from ) + ', ' + JSON.stringify( to ) );
    return Url.resolve( from, to );
}

function deepClone( obj ){
    return JSON.parse(JSON.stringify(obj));
}

// from: http://www.tuanhuynh.com/blog/2014/unpacking-underscore-clone-and-extend/
function deepExtend( out ){
    var i, len;
    var obj;
    var key;

    out || (out={});

    for (i = 1, len = arguments.length; i < len; i++) {
        obj = arguments[i];

        if (!obj){
            continue;
        }

        for (key in obj) {
            if( !obj.hasOwnProperty(key) ){
                continue;
            }

            if( _.isArray(obj[key] ) ){
                out[key] = deepExtend( out[key] || [], obj[key] );
            }
            else if (typeof obj[key] === 'object'){
                out[key] = deepExtend(out[key], obj[key]);
            }
            else {
                out[key] = obj[key];
            }
        }
    }
    return out;
}

/**
*   calls a passed iterator until it is exhausted.
*   The iterator function should implement a function next()
*   which returns an object containing the value, or if
*   no more values are available, it should return a Promise.reject
*/
function reduceIterator( iterator, eachFn, memo ){
    return new Promise( function( resolve, reject){
        function iterateOk(item){
            return Promise.resolve()
                .then( function(){
                    return eachFn(memo,item);
                })
                .then( iterate );
        };

        function iterateFail(){
            return resolve( memo );
        }

        function iterate(){
            return iterator.next().then( iterateOk, iterateFail );
        };

        iterate();
    });
}

module.exports = {
    ElsinoreError: ElsinoreError,
    mergeRecursive: mergeRecursive,
    chunk: chunk,
    isNumeric: isNumeric,
    isInteger: isInteger,
    hash: hashFnv32a,
    normalizeUri: normalizeUri,
    parseUri: parseUri,
    resolveUri: resolveUri,
    deepClone: deepClone,
    deepExtend: deepExtend,
    reduceIterator: reduceIterator
};
<|endoftext|>


<commit_before>var assert = require('assert');
var samsungTv = require('../lib/app');

var tv = new samsungTv({port: '/dev/tty.usbserial'});
describe('tv', function() {
  describe('#calculateChecksum([0x08, 0x22, 0x00, 0x00, 0x00, 0x00])', function() {
    it('should return 2a', function() {
      assert.equal('2a', tv.calculateChecksum([0x08, 0x22, 0x00, 0x00, 0x00, 0x00]));
    });
  });
});<commit_msg>added test for calculateChecksum()<commit_after>var assert = require('assert');

var samsungTv = require('../lib/app');
var tv = new samsungTv({port: '/dev/tty.usbserial'});

describe('tv', function() {
  describe('#calculateChecksum([0x08, 0x22, 0x00, 0x00, 0x00, 0x00])', function() {
    it('should return 2a', function() {
      assert.equal('2a', tv.calculateChecksum([0x08, 0x22, 0x00, 0x00, 0x00, 0x00]));
    });
  });
});

describe('tv', function() {
  describe('#calculateChecksum([0x11, 0xFF, 0x01, 0x01])', function() {
    it('should return 12', function() {
      assert.equal('12', tv.calculateChecksum([0x11, 0xFF, 0x01, 0x01]));
    });
  });
});<|endoftext|>


<commit_before>"use strict";
var game = new Phaser.Game(800, 600, Phaser.AUTO, '', { preload: preload, create: create, update: update });
var player, yourKnife, otherPlayers, otherKnives, cursors, walls;
//Other players' knives might not need to be simulated if the wind is synced well enough. Other players still ought to be for hit detection purposes -- both movement and knife-stabbing.

function preload() {
    game.load.image('skyBackground', 'assets/sky.png');
    game.load.image('playerSprite', 'assets/player.png');
    game.load.image('wallSprite', 'assets/wall.png');
}

function create() {

    game.physics.startSystem(Phaser.Physics.ARCADE);

	//Adding things to world
	//Stuff is rendered in the order it's added (back to front)
	//Desired order: Background < Wind (to be added later) < Players < Walls

    game.add.sprite(0, 0, 'skyBackground');

	player = game.add.sprite(game.world.width/2, game.world.height/2, 'playerSprite');
	game.physics.enable(player);
	player.body.gravity.y = 0;
	player.body.collideWorldBounds = true;

	otherPlayers = game.add.group();
	otherPlayers.enableBody = true;
	var newPlayer = otherPlayers.create(3*game.world.width/4, game.world.height/3, 'playerSprite');

	walls = game.add.group();
	walls.enableBody = true;

	//Wallsprite is 50px*50px, scale is multiplicative
	var newWall = walls.create(game.world.width/4-25, game.world.height/4-25, 'wallSprite');
	newWall.scale.setTo(2, 1);
	newWall.body.immovable = true;

	newWall = walls.create(2*game.world.width/3, 3*game.world.height/4-75, 'wallSprite');
	newWall.scale.setTo(1, 3);
	newWall.body.immovable = true;

	//Todo in the future: Change arrow keys to WASD
    cursors = game.input.keyboard.createCursorKeys();
	game.input.keyboard.addKeyCapture([Phaser.Keyboard.SPACEBAR]);
}

function update() {
	game.physics.arcade.collide(player, walls);
	game.physics.arcade.overlap(player, walls, destroySecondThing, null, this);
	game.physics.arcade.overlap(yourKnife, walls, destroyFirstThing, null, this);
	game.physics.arcade.overlap(yourKnife, otherPlayers, destroyBothThings, null, this);

	player.body.velocity.x = 0;
	player.body.velocity.y = 0;
	var moveSpeed = 300;

	if(cursors.left.isDown)
	{
		player.body.velocity.x -= moveSpeed;
	}
	if(cursors.right.isDown)
	{
		player.body.velocity.x += moveSpeed;
	}
	if(cursors.up.isDown)
	{
		player.body.velocity.y -= moveSpeed;
	}
	if(cursors.down.isDown)
	{
		player.body.velocity.y += moveSpeed;
	}

	//Enforces one-knife-at-once limit, re-enables throw as soon as existing knife dies. Todo: Add time delay like in unity game
	if(yourKnife == null)
	{
		if(game.input.keyboard.isDown(Phaser.Keyboard.SPACEBAR))
		{
			//Todo: Trigger this on mouse click, use position to determine knife velocity
			throwKnife(player.position.x+20, player.position.y+20, 400, 0);
		}
	}
	else
	{
		if(!yourKnife.alive)
		{
			yourKnife = null;
		}
	}
}

function throwKnife(posX, posY, velX, velY)
{
	yourKnife = game.add.sprite(posX, posY, 'wallSprite');
	game.physics.enable(yourKnife);
	yourKnife.body.gravity.y = 0;
	yourKnife.scale.setTo(1/5, 1/5);

	yourKnife.body.velocity.x = velX;
	yourKnife.body.velocity.y = velY;

	//todo: destroy knife(/knives) when they hit level bounds because HOLY SHIT IS THAT A HUGE MEMORY LEAK
	//also todo: only let player have one knife at once
}

//These will have to be replaced with more specific functions later, but they work for prototyping.
function destroyFirstThing(firstThing, secondThing){firstThing.destroy(); firstThing = null;}
function destroySecondThing(firstThing, secondThing){secondThing.destroy();}
function destroyBothThings(firstThing, secondThing)
{
	destroyFirstThing(firstThing, secondThing);
	destroySecondThing(firstThing, secondThing);
}<commit_msg>Added big world, fixed some bugs<commit_after>"use strict";
var game = new Phaser.Game(800, 600, Phaser.AUTO, '', { preload: preload, create: create, update: update });
var player, yourKnife, otherPlayers, otherKnives, cursors, walls;
//Other players' knives might not need to be simulated if the wind is synced well enough. Other players still ought to be for hit detection purposes -- both movement and knife-stabbing.

function preload() {
    game.load.image('skyBackground', 'assets/sky.png');
    game.load.image('playerSprite', 'assets/player.png');
    game.load.image('wallSprite', 'assets/wall.png');
}

function create() {

    game.physics.startSystem(Phaser.Physics.ARCADE);

	//Adding things to world
	//Stuff is rendered in the order it's added (back to front)
	//Desired order: Background < Wind (to be added later) < Players < Walls

	var WORLD_WIDTH = 2000;
	var WORLD_HEIGHT = 2000;
    game.add.tileSprite(0, 0, WORLD_WIDTH, WORLD_HEIGHT, 'skyBackground');
	game.world.setBounds(0, 0, WORLD_WIDTH, WORLD_HEIGHT);

	player = game.add.sprite(game.world.width/2, game.world.height/2, 'playerSprite');
	game.physics.enable(player);
	player.body.gravity.y = 0;
	player.body.collideWorldBounds = true;
	game.camera.follow(player);

	otherPlayers = game.add.group();
	otherPlayers.enableBody = true;
	var newPlayer = otherPlayers.create(3*game.world.width/4, game.world.height/3, 'playerSprite');

	walls = game.add.group();
	walls.enableBody = true;

	//Wallsprite is 50px*50px, scale is multiplicative
	var newWall = walls.create(game.world.width/4-25, game.world.height/4-25, 'wallSprite');
	newWall.scale.setTo(2, 1);
	newWall.body.immovable = true;

	newWall = walls.create(1000, 1100, 'wallSprite');
	newWall.scale.setTo(5, 5);
	newWall.body.immovable = true;

	//Todo in the future: Change arrow keys to WASD
    cursors = game.input.keyboard.createCursorKeys();
	game.input.keyboard.addKeyCapture([Phaser.Keyboard.SPACEBAR]);
}

function update() {
	game.physics.arcade.collide(player, walls);
	game.physics.arcade.collide(player, otherPlayers);
	game.physics.arcade.overlap(player, walls, destroySecondThing, null, this);
	game.physics.arcade.overlap(yourKnife, walls, destroyFirstThing, null, this);
	game.physics.arcade.overlap(yourKnife, otherPlayers, destroyBothThings, null, this);

	player.body.velocity.x = 0;
	player.body.velocity.y = 0;
	var moveSpeed = 300;

	if(cursors.left.isDown)
	{
		player.body.velocity.x -= moveSpeed;
	}
	if(cursors.right.isDown)
	{
		player.body.velocity.x += moveSpeed;
	}
	if(cursors.up.isDown)
	{
		player.body.velocity.y -= moveSpeed;
	}
	if(cursors.down.isDown)
	{
		player.body.velocity.y += moveSpeed;
	}

	//Enforces one-knife-at-once limit, re-enables throw as soon as existing knife dies. Todo: Add time delay like in unity game
	if(yourKnife == null)
	{
		if(game.input.keyboard.isDown(Phaser.Keyboard.SPACEBAR))
		{
			//Todo: Trigger this on mouse click, use position to determine knife velocity
			throwKnife(player.position.x+20, player.position.y+20, 400, 0);
		}
	}
	else
	{
		if(!yourKnife.alive)
		{
			yourKnife = null;
		}
	}
}

function throwKnife(posX, posY, velX, velY)
{
	yourKnife = game.add.sprite(posX, posY, 'wallSprite');
	game.physics.enable(yourKnife);
	yourKnife.checkWorldBounds = true;
	yourKnife.outOfBoundsKill = true;
	yourKnife.body.gravity.y = 0;
	yourKnife.scale.setTo(1/5, 1/5);

	yourKnife.body.velocity.x = velX;
	yourKnife.body.velocity.y = velY;

	//todo: destroy knife(/knives) when they hit level bounds because HOLY SHIT IS THAT A HUGE MEMORY LEAK
	//also todo: only let player have one knife at once
}

//These will have to be replaced with more specific functions later, but they work for prototyping.
function destroyFirstThing(firstThing, secondThing){firstThing.destroy(); firstThing = null;}
function destroySecondThing(firstThing, secondThing){secondThing.destroy();}
function destroyBothThings(firstThing, secondThing)
{
	destroyFirstThing(firstThing, secondThing);
	destroySecondThing(firstThing, secondThing);
}<|endoftext|>


<commit_before>'use strict';

module.exports.merge = function (defaults, options) {
    defaults = defaults || {};
    if (options && typeof options === 'object') {
        var i = 0,
            keys = Object.keys(options);

        for (i = 0; i < keys.length; i += 1) {
            if (options[keys[i]] !== undefined) {
                defaults[keys[i]] = options[keys[i]];
            }
        }
    }
    return defaults;
};

/**
 * trim helper function to trim leading & trailing whitespace from strings
 * @param  {String} string
 * @return {String}
 */
module.exports.trim = function (string) {
  string = string.replace(/(?:(?:^|\n)\s+|\s+(?:$|\n))/g,'');
  string = string.replace(/\s+/g,' ');
  return string;
};
<commit_msg>Documentation and cleanup of utils merge function<commit_after>'use strict';

/**
 * merge helper function to merge objects
 * @param  {Object} defaults
 * @param  {Object} options
 * @return {Object}
 */
module.exports.merge = function (defaults, options) {
  defaults = defaults || {};
  if (options && typeof options === 'object') {
    var i = 0,
    keys = Object.keys(options);

    for (i = 0; i < keys.length; i += 1) {
      if (options[keys[i]] !== undefined) {
       defaults[keys[i]] = options[keys[i]];
      }
    }
  }
  return defaults;
};

/**
 * trim helper function to trim leading & trailing whitespace from strings
 * @param  {String} string
 * @return {String}
 */
module.exports.trim = function (string) {
  string = string.replace(/(?:(?:^|\n)\s+|\s+(?:$|\n))/g,'');
  string = string.replace(/\s+/g,' ');
  return string;
};
<|endoftext|>


<commit_before>'use strict';

const ASSERT = require('assert'),
  REQUEST = require('request'),
  SPEC_GEN = require('../server');

const PORT = 3000,
  AUTHORIZATION = encodeURIComponent(process.env.AUTHORIZATION),
  BASE_URL = 'http://localhost:3000/',
  NO_URL = '&type=foo&URL=notice-that-its-in-uppercase',
  NO_TYPE = '&url=foo&TYPE=notice-that-its-in-uppercase',
  BAD_GENERATOR = '&type=fluxor&url=http://example.com/',
  BAD_SHORTNAME = '&type=RESPEC&url=http://example.com/%3FshortName%3Ddiplodocus',
  NO_RESPEC = '&type=RESPEC&url=http://example.com/',
  SUCCESS1 = `&type=respec&url=https://w3c.github.io/manifest/?${AUTHORIZATION}`,
  SUCCESS2 = `&type=respec&url=https://w3c.github.io/payment-request/?${AUTHORIZATION}`,
  SUCCESS3 = `&type=respec&url=https://w3c.github.io/resource-hints/?${AUTHORIZATION}`;

const FAILS_WITH = (done, expectedMessage = '{"error":"Both \'type\' and \'url\' are required."}', expectedCode = 500) =>
  (error, response, body) => {
    ASSERT.equal(error, null);
    ASSERT.equal(response.statusCode, expectedCode);
    if (expectedMessage instanceof RegExp)
      ASSERT.ok(body.match(expectedMessage));
    else
      ASSERT.equal(body, expectedMessage);
    done();
  }
;

const SUCCEEDS = (done) =>
  (error, response, body) => {
    ASSERT.equal(error, null);
    ASSERT.equal(response.statusCode, 200);
    ASSERT.equal(response.statusMessage, 'OK');
    done();
  };
;

let server;

describe('spec-generator', () => {

  before(() => {
    server = SPEC_GEN.start(PORT);
  });

  describe('fails when it should', () => {
    it('without parameters', (done) => REQUEST.get(BASE_URL, FAILS_WITH(done)));
    it('if there\'s no URL', (done) => REQUEST.get(BASE_URL + NO_URL, FAILS_WITH(done)));
    it('if there\'s no type', (done) => REQUEST.get(BASE_URL + NO_TYPE, FAILS_WITH(done)));
    it('if the generator is not valid', (done) => REQUEST.get(BASE_URL + BAD_GENERATOR, FAILS_WITH(done, '{"error":"Unknown generator: fluxor"}')));
    it('if the shortname is not valid', (done) => REQUEST.get(BASE_URL + BAD_SHORTNAME, FAILS_WITH(done, '{"error":"Not Found"}', 404)));
    it('if the URL does not point to a Respec document', (done) => REQUEST.get(BASE_URL + NO_RESPEC, FAILS_WITH(
      done,
      /That\ doesn't\ seem\ to\ be\ a\ ReSpec\ document\.\ Please\ check\ manually\:/
    )));
  });

  describe('succeeds when it should', () => {
    it('Web App Manifest ("appmanifest")', (done) => REQUEST.get(BASE_URL + SUCCESS1, SUCCEEDS(done)));
    it('Payment Request API ("payment-request")', (done) => REQUEST.get(BASE_URL + SUCCESS2, SUCCEEDS(done)));
    it('Resource Hints ("resource-hints")', (done) => REQUEST.get(BASE_URL + SUCCESS3, SUCCEEDS(done)));
  });

  after(() => server.close());

});
<commit_msg>Encode ? to %3F<commit_after>'use strict';

const ASSERT = require('assert'),
  REQUEST = require('request'),
  SPEC_GEN = require('../server');

const PORT = 3000,
  AUTHORIZATION = encodeURIComponent(process.env.AUTHORIZATION),
  BASE_URL = 'http://localhost:3000/',
  NO_URL = '&type=foo&URL=notice-that-its-in-uppercase',
  NO_TYPE = '&url=foo&TYPE=notice-that-its-in-uppercase',
  BAD_GENERATOR = '&type=fluxor&url=http://example.com/',
  BAD_SHORTNAME = '&type=RESPEC&url=http://example.com/%3FshortName%3Ddiplodocus',
  NO_RESPEC = '&type=RESPEC&url=http://example.com/',
  SUCCESS1 = `&type=respec&url=https://w3c.github.io/manifest/%3F${AUTHORIZATION}`,
  SUCCESS2 = `&type=respec&url=https://w3c.github.io/payment-request/%3F${AUTHORIZATION}`,
  SUCCESS3 = `&type=respec&url=https://w3c.github.io/resource-hints/%3F${AUTHORIZATION}`;

const FAILS_WITH = (done, expectedMessage = '{"error":"Both \'type\' and \'url\' are required."}', expectedCode = 500) =>
  (error, response, body) => {
    ASSERT.equal(error, null);
    ASSERT.equal(response.statusCode, expectedCode);
    if (expectedMessage instanceof RegExp)
      ASSERT.ok(body.match(expectedMessage));
    else
      ASSERT.equal(body, expectedMessage);
    done();
  }
;

const SUCCEEDS = (done) =>
  (error, response, body) => {
    ASSERT.equal(error, null);
    ASSERT.equal(response.statusCode, 200);
    ASSERT.equal(response.statusMessage, 'OK');
    done();
  };
;

let server;

describe('spec-generator', () => {

  before(() => {
    server = SPEC_GEN.start(PORT);
  });

  describe('fails when it should', () => {
    it('without parameters', (done) => REQUEST.get(BASE_URL, FAILS_WITH(done)));
    it('if there\'s no URL', (done) => REQUEST.get(BASE_URL + NO_URL, FAILS_WITH(done)));
    it('if there\'s no type', (done) => REQUEST.get(BASE_URL + NO_TYPE, FAILS_WITH(done)));
    it('if the generator is not valid', (done) => REQUEST.get(BASE_URL + BAD_GENERATOR, FAILS_WITH(done, '{"error":"Unknown generator: fluxor"}')));
    it('if the shortname is not valid', (done) => REQUEST.get(BASE_URL + BAD_SHORTNAME, FAILS_WITH(done, '{"error":"Not Found"}', 404)));
    it('if the URL does not point to a Respec document', (done) => REQUEST.get(BASE_URL + NO_RESPEC, FAILS_WITH(
      done,
      /That\ doesn't\ seem\ to\ be\ a\ ReSpec\ document\.\ Please\ check\ manually\:/
    )));
  });

  describe('succeeds when it should', () => {
    it('Web App Manifest ("appmanifest")', (done) => REQUEST.get(BASE_URL + SUCCESS1, SUCCEEDS(done)));
    it('Payment Request API ("payment-request")', (done) => REQUEST.get(BASE_URL + SUCCESS2, SUCCEEDS(done)));
    it('Resource Hints ("resource-hints")', (done) => REQUEST.get(BASE_URL + SUCCESS3, SUCCEEDS(done)));
  });

  after(() => server.close());

});
<|endoftext|>


<commit_before>// Enemies our player must avoid
var Enemy = function(enemy_x, enemy_y, startSpeed) {
    // Variables applied to each of our instances go here,
    // we've provided one for you to get started
    this.x = enemy_x;
    this.y = enemy_y;
    this.speed = startSpeed;
    // The image/sprite for our enemies, this uses
    // a helper we've provided to easily load images
    this.sprite = 'images/enemy-bug.png';
};

// Update the enemy's position, required method for game
// Parameter: dt, a time delta between ticks
Enemy.prototype.update = function(dt) {
    // You should multiply any movement by the dt parameter
    // which will ensure the game runs at the same speed for
    // all computers.
    this.x = this.x + this.speed * dt;
    if (this.x > 505) {
        this.speed = this.reset();
    }
    // invoke collision detection
    this.findCollision();
};

Enemy.prototype.reset = function(speed){
    this.x = -100;
    speed = Math.floor(Math.random() * 140 + 40);
    //console.log("Bug reset, new speed is " + speed + "!");
    return speed;
};

// Draw the enemy on the screen, required method for game
Enemy.prototype.render = function() {
    ctx.drawImage(Resources.get(this.sprite), this.x, this.y);
};

// method to handle
Enemy.prototype.findCollision = function(){

    var pngWidth = 56; //total width of png: 101
    var pngHeight = 85; // total height of png : 171

    if (player.x < this.x + pngWidth &&
        player.x + pngWidth > this.x &&
        player.y < this.y + pngHeight &&
        player.y + pngHeight > this.y) {
        //collision?
        console.log("Enemy Collision!!!1!");
    }

};

// Now write your own player class
// This class requires an update(), render() and
// a handleInput() method.
// Now write your own player class
var Player = function() {
    this.x = 200;
    this.y = 410;
    this.sprite = 'images/char-pink-girl.png';
};

Player.prototype.update = function() {

};

Player.prototype.render = function() {
    ctx.drawImage(Resources.get(this.sprite), this.x, this.y);
};

    var player_base_move = 30;
Player.prototype.handleInput = function(event) {
    this.ctlKey = event;
    //console.log(this.ctlKey);

    if (this.ctlKey === 'left' && this.x > 0) {
        this.x -= player_base_move;
    } else if (this.ctlKey === 'right' && this.x < 410) {
        this.x = this.x + player_base_move;
    } else if (this.ctlKey === 'up' && this.y > 18 ) {
        this.y = this.y - player_base_move;
    } else if (this.ctlKey === 'down' && this.y < 410) {
        this.y = this.y + player_base_move;
    }
    console.log(this.ctlKey + ": I am at x" + this.x + ", y" + this.y);
};
// Now instantiate your objects.
// Place all enemy objects in an array called allEnemies
// Place the player object in a variable called player

var Vader = new Enemy(-75, 226, 80);
var Voldermort = new Enemy(-145, 145, 100);
var Darkseid = new Enemy(-215, 65, 120);

var allEnemies = [Vader, Voldermort, Darkseid];
//console.log(allEnemies);

var player = new Player();

// This listens for key presses and sends the keys to your
// Player.handleInput() method. You don't need to modify this.
document.addEventListener('keyup', function(e) {
    var allowedKeys = {
        37: 'left',
        38: 'up',
        39: 'right',
        40: 'down'
    };

    player.handleInput(allowedKeys[e.keyCode]);

});
<commit_msg>allEnemies.push(newEnemy) now works.  Now to randomize starting point and speed!<commit_after>// Enemies our player must avoid
var Enemy = function(enemy_x, enemy_y, startSpeed) {
    // Variables applied to each of our instances go here,
    // we've provided one for you to get started
    this.x = enemy_x;
    this.y = enemy_y;
    this.speed = startSpeed;
    // The image/sprite for our enemies, this uses
    // a helper we've provided to easily load images
    this.sprite = 'images/enemy-bug.png';
};

// Update the enemy's position, required method for game
// Parameter: dt, a time delta between ticks
Enemy.prototype.update = function(dt) {
    // You should multiply any movement by the dt parameter
    // which will ensure the game runs at the same speed for
    // all computers.
    this.x = this.x + this.speed * dt;
    if (this.x > 505) {
        this.speed = this.reset();
    }
    // invoke collision detection
    this.findCollision();
};

Enemy.prototype.reset = function(speed){
    this.x = -100;
    speed = Math.floor(Math.random() * 140 + 40);
    //console.log("Bug reset, new speed is " + speed + "!");
    return speed;
};

// Draw the enemy on the screen, required method for game
Enemy.prototype.render = function() {
    ctx.drawImage(Resources.get(this.sprite), this.x, this.y);
};

// method to handle
Enemy.prototype.findCollision = function(){

    var pngWidth = 56; //total width of png: 101
    var pngHeight = 85; // total height of png : 171

    if (player.x < this.x + pngWidth &&
        player.x + pngWidth > this.x &&
        player.y < this.y + pngHeight &&
        player.y + pngHeight > this.y) {
        //collision?
        console.log("Enemy Collision!!!1!");
    }

};

// Now write your own player class
// This class requires an update(), render() and
// a handleInput() method.
// Now write your own player class
var Player = function() {
    this.x = 200;
    this.y = 410;
    this.sprite = 'images/char-pink-girl.png';
};

Player.prototype.update = function() {

};

Player.prototype.render = function() {
    ctx.drawImage(Resources.get(this.sprite), this.x, this.y);
};

    var player_base_move = 30;
Player.prototype.handleInput = function(event) {
    this.ctlKey = event;
    //console.log(this.ctlKey);

    if (this.ctlKey === 'left' && this.x > 0) {
        this.x -= player_base_move;
    } else if (this.ctlKey === 'right' && this.x < 410) {
        this.x = this.x + player_base_move;
    } else if (this.ctlKey === 'up' && this.y > 18 ) {
        this.y = this.y - player_base_move;
    } else if (this.ctlKey === 'down' && this.y < 410) {
        this.y = this.y + player_base_move;
    }
    console.log(this.ctlKey + ": I am at x" + this.x + ", y" + this.y);
};
// Now instantiate your objects.
// Place all enemy objects in an array called allEnemies
// Place the player object in a variable called player

/*var Vader = new Enemy(-75, 226, 80);
var Voldermort = new Enemy(-145, 145, 100);
var Darkseid = new Enemy(-215, 65, 120);

var allEnemies = [Vader, Voldermort, Darkseid];*/

var paths = [65, 145, 226];
var allEnemies = [];

for (var path = 0; path < paths.length; path++ ) {
    var newEnemy = new Enemy(-100, paths[path], 80);
    console.log(newEnemy);
    allEnemies.push(newEnemy);
}
console.log(allEnemies);

var player = new Player();

// This listens for key presses and sends the keys to your
// Player.handleInput() method. You don't need to modify this.
document.addEventListener('keyup', function(e) {
    var allowedKeys = {
        37: 'left',
        38: 'up',
        39: 'right',
        40: 'down'
    };

    player.handleInput(allowedKeys[e.keyCode]);

});
<|endoftext|>


<commit_before>var should = require('chai').should();

var scout = require('nock')('http://api.captainteemo.com');

var resteemo = require('../');
var teemo = resteemo('node-resteemo test suite');

var TEST_SUMMONER = 'guardsmanbob';
var TEST_PLATFORM = 'euw';
var TEST_PLATFORM_FULL = 'Europe_West';
var PLAYER_PATH = '/player/' + TEST_PLATFORM + '/' + TEST_SUMMONER;
var TEAM_PATH = '/team/' + TEST_PLATFORM;
var DATA_FOLDER = __dirname + '/data/';

describe('node-resteemo', function() {
  it('should export a function', function() {
    resteemo.should.be.a('function');
  });
  it('should return an object', function() {
    teemo.should.be.an('object');
  });
  it('should throw error if referer string is not provided', function() {
    resteemo.should.throw(/refererString/);
  });

  describe('player', function() {
    before(function(done) {
      scout
        .get(PLAYER_PATH)
        .replyWithFile(200, DATA_FOLDER + 'profile.json');

      teemo.player(TEST_PLATFORM, TEST_SUMMONER, function(error, profile) {
        if (error) return done(error);
        this.profile = profile;
        done();
      });
    });
    after(function() {
      this.profile = null;
    });

    it('should be a function', function() {
      teemo.player.should.be.a('function');
    });
    it('should return an object that is deep equal', function() {
      profile.should.be.an('object');
      profile.should.deep.equal(require(DATA_FOLDER + 'profile.json'));
    });
    it('should work with full platform names', function(done) {
      scout
        .get(PLAYER_PATH)
        .replyWithFile(200, DATA_FOLDER + 'profile.json');

      teemo.player(TEST_PLATFORM_FULL, TEST_SUMMONER, function(error, prof) {
        should.not.exist(error);
        should.exist(prof);
        prof.should.deep.equal(require(DATA_FOLDER + 'profile.json'));
        done();
      });
    });
    it('should return error if api fails', function(done) {
      scout
        .get('/player/' + TEST_PLATFORM + '/guardsmanbo')
        .replyWithFile(503, DATA_FOLDER + 'error-profile.json');

      teemo.player(TEST_PLATFORM, 'guardsmanbo', function(error, nothing) {
        should.exist(error);
        should.not.exist(nothing);
        done();
      });
    });
    it('should return error if second api call fails', function(done) {
      scout
        .get('/player/' + TEST_PLATFORM + '/guardsmanbob')
        .replyWithFile(503, DATA_FOLDER + 'error-second.json');

      teemo.player(TEST_PLATFORM, 'guardsmanbob', function(error, nothing) {
        should.exist(error);
        should.not.exist(nothing);
        done();
      });
    });
    it('should return error if json cannot be parsed', function(done) {
      scout
        .get('/player/' + TEST_PLATFORM + '/fakejson')
        .replyWithFile(200, DATA_FOLDER + 'error-json.json');

      teemo.player(TEST_PLATFORM, 'fakejson', function(error, nothing) {
        should.exist(error);
        should.not.exist(nothing);
        done();
      });
    });

    describe('ingame', function() {
      before(function(done) {
        scout
          .get(PLAYER_PATH + '/ingame')
          .replyWithFile(200, DATA_FOLDER + 'ingame.json');

        teemo.player.ingame(TEST_PLATFORM, TEST_SUMMONER, function(error, game) {
          if (error) return done(error);
          this.game = game;
          done();
        });
      });
      after(function() {
        this.game = null;
      });

      it('should be a function', function() {
        teemo.player.ingame.should.be.a('function');
      });
      it('should return an object that is deep equal', function() {
        game.should.be.an('object');
        game.should.deep.equal(require(DATA_FOLDER + 'ingame.json'));
      });
    });

    describe('recentGames', function() {
      before(function(done) {
        scout
          .get(PLAYER_PATH + '/recent_games')
          .replyWithFile(200, DATA_FOLDER + 'recent_games.json');

        teemo.player.recentGames(TEST_PLATFORM, TEST_SUMMONER, function(error, games) {
          if (error) return done(error);
          this.games = games;
          done();
        });
      });
      after(function() {
        this.games = null;
      });

      it('should be a function', function() {
        teemo.player.recentGames.should.be.a('function');
      });
      it('should return an object that is deep equal', function() {
        games.should.be.an('object');
        games.should.deep.equal(require(DATA_FOLDER + 'recent_games.json'));
      });
    });

    describe('influencePoints', function() {
      before(function(done) {
        scout
          .get(PLAYER_PATH + '/influence_points')
          .replyWithFile(200, DATA_FOLDER + 'influence_points.json');

        teemo.player.influencePoints(TEST_PLATFORM, TEST_SUMMONER, function(error, points) {
          if (error) return done(error);
          this.points = points;
          done();
        });
      });
      after(function() {
        this.points = null;
      });

      it('should be a function', function() {
        teemo.player.influencePoints.should.be.a('function');
      });
      it('should return an object that is deep equal', function() {
        points.should.be.an('object');
        points.should.deep.equal(require(DATA_FOLDER + 'influence_points.json'));
      });
    });

    describe('runes', function() {
      before(function(done) {
        scout
          .get(PLAYER_PATH + '/runes')
          .replyWithFile(200, DATA_FOLDER + 'runes.json');

        teemo.player.runes(TEST_PLATFORM, TEST_SUMMONER, function(error, runes) {
          if (error) return done(error);
          this.runes = runes;
          done();
        });
      });
      after(function() {
        this.runes = null;
      });

      it('should be a function', function() {
        teemo.player.runes.should.be.a('function');
      });
      it('should return an object that is deep equal', function() {
        runes.should.be.an('object');
        runes.should.deep.equal(require(DATA_FOLDER + 'runes.json'));
      });
    });

    describe('mastery', function() {
      before(function(done) {
        scout
          .get(PLAYER_PATH + '/mastery')
          .replyWithFile(200, DATA_FOLDER + 'mastery.json');

        teemo.player.mastery(TEST_PLATFORM, TEST_SUMMONER, function(error, pages) {
          if (error) return done(error);
          this.pages = pages;
          done();
        });
      });
      after(function() {
        this.pages = null;
      });

      it('should be a function', function() {
        teemo.player.mastery.should.be.a('function');
      });
      it('should return an object that is deep equal', function() {
        pages.should.be.an('object');
        pages.should.deep.equal(require(DATA_FOLDER + 'mastery.json'));
      });
    });

    describe('leagues', function() {
      before(function(done) {
        scout
          .get(PLAYER_PATH + '/leagues')
          .replyWithFile(200, DATA_FOLDER + 'leagues.json');

        teemo.player.leagues(TEST_PLATFORM, TEST_SUMMONER, function(error, leagues) {
          if (error) return done(error);
          this.leagues = leagues;
          done();
        });
      });
      after(function() {
        this.leagues = null;
      });

      it('should be a function', function() {
        teemo.player.leagues.should.be.a('function');
      });
      it('should return an object that is deep equal', function() {
        leagues.should.be.an('object');
        leagues.should.deep.equal(require(DATA_FOLDER + 'leagues.json'));
      });
    });

    describe('honor', function() {
      before(function(done) {
        scout
          .get(PLAYER_PATH + '/honor')
          .replyWithFile(200, DATA_FOLDER + 'honor.json');

        teemo.player.honor(TEST_PLATFORM, TEST_SUMMONER, function(error, honor) {
          if (error) return done(error);
          this.honor = honor;
          done();
        });
      });
      after(function() {
        this.honor = null;
      });

      it('should be a function', function() {
        teemo.player.honor.should.be.a('function');
      });
      it('should return an object that is deep equal', function() {
        honor.should.be.an('object');
        honor.should.deep.equal(require(DATA_FOLDER + 'honor.json'));
      });
    });

    describe('rankedStats', function() {
      before(function(done) {
        scout
          .get(PLAYER_PATH + '/ranked_stats/season/3')
          .replyWithFile(200, DATA_FOLDER + 'ranked_stats.json');

        teemo.player.rankedStats(TEST_PLATFORM, TEST_SUMMONER, 3, function(error, stats) {
          if (error) return done(error);
          this.stats = stats;
          done();
        });
      });
      after(function() {
        this.stats = null;
      });

      it('should be a function', function() {
        teemo.player.rankedStats.should.be.a('function');
      });
      it('should return an object that is deep equal', function() {
        stats.should.be.an('object');
        stats.should.deep.equal(require(DATA_FOLDER + 'ranked_stats.json'));
      });
    });

    describe('teams', function() {
      before(function(done) {
        scout
          .get(PLAYER_PATH + '/teams')
          .replyWithFile(200, DATA_FOLDER + 'teams.json');

        teemo.player.teams(TEST_PLATFORM, TEST_SUMMONER, function(error, teams) {
          if (error) return done(error);
          this.teams = teams;
          done();
        });
      });
      after(function() {
        this.teams = null;
      });

      it('should be a function', function() {
        teemo.player.teams.should.be.a('function');
      });
      it('should return an object that is deep equal', function() {
        teams.should.be.an('object');
        teams.should.deep.equal(require(DATA_FOLDER + 'teams.json'));
      });
    });
  });

  describe('team', function() {
    before(function(done) {
      scout
        .get(TEAM_PATH + '/tag/WHEELZ')
        .replyWithFile(200, DATA_FOLDER + 'tag.json');

      teemo.team(TEST_PLATFORM, 'WHEELZ', function(error, matches) {
        if (error) return done(error);
        this.matches = matches;
        done();
      });
    });
    after(function() {
      this.matches = null;
    });

    it('should be a function', function() {
      teemo.team.should.be.a('function');
    });
    it('should return an object that is deep equal', function() {
      matches.should.be.an('object');
      matches.should.deep.equal(require(DATA_FOLDER + 'tag.json'));
    });

    describe('leagues', function() {
      before(function(done) {
        scout
          .get(TEAM_PATH + '/guid/TEAM-1e4caa75-aaf0-11e2-8fcc-782bcb4d0bb2/leagues')
          .replyWithFile(200, DATA_FOLDER + 'team_leagues.json');

        teemo.team.leagues(TEST_PLATFORM, 'TEAM-1e4caa75-aaf0-11e2-8fcc-782bcb4d0bb2', function(error, leagues) {
          if (error) return done(error);
          this.leagues = leagues;
          done();
        });
      });
      after(function() {
        this.leagues = null;
      });

      it('should be a function', function() {
        teemo.team.leagues.should.be.a('function');
      });
      it('should return an object', function() {
        leagues.should.be.an('object');
        leagues.should.deep.equal(require(DATA_FOLDER + 'team_leagues.json'));
      });
    });
  });
  describe('freeWeek', function() {
    before(function(done) {
      scout
        .get('/service-state/na/free-week')
        .replyWithFile(200, DATA_FOLDER + 'free_week.json');

      teemo.freeWeek('na', function(error, week) {
        if (error) return done(error);
        this.week = week;
        done();
      });
    });
    after(function() {
      this.week = null;
    });

    it('should be a function', function() {
      teemo.freeWeek.should.be.a('function');
    });
    it('should return an object that is deep equal', function() {
      week.should.be.an('object');
      week.should.deep.equal(require(DATA_FOLDER + 'free_week.json'));
    });
  });
});<commit_msg>Reduce test redundancy through shared behaviors<commit_after>var should = require('chai').should();

var scout = require('nock')('http://api.captainteemo.com');

var resteemo = require('../');
var teemo = resteemo('node-resteemo test suite');

var TEST_SUMMONER = 'guardsmanbob';
var TEST_PLATFORM = 'euw';
var TEST_PLATFORM_FULL = 'Europe_West';
var PLAYER_PATH = '/player/' + TEST_PLATFORM + '/' + TEST_SUMMONER;
var TEAM_PATH = '/team/' + TEST_PLATFORM;
var DATA_FOLDER = __dirname + '/data/';

var shouldShare = function(fn, file) {
  it('should be a function', function() {
    fn.should.be.a('function');
  });
  it('should return an object', function() {
    this.response.should.be.an('object');
  });
  it('should return the correct response', function() {
    this.response.should.deep.equal(require(file));
  });
};

describe('node-resteemo', function() {
  it('should export a function', function() {
    resteemo.should.be.a('function');
  });
  it('should return an object', function() {
    teemo.should.be.an('object');
  });
  it('should throw error if referer string is not provided', function() {
    resteemo.should.throw(/refererString/);
  });

  describe('player', function() {
    beforeEach(function(done) {
      var that = this;

      scout
        .get(PLAYER_PATH)
        .replyWithFile(200, DATA_FOLDER + 'profile.json');

      teemo.player(TEST_PLATFORM, TEST_SUMMONER, function(error, profile) {
        if (error) return done(error);
        that.response = profile;
        done();
      });
    });
    afterEach(function() {
      this.response = null;
    });

    shouldShare(teemo.player, DATA_FOLDER + 'profile.json');

    it('should work with full platform names', function(done) {
      scout
        .get(PLAYER_PATH)
        .replyWithFile(200, DATA_FOLDER + 'profile.json');

      teemo.player(TEST_PLATFORM_FULL, TEST_SUMMONER, function(error, response) {
        should.not.exist(error);
        should.exist(response);
        response.should.deep.equal(require(DATA_FOLDER + 'profile.json'));
        done();
      });
    });
    it('should return error if api fails', function(done) {
      scout
        .get('/player/' + TEST_PLATFORM + '/guardsmanbo')
        .replyWithFile(503, DATA_FOLDER + 'error-profile.json');

      teemo.player(TEST_PLATFORM, 'guardsmanbo', function(error, nothing) {
        should.exist(error);
        should.not.exist(nothing);
        done();
      });
    });
    it('should return error if second api call fails', function(done) {
      scout
        .get('/player/' + TEST_PLATFORM + '/guardsmanbob')
        .replyWithFile(503, DATA_FOLDER + 'error-second.json');

      teemo.player(TEST_PLATFORM, 'guardsmanbob', function(error, nothing) {
        should.exist(error);
        should.not.exist(nothing);
        done();
      });
    });
    it('should return error if json cannot be parsed', function(done) {
      scout
        .get('/player/' + TEST_PLATFORM + '/fakejson')
        .replyWithFile(200, DATA_FOLDER + 'error-json.json');

      teemo.player(TEST_PLATFORM, 'fakejson', function(error, nothing) {
        should.exist(error);
        should.not.exist(nothing);
        done();
      });
    });

    describe('ingame', function() {
      beforeEach(function(done) {
        var that = this;

        scout
          .get(PLAYER_PATH + '/ingame')
          .replyWithFile(200, DATA_FOLDER + 'ingame.json');

        teemo.player.ingame(TEST_PLATFORM, TEST_SUMMONER, function(error, game) {
          if (error) return done(error);
          that.response = game;
          done();
        });
      });
      afterEach(function() {
        this.response = null;
      });

      shouldShare(teemo.player.ingame, DATA_FOLDER + 'ingame.json');
    });

    describe('recentGames', function() {
      beforeEach(function(done) {
        var that = this;

        scout
          .get(PLAYER_PATH + '/recent_games')
          .replyWithFile(200, DATA_FOLDER + 'recent_games.json');

        teemo.player.recentGames(TEST_PLATFORM, TEST_SUMMONER, function(error, games) {
          if (error) return done(error);
          that.response = games;
          done();
        });
      });
      afterEach(function() {
        this.response = null;
      });

      shouldShare(teemo.player.recentGames, DATA_FOLDER + 'recent_games.json');
    });

    describe('influencePoints', function() {
      beforeEach(function(done) {
        var that = this;

        scout
          .get(PLAYER_PATH + '/influence_points')
          .replyWithFile(200, DATA_FOLDER + 'influence_points.json');

        teemo.player.influencePoints(TEST_PLATFORM, TEST_SUMMONER, function(error, points) {
          if (error) return done(error);
          that.response = points;
          done();
        });
      });
      afterEach(function() {
        this.response = null;
      });

      shouldShare(teemo.player.influencePoints, DATA_FOLDER + 'influence_points.json');
    });

    describe('runes', function() {
      beforeEach(function(done) {
        var that = this;

        scout
          .get(PLAYER_PATH + '/runes')
          .replyWithFile(200, DATA_FOLDER + 'runes.json');

        teemo.player.runes(TEST_PLATFORM, TEST_SUMMONER, function(error, runes) {
          if (error) return done(error);
          that.response = runes;
          done();
        });
      });
      afterEach(function() {
        this.response = null;
      });

      shouldShare(teemo.player.runes, DATA_FOLDER + 'runes.json');
    });

    describe('mastery', function() {
      beforeEach(function(done) {
        var that = this;

        scout
          .get(PLAYER_PATH + '/mastery')
          .replyWithFile(200, DATA_FOLDER + 'mastery.json');

        teemo.player.mastery(TEST_PLATFORM, TEST_SUMMONER, function(error, pages) {
          if (error) return done(error);
          that.response = pages;
          done();
        });
      });
      afterEach(function() {
        this.response = null;
      });

      shouldShare(teemo.player.mastery, DATA_FOLDER + 'mastery.json');
    });

    describe('leagues', function() {
      beforeEach(function(done) {
        var that = this;

        scout
          .get(PLAYER_PATH + '/leagues')
          .replyWithFile(200, DATA_FOLDER + 'leagues.json');

        teemo.player.leagues(TEST_PLATFORM, TEST_SUMMONER, function(error, leagues) {
          if (error) return done(error);
          that.response = leagues;
          done();
        });
      });
      afterEach(function() {
        this.response = null;
      });

      shouldShare(teemo.player.leagues, DATA_FOLDER + 'leagues.json');
    });

    describe('honor', function() {
      beforeEach(function(done) {
        var that = this;

        scout
          .get(PLAYER_PATH + '/honor')
          .replyWithFile(200, DATA_FOLDER + 'honor.json');

        teemo.player.honor(TEST_PLATFORM, TEST_SUMMONER, function(error, honor) {
          if (error) return done(error);
          that.response = honor;
          done();
        });
      });
      afterEach(function() {
        this.response = null;
      });

      shouldShare(teemo.player.honor, DATA_FOLDER + 'honor.json');
    });

    describe('rankedStats', function() {
      beforeEach(function(done) {
        var that = this;

        scout
          .get(PLAYER_PATH + '/ranked_stats/season/3')
          .replyWithFile(200, DATA_FOLDER + 'ranked_stats.json');

        teemo.player.rankedStats(TEST_PLATFORM, TEST_SUMMONER, 3, function(error, stats) {
          if (error) return done(error);
          that.response = stats;
          done();
        });
      });
      afterEach(function() {
        this.response = null;
      });

      shouldShare(teemo.player.rankedStats, DATA_FOLDER + 'ranked_stats.json');
    });

    describe('teams', function() {
      beforeEach(function(done) {
        var that = this;

        scout
          .get(PLAYER_PATH + '/teams')
          .replyWithFile(200, DATA_FOLDER + 'teams.json');

        teemo.player.teams(TEST_PLATFORM, TEST_SUMMONER, function(error, teams) {
          if (error) return done(error);
          that.response = teams;
          done();
        });
      });
      afterEach(function() {
        this.response = null;
      });

      shouldShare(teemo.player.teams, DATA_FOLDER + 'teams.json');
    });
  });

  describe('team', function() {
    beforeEach(function(done) {
      var that = this;

      scout
        .get(TEAM_PATH + '/tag/WHEELZ')
        .replyWithFile(200, DATA_FOLDER + 'tag.json');

      teemo.team(TEST_PLATFORM, 'WHEELZ', function(error, matches) {
        if (error) return done(error);
        that.response = matches;
        done();
      });
    });
    afterEach(function() {
      this.response = null;
    });

    shouldShare(teemo.team, DATA_FOLDER + 'tag.json');

    describe('leagues', function() {
      beforeEach(function(done) {
        var that = this;

        scout
          .get(TEAM_PATH + '/guid/TEAM-1e4caa75-aaf0-11e2-8fcc-782bcb4d0bb2/leagues')
          .replyWithFile(200, DATA_FOLDER + 'team_leagues.json');

        teemo.team.leagues(TEST_PLATFORM, 'TEAM-1e4caa75-aaf0-11e2-8fcc-782bcb4d0bb2', function(error, leagues) {
          if (error) return done(error);
          that.response = leagues;
          done();
        });
      });
      afterEach(function() {
        this.response = null;
      });

      shouldShare(teemo.team.leagues, DATA_FOLDER + 'team_leagues.json');
    });
  });
  describe('freeWeek', function() {
    beforeEach(function(done) {
      var that = this;

      scout
        .get('/service-state/na/free-week')
        .replyWithFile(200, DATA_FOLDER + 'free_week.json');

      teemo.freeWeek('na', function(error, week) {
        if (error) return done(error);
        that.response = week;
        done();
      });
    });
    afterEach(function() {
      this.response = null;
    });

    shouldShare(teemo.freeWeek, DATA_FOLDER + 'free_week.json');
  });
});<|endoftext|>


<commit_before><commit_msg>Update app.js<commit_after><|endoftext|>


<commit_before>var _ = require('underscore');

_.string = require('underscore.string');
_.mixin(_.string.exports());

exports.formatDate = function (date) {
	return _.strLeft(date.toISOString(), 'T');
};

/**
 * returns a date or a period denoted by 'day', 'week', or 'month' in a format
 * that can be used in a route (return value will start with the '/' character
 *
 * returns undefined if undefined is passed as the period
 *
 * @param period
 * @returns {string}
 */
exports.formatPeriod = function(period) {
	if (_.isUndefined(period)) { return ''; }

	if (_.isDate(period)) { return '/' + exports.formatDate(period); }

	//noinspection FallthroughInSwitchStatementJS
	switch(period) {
		case 'day':
		case '1d':
			return '/1d';

		case 'week':
		case '1w':
		case '7d':
			return '/1w';

		case 'month':
		case '30d':
		case '1m':
			return '/1m';

		default:
			return '';
	}
};<commit_msg>fixed bad underscore require<commit_after>var _ = require('lodash');

_.string = require('underscore.string');
_.mixin(_.string.exports());

exports.formatDate = function (date) {
	return _.strLeft(date.toISOString(), 'T');
};

/**
 * returns a date or a period denoted by 'day', 'week', or 'month' in a format
 * that can be used in a route (return value will start with the '/' character
 *
 * returns undefined if undefined is passed as the period
 *
 * @param period
 * @returns {string}
 */
exports.formatPeriod = function(period) {
	if (_.isUndefined(period)) { return ''; }

	if (_.isDate(period)) { return '/' + exports.formatDate(period); }

	//noinspection FallthroughInSwitchStatementJS
	switch(period) {
		case 'day':
		case '1d':
			return '/1d';

		case 'week':
		case '1w':
		case '7d':
			return '/1w';

		case 'month':
		case '30d':
		case '1m':
			return '/1m';

		default:
			return '';
	}
};<|endoftext|>


<commit_before>var assert = require('assert')
var getCssColors = require('..')

var stringWithColors = 'foobar hsl(,,) hsla(1, 1.111%, 1.1111%, .8) rgba(123, 123, 123, .8) #fff turtles rebeccapurple'

describe('get-css-colors', function() {

  it('should do something awesome', function() {
    assert.deepEqual(
      getCssColors(stringWithColors),
      ['hsla(1, 1.111%, 1.1111%, .8)', 'rgba(123, 123, 123, .8)', '#fff', 'rebeccapurple']
    )
  })
})
<commit_msg>Add case sensitivity test<commit_after>var assert = require('assert')
var getCssColors = require('..')

var stringWithColors = 'foobar hsl(,,) HSLA(1, 1.111%, 1.1111%, .8) rgba(123, 123, 123, .8) #fff turtles rebeccapurple #123AAA'

describe('get-css-colors', function() {

  it('should do something awesome', function() {
    assert.deepEqual(
      getCssColors(stringWithColors),
      ['HSLA(1, 1.111%, 1.1111%, .8)', 'rgba(123, 123, 123, .8)', '#fff', 'rebeccapurple', '#123AAA']
    )
  })
})
<|endoftext|>


<commit_before>#!/usr/bin/env node

var fs = require('fs');
var karel = require('./karel.js');
var version = require('../package.json').version;
var DOMParser = require('xmldom').DOMParser;

var nomnom = require('nomnom');

nomnom.command('compile')
    .option('lang',
            {
              abbr: 'l',
              position: 1,
              required: true,
              choices: ['pascal', 'java', 'ruby'],
              type: 'string',
              help: 'the language (pascal, java, ruby)'
            })
    .option('input',
            {
              abbr: 'i',
              position: 2,
              required: true,
              type: 'string',
              help: 'the program to compile'
            })
    .option('output', {abbr: 'o', type: 'string', help: 'the output file'})
    .help('compile a karel program');

nomnom.command('run')
    .option('program',
            {
              abbr: 'p',
              position: 1,
              required: true,
              type: 'string',
              help: 'the program you want to run'
            })
    .help('run a compiled karel program');

var opts = nomnom.script('karel.js')
               .option('verbose',
                       {
                         abbr: 'v',
                         flag: true,
                         help: 'be verbose (print debugging messages)'
                       })
               .option('version',
                       {
                         abbr: 'V',
                         flag: true,
                         help: 'print version and exit',
                         callback: function() { return version; }
                       })
               .parse();

if (opts['0'] == 'compile') {
  var file = fs.readFileSync(opts.input, {encoding: 'utf-8'});
  var parser = null;

  if (opts.lang == 'java') {
    parser = require('./kareljava.js').parse;
  } else if (opts.lang == 'pascal') {
    parser = require('./karelpascal.js').parse;
  } else if (opts.lang == 'ruby') {
    parser = require('./karelruby.js').parse;
  }

  var program = null;
  try {
    program = parser(file);
  } catch (e) {
    console.log(e.message);
    if (!e.hash || !e.hash.line || !e.hash.text) {
      process.exit(1);
    }
    var lines = file.split('\n');
    if (e.hash.line < 1 || e.hash.line > lines.length) {
      process.exit(1);
    }
    var errorLine = lines[e.hash.line].replace(/\t/g, '        ');
    var idx = errorLine.indexOf(e.hash.text);
    if (idx < 0) {
      process.exit(1);
    }
    var lineNumberPrefix = e.hash.line.toString(10) + ': ';
    console.log('\n' + lineNumberPrefix + errorLine);
    console.log(' '.repeat(idx + lineNumberPrefix.length) + '^'.repeat(e.hash.text.length));
    process.exit(1);
  }

  var output = opts.output;
  if (!output) {
    var index = opts.input.lastIndexOf('.');
    if (index == -1) {
      output = opts.input + '.json';
    } else {
      output = opts.input.substring(0, index) + '.json';
    }
  }

  fs.writeFileSync(output, JSON.stringify(program));
} else {
  var program = JSON.parse(fs.readFileSync(opts.program, {encoding: 'utf-8'}));
  var worldXml = new DOMParser().parseFromString(
      fs.readFileSync('/dev/stdin', {encoding: 'utf-8'}), 'text/xml');
  var world = new karel.World(100, 100);
  world.load(worldXml);
  if (opts.verbose) {
    world.runtime.debug = true;
    world.runtime.addEventListener(
        'debug', function(ev) { console.log(ev.debugType, ev.message); });
  }
  world.runtime.load(program);
  while (world.runtime.step()) {
    // Keep going...
  }
  console.log(world.output());
}
<commit_msg>Desplegando el error en stderr<commit_after>#!/usr/bin/env node

var fs = require('fs');
var karel = require('./karel.js');
var version = require('../package.json').version;
var DOMParser = require('xmldom').DOMParser;

var nomnom = require('nomnom');

nomnom.command('compile')
    .option('lang',
            {
              abbr: 'l',
              position: 1,
              required: true,
              choices: ['pascal', 'java', 'ruby'],
              type: 'string',
              help: 'the language (pascal, java, ruby)'
            })
    .option('input',
            {
              abbr: 'i',
              position: 2,
              required: true,
              type: 'string',
              help: 'the program to compile'
            })
    .option('output', {abbr: 'o', type: 'string', help: 'the output file'})
    .help('compile a karel program');

nomnom.command('run')
    .option('program',
            {
              abbr: 'p',
              position: 1,
              required: true,
              type: 'string',
              help: 'the program you want to run'
            })
    .help('run a compiled karel program');

var opts = nomnom.script('karel.js')
               .option('verbose',
                       {
                         abbr: 'v',
                         flag: true,
                         help: 'be verbose (print debugging messages)'
                       })
               .option('version',
                       {
                         abbr: 'V',
                         flag: true,
                         help: 'print version and exit',
                         callback: function() { return version; }
                       })
               .parse();

if (opts['0'] == 'compile') {
  var file = fs.readFileSync(opts.input, {encoding: 'utf-8'});
  var parser = null;

  if (opts.lang == 'java') {
    parser = require('./kareljava.js').parse;
  } else if (opts.lang == 'pascal') {
    parser = require('./karelpascal.js').parse;
  } else if (opts.lang == 'ruby') {
    parser = require('./karelruby.js').parse;
  }

  var program = null;
  try {
    program = parser(file);
  } catch (e) {
    console.error(e.message);
    if (!e.hash || !e.hash.line || !e.hash.text) {
      process.exit(1);
    }
    var lines = file.split('\n');
    if (e.hash.line < 1 || e.hash.line > lines.length) {
      process.exit(1);
    }
    var errorLine = lines[e.hash.line].replace(/\t/g, '        ');
    var idx = errorLine.indexOf(e.hash.text);
    if (idx < 0) {
      process.exit(1);
    }
    var lineNumberPrefix = e.hash.line.toString(10) + ': ';
    console.error('\n' + lineNumberPrefix + errorLine);
    console.error(' '.repeat(idx + lineNumberPrefix.length) + '^'.repeat(e.hash.text.length));
    process.exit(1);
  }

  var output = opts.output;
  if (!output) {
    var index = opts.input.lastIndexOf('.');
    if (index == -1) {
      output = opts.input + '.json';
    } else {
      output = opts.input.substring(0, index) + '.json';
    }
  }

  fs.writeFileSync(output, JSON.stringify(program));
} else {
  var program = JSON.parse(fs.readFileSync(opts.program, {encoding: 'utf-8'}));
  var worldXml = new DOMParser().parseFromString(
      fs.readFileSync('/dev/stdin', {encoding: 'utf-8'}), 'text/xml');
  var world = new karel.World(100, 100);
  world.load(worldXml);
  if (opts.verbose) {
    world.runtime.debug = true;
    world.runtime.addEventListener(
        'debug', function(ev) { console.log(ev.debugType, ev.message); });
  }
  world.runtime.load(program);
  while (world.runtime.step()) {
    // Keep going...
  }
  console.log(world.output());
}
<|endoftext|>


<commit_before>/*jshint -W083 */

var fs = require('fs');
var glob = require('glob');

var svgRegex = /url\("data:image\/svg\+xml;.*?"\)/gi;
var whiteSpaceRegex = /\s/g;
var utils = {};

/**
 * Get an id by hyphen separating the name.
 *
 * @param {string} str - String to hyphenate.
 * @returns {string}
 */
utils.getId = function getId(str) {
  return encodeURIComponent(str.toLowerCase().replace(whiteSpaceRegex, '-'));
};

/**
 * Normalize a name.
 *
 * @param {string} name - Name to normalize.
 * @returns string
 */
utils.normalizeName = function normalizeName(name) {
  return name.toLowerCase();
};

/**
 * Generate the sort order of pages and sections.
 *
 * @param {object} context - Context to pass to handlebars.
 * @param {string[]} [context.pageOrder=[]] - Order that the pages should be sorted by.
 * @param {object[]} context.pages - List of pages.
 * @param {object[]} sortOrder - Array of objects of page name to array of section names.
 */
utils.generateSortOrder = function generateSortOrder(context, sortOrder) {
  context.pageOrder = context.pageOrder || [];

  // sortOrder can be:
  // sort just pages: array of page names
  // sort just sections: object of page names to array of section names
  // sort both: array of objects of page names to array of section names
  // sort some: array of objects and strings
  if (!Array.isArray(sortOrder)) {
    sortOrder = [sortOrder];
  }

  sortOrder.forEach(function(value, index) {
    // string page name
    if (typeof value === 'string') {
      context.pageOrder.push(utils.normalizeName(value));
      return;
    }

    if (Array.isArray(value)) {
      value.forEach(function(name) {
        context.pageOrder.push(utils.normalizeName(name));
      });
      return;
    }

    // object of string page name to array of section names
    for (var prop in value) {
      if (!value.hasOwnProperty(prop)) {
        continue;
      }

      context.pageOrder.push(utils.normalizeName(prop));

      if (context.pages[prop]) {
        context.pages[prop].sectionOrder = context.pages[prop].sectionOrder || [];

        // sections
        value[prop].forEach(function(val) {
          context.pages[prop].sectionOrder.push(utils.normalizeName(val));
        });
      }
    }
  });
};

/**
 * Sort a list of categories (pages, sections) by a given array.
 *
 * @param {object[]} categories - List of categories.
 * @param {object} sortOrder - List of category names in the order they should be sorted. Any category not listed will be added to the end in the order encountered.
 */
utils.sortCategoryBy = function sortCategoryBy(categories, sortOrder) {
  categories.sort(function(a, b) {
    var aIndex = sortOrder.indexOf(utils.normalizeName(a.name));
    var bIndex = sortOrder.indexOf(utils.normalizeName(b.name));

    // default categories not in the section order to the bottom of the stack
    if (aIndex === -1) {
      return 1;
    }
    else if (bIndex === -1) {
      return -1;
    }

    return aIndex - bIndex;
  });
};

/**
 * Asynchronously read a list of glob pattern files and pass the list of files to
 * be read. Maintains file order.
 *
 * @param {string[]} patterns - List of glob pattern files.
 * @param {function} callback - Callback to execute for each read file.
 * @returns {Promise}
 */
utils.readFileGlobs = function readFileGlobs(patterns, callback) {
  patterns = (!Array.isArray(patterns) ? [patterns] : patterns);
  var promises = [];

  patterns.forEach(function(pattern) {

    promises.push(new Promise(function(resolve, reject) {
      glob(pattern, function(err, files) {
        if (err) {
          reject(err);
        }

        if (files.length === 0) {
          console.warn('pattern "' + pattern + '" does not match any file');
        }

        resolve(files);
      });
    }));

  });

  return new Promise(function(resolve, reject) {
    Promise.all(promises).then(function(fileList) {
      promises.length = 0;

      fileList.forEach(function(files) {
        promises.push(utils.readFiles(files, callback));
      });

      Promise.all(promises).then(function() {
        resolve();
      })
      .catch(function(err) {
        reject(err);
      });
    });
  })
  .catch(function(err) {
    throw err;
  });
};

/**
 * Asynchronously read a list of files and call the callback function for each of
 * them. Maintains file order.
 *
 * @param {string[]} patterns - List of glob pattern files.
 * @param {function} callback - Callback to execute for each read file.
 * @returns {Promise}
 */
utils.readFiles = function readFiles(files, callback) {
  if (!files || files.length === 0) {
    return Promise.resolve();
  }

  files = (!Array.isArray(files) ? [files] : files);
  var promises = [];

  files.forEach(function(file) {

    promises.push(new Promise(function(resolve, reject) {
      fs.readFile(file, 'utf8', function(err, data) {
        if (err) {
          reject(err);
        }

        resolve([data, file]);
      });
    }));

  });

  return Promise.all(promises).then(function(files) {
    files.forEach(function(data) {
      callback.apply(null, data);
    });
  })
  .catch(function(err) {
    throw err;
  });
};

/**
 * Workaround for polymer issue: https://github.com/Polymer/polymer/issues/1276.
 *
 * @param {string} stylesheetData - Actual stylesheet text
 * @returns {string} Corrected stylesheet text
 */
utils.fixSVGIssue = function fixSVGIssue(stylesheetData) {
  return stylesheetData.replace(svgRegex, function replacer(match) {
    return match.replace(/'/g, '%27');
  });
};

module.exports = utils;
<commit_msg>fix(utils): fix bug that read files out of order<commit_after>/*jshint -W083 */

var fs = require('fs');
var glob = require('glob');

var svgRegex = /url\("data:image\/svg\+xml;.*?"\)/gi;
var whiteSpaceRegex = /\s/g;
var utils = {};

/**
 * Get an id by hyphen separating the name.
 *
 * @param {string} str - String to hyphenate.
 * @returns {string}
 */
utils.getId = function getId(str) {
  return encodeURIComponent(str.toLowerCase().replace(whiteSpaceRegex, '-'));
};

/**
 * Normalize a name.
 *
 * @param {string} name - Name to normalize.
 * @returns string
 */
utils.normalizeName = function normalizeName(name) {
  return name.toLowerCase();
};

/**
 * Generate the sort order of pages and sections.
 *
 * @param {object} context - Context to pass to handlebars.
 * @param {string[]} [context.pageOrder=[]] - Order that the pages should be sorted by.
 * @param {object[]} context.pages - List of pages.
 * @param {object[]} sortOrder - Array of objects of page name to array of section names.
 */
utils.generateSortOrder = function generateSortOrder(context, sortOrder) {
  context.pageOrder = context.pageOrder || [];

  // sortOrder can be:
  // sort just pages: array of page names
  // sort just sections: object of page names to array of section names
  // sort both: array of objects of page names to array of section names
  // sort some: array of objects and strings
  if (!Array.isArray(sortOrder)) {
    sortOrder = [sortOrder];
  }

  sortOrder.forEach(function(value, index) {
    // string page name
    if (typeof value === 'string') {
      context.pageOrder.push(utils.normalizeName(value));
      return;
    }

    if (Array.isArray(value)) {
      value.forEach(function(name) {
        context.pageOrder.push(utils.normalizeName(name));
      });
      return;
    }

    // object of string page name to array of section names
    for (var prop in value) {
      if (!value.hasOwnProperty(prop)) {
        continue;
      }

      context.pageOrder.push(utils.normalizeName(prop));

      if (context.pages[prop]) {
        context.pages[prop].sectionOrder = context.pages[prop].sectionOrder || [];

        // sections
        value[prop].forEach(function(val) {
          context.pages[prop].sectionOrder.push(utils.normalizeName(val));
        });
      }
    }
  });
};

/**
 * Sort a list of categories (pages, sections) by a given array.
 *
 * @param {object[]} categories - List of categories.
 * @param {object} sortOrder - List of category names in the order they should be sorted. Any category not listed will be added to the end in the order encountered.
 */
utils.sortCategoryBy = function sortCategoryBy(categories, sortOrder) {
  categories.sort(function(a, b) {
    var aIndex = sortOrder.indexOf(utils.normalizeName(a.name));
    var bIndex = sortOrder.indexOf(utils.normalizeName(b.name));

    // default categories not in the section order to the bottom of the stack
    if (aIndex === -1) {
      return 1;
    }
    else if (bIndex === -1) {
      return -1;
    }

    return aIndex - bIndex;
  });
};

/**
 * Asynchronously read a list of glob pattern files and pass the list of files to
 * be read. Maintains file order.
 *
 * @param {string[]} patterns - List of glob pattern files.
 * @param {function} callback - Callback to execute for each read file.
 * @returns {Promise}
 */
utils.readFileGlobs = function readFileGlobs(patterns, callback) {
  patterns = (!Array.isArray(patterns) ? [patterns] : patterns);
  var promises = [];

  patterns.forEach(function(pattern) {

    promises.push(new Promise(function(resolve, reject) {
      glob(pattern, function(err, files) {
        if (err) {
          reject(err);
        }

        if (files.length === 0) {
          console.warn('pattern "' + pattern + '" does not match any file');
        }

        resolve(files);
      });
    }));

  });

  return new Promise(function(resolve, reject) {
    Promise.all(promises).then(function(fileList) {
      promises.length = 0;

      fileList.forEach(function(files) {
        promises.push(new Promise(function(resolve, reject) {
          utils.readFiles(files, function(data, file) {
            resolve([data, file]);
          });
        }));
      });

      Promise.all(promises).then(function(files) {
        files.forEach(function(data) {
          callback.apply(null, data);
        });
        resolve();
      })
      .catch(function(err) {
        reject(err);
      });
    });
  })
  .catch(function(err) {
    throw err;
  });
};

/**
 * Asynchronously read a list of files and call the callback function for each of
 * them. Maintains file order.
 *
 * @param {string[]} patterns - List of glob pattern files.
 * @param {function} callback - Callback to execute for each read file.
 * @returns {Promise}
 */
utils.readFiles = function readFiles(files, callback) {
  if (!files || files.length === 0) {
    return Promise.resolve();
  }

  files = (!Array.isArray(files) ? [files] : files);
  var promises = [];

  files.forEach(function(file) {

    promises.push(new Promise(function(resolve, reject) {
      fs.readFile(file, 'utf8', function(err, data) {
        if (err) {
          reject(err);
        }

        resolve([data, file]);
      });
    }));

  });

  return Promise.all(promises).then(function(files) {
    files.forEach(function(data) {
      callback.apply(null, data);
    });
  })
  .catch(function(err) {
    throw err;
  });
};

/**
 * Workaround for polymer issue: https://github.com/Polymer/polymer/issues/1276.
 *
 * @param {string} stylesheetData - Actual stylesheet text
 * @returns {string} Corrected stylesheet text
 */
utils.fixSVGIssue = function fixSVGIssue(stylesheetData) {
  return stylesheetData.replace(svgRegex, function replacer(match) {
    return match.replace(/'/g, '%27');
  });
};

module.exports = utils;
<|endoftext|>