<commit_before>/*
 * Swipe 2.0
 *
 * Brad Birdsall
 * Copyright 2013, MIT License
 *
*/

function Swipe(container, options) {

  "use strict";

  // utilities
  var noop = function() {}; // simple no operation function
  var offloadFn = function(fn) { setTimeout(fn || noop, 0) }; // offload a functions execution

  // check browser capabilities
  var browser = {
    addEventListener: !!window.addEventListener,
    touch: ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch,
    transitions: (function(temp) {
      var props = ['transitionProperty', 'WebkitTransition', 'MozTransition', 'OTransition', 'msTransition'];
      for ( var i in props ) if (temp.style[ props[i] ] !== undefined) return true;
      return false;
    })(document.createElement('swipe'))
  };

  // quit if no root element
  if (!container) return;
  var element = container.children[0];
  var slides, slidePos, width, length;
  options = options || {};
  var index = parseInt(options.startSlide, 10) || 0;
  var speed = options.speed || 300;
  options.continuous = options.continuous !== undefined ? options.continuous : true;

  function setup() {

    // cache slides
    slides = element.children;
    length = slides.length;

    // set continuous to false if only one slide
    if (slides.length < 2) options.continuous = false;

    //special case if two slides
    if (browser.transitions && options.continuous && slides.length < 3) {
      element.appendChild(slides[0].cloneNode(true));
      element.appendChild(element.children[1].cloneNode(true));
      slides = element.children;
    }

    // create an array to store current positions of each slide
    slidePos = new Array(slides.length);

    // determine width of each slide
    width = container.getBoundingClientRect().width || container.offsetWidth;

    element.style.width = (slides.length * width) + 'px';

    // stack elements
    var pos = slides.length;
    while(pos--) {

      var slide = slides[pos];

      slide.style.width = width + 'px';
      slide.setAttribute('data-index', pos);

      if (browser.transitions) {
        slide.style.left = (pos * -width) + 'px';
        move(pos, index > pos ? -width : (index < pos ? width : 0), 0);
      }

    }

    // reposition elements before and after index
    if (options.continuous && browser.transitions) {
      move(circle(index-1), -width, 0);
      move(circle(index+1), width, 0);
    }

    if (!browser.transitions) element.style.left = (index * -width) + 'px';

    container.style.visibility = 'visible';

  }

  function prev() {

    if (options.continuous) slide(index-1);
    else if (index) slide(index-1);

  }

  function next() {

    if (options.continuous) slide(index+1);
    else if (index < slides.length - 1) slide(index+1);

  }

  function circle(index) {

    // a simple positive modulo using slides.length
    return (slides.length + (index % slides.length)) % slides.length;

  }

  function slide(to, slideSpeed) {

    // do nothing if already on requested slide
    if (index == to) return;

    if (browser.transitions) {

      var direction = Math.abs(index-to) / (index-to); // 1: backward, -1: forward

      // get the actual position of the slide
      if (options.continuous) {
        var natural_direction = direction;
        direction = -slidePos[circle(to)] / width;

        // if going forward but to < index, use to = slides.length + to
        // if going backward but to > index, use to = -slides.length + to
        if (direction !== natural_direction) to =  -direction * slides.length + to;

      }

      var diff = Math.abs(index-to) - 1;

      // move all the slides between index and to in the right direction
      while (diff--) move( circle((to > index ? to : index) - diff - 1), width * direction, 0);

      to = circle(to);

      move(index, width * direction, slideSpeed || speed);
      move(to, 0, slideSpeed || speed);

      if (options.continuous) move(circle(to - direction), -(width * direction), 0); // we need to get the next in place

    } else {

      to = circle(to);
      animate(index * -width, to * -width, slideSpeed || speed);
      //no fallback for a circular continuous if the browser does not accept transitions
    }

    index = to;
    offloadFn(options.callback && options.callback(index, slides[index]));
  }

  function move(index, dist, speed) {

    translate(index, dist, speed);
    slidePos[index] = dist;

  }

  function translate(index, dist, speed) {

    var slide = slides[index];
    var style = slide && slide.style;

    if (!style) return;

    style.webkitTransitionDuration =
    style.MozTransitionDuration =
    style.msTransitionDuration =
    style.OTransitionDuration =
    style.transitionDuration = speed + 'ms';

    style.webkitTransform = 'translate(' + dist + 'px,0)' + 'translateZ(0)';
    style.msTransform =
    style.MozTransform =
    style.OTransform = 'translateX(' + dist + 'px)';

  }

  function animate(from, to, speed) {

    // if not an animation, just reposition
    if (!speed) {

      element.style.left = to + 'px';
      return;

    }

    var start = +new Date;

    var timer = setInterval(function() {

      var timeElap = +new Date - start;

      if (timeElap > speed) {

        element.style.left = to + 'px';

        if (delay) begin();

        options.transitionEnd && options.transitionEnd.call(event, index, slides[index]);

        clearInterval(timer);
        return;

      }

      element.style.left = (( (to - from) * (Math.floor((timeElap / speed) * 100) / 100) ) + from) + 'px';

    }, 4);

  }

  // setup auto slideshow
  var delay = options.auto || 0;
  var interval;

  function begin() {

    interval = setTimeout(next, delay);

  }

  function stop() {

    delay = 0;
    clearTimeout(interval);

  }

  // setup initial vars
  var start = {};
  var delta = {};
  var isScrolling;

  // setup event capturing
  var events = {

    handleEvent: function(event) {

      switch (event.type) {
        case 'touchstart': this.start(event); break;
        case 'touchmove': this.move(event); break;
        case 'touchend': offloadFn(this.end(event)); break;
        case 'webkitTransitionEnd':
        case 'msTransitionEnd':
        case 'oTransitionEnd':
        case 'otransitionend':
        case 'transitionend': offloadFn(this.transitionEnd(event)); break;
        case 'resize': offloadFn(setup.call()); break;
      }

      if (options.stopPropagation) event.stopPropagation();

    },
    start: function(event) {

      var touches = event.touches[0];

      // measure start values
      start = {

        // get initial touch coords
        x: touches.pageX,
        y: touches.pageY,

        // store time to determine touch duration
        time: +new Date

      };

      // used for testing first move event
      isScrolling = undefined;

      // reset delta and end measurements
      delta = {};

      // attach touchmove and touchend listeners
      element.addEventListener('touchmove', this, false);
      element.addEventListener('touchend', this, false);

    },
    move: function(event) {

      // ensure swiping with one touch and not pinching
      if ( event.touches.length > 1 || event.scale && event.scale !== 1) return

      if (options.disableScroll) event.preventDefault();

      var touches = event.touches[0];

      // measure change in x and y
      delta = {
        x: touches.pageX - start.x,
        y: touches.pageY - start.y
      }

      // determine if scrolling test has run - one time test
      if ( typeof isScrolling == 'undefined') {
        isScrolling = !!( isScrolling || Math.abs(delta.x) < Math.abs(delta.y) );
      }

      // if user is not trying to scroll vertically
      if (!isScrolling) {

        // prevent native scrolling
        event.preventDefault();

        // stop slideshow
        stop();

        // increase resistance if first or last slide
        if (options.continuous) { // we don't add resistance at the end

          translate(circle(index-1), delta.x + slidePos[circle(index-1)], 0);
          translate(index, delta.x + slidePos[index], 0);
          translate(circle(index+1), delta.x + slidePos[circle(index+1)], 0);

        } else {

          delta.x =
            delta.x /
              ( (!index && delta.x > 0               // if first slide and sliding left
                || index == slides.length - 1        // or if last slide and sliding right
                && delta.x < 0                       // and if sliding at all
              ) ?
              ( Math.abs(delta.x) / width + 1 )      // determine resistance level
              : 1 );                                 // no resistance if false

          // translate 1:1
          translate(index-1, delta.x + slidePos[index-1], 0);
          translate(index, delta.x + slidePos[index], 0);
          translate(index+1, delta.x + slidePos[index+1], 0);
        }

      }

    },
    end: function(event) {

      // measure duration
      var duration = +new Date - start.time;

      // determine if slide attempt triggers next/prev slide
      var isValidSlide =
            Number(duration) < 250               // if slide duration is less than 250ms
            && Math.abs(delta.x) > 20            // and if slide amt is greater than 20px
            || Math.abs(delta.x) > width/2;      // or if slide amt is greater than half the width

      // determine if slide attempt is past start and end
      var isPastBounds =
            !index && delta.x > 0                            // if first slide and slide amt is greater than 0
            || index == slides.length - 1 && delta.x < 0;    // or if last slide and slide amt is less than 0

      if (options.continuous) isPastBounds = false;

      // determine direction of swipe (true:right, false:left)
      var direction = delta.x < 0;

      // if not scrolling vertically
      if (!isScrolling) {

        if (isValidSlide && !isPastBounds) {

          if (direction) {

            if (options.continuous) { // we need to get the next in this direction in place

              move(circle(index-1), -width, 0);
              move(circle(index+2), width, 0);

            } else {
              move(index-1, -width, 0);
            }

            move(index, slidePos[index]-width, speed);
            move(circle(index+1), slidePos[circle(index+1)]-width, speed);
            index = circle(index+1);

          } else {
            if (options.continuous) { // we need to get the next in this direction in place

              move(circle(index+1), width, 0);
              move(circle(index-2), -width, 0);

            } else {
              move(index+1, width, 0);
            }

            move(index, slidePos[index]+width, speed);
            move(circle(index-1), slidePos[circle(index-1)]+width, speed);
            index = circle(index-1);

          }

          options.callback && options.callback(index, slides[index]);

        } else {

          if (options.continuous) {

            move(circle(index-1), -width, speed);
            move(index, 0, speed);
            move(circle(index+1), width, speed);

          } else {

            move(index-1, -width, speed);
            move(index, 0, speed);
            move(index+1, width, speed);
          }

        }

      }

      // kill touchmove and touchend event listeners until touchstart called again
      element.removeEventListener('touchmove', events, false)
      element.removeEventListener('touchend', events, false)

    },
    transitionEnd: function(event) {

      if (parseInt(event.target.getAttribute('data-index'), 10) == index) {

        if (delay) begin();

        options.transitionEnd && options.transitionEnd.call(event, index, slides[index]);

      }

    }

  }

  // trigger setup
  setup();

  // start auto slideshow if applicable
  if (delay) begin();

  // add event listeners
  if (browser.addEventListener) {

    // set touchstart event on element
    if (browser.touch) element.addEventListener('touchstart', events, false);

    if (browser.transitions) {
      element.addEventListener('webkitTransitionEnd', events, false);
      element.addEventListener('msTransitionEnd', events, false);
      element.addEventListener('oTransitionEnd', events, false);
      element.addEventListener('otransitionend', events, false);
      element.addEventListener('transitionend', events, false);
    }

    // set resize event on window
    window.addEventListener('resize', events, false);

  } else {

    window.onresize = function () { setup() }; // to play nice with old IE

  }

  // expose the Swipe API
  return {
    setup: function() {

      setup();

    },
    slide: function(to, speed) {

      // cancel slideshow
      stop();

      slide(to, speed);

    },
    prev: function() {

      // cancel slideshow
      stop();

      prev();

    },
    next: function() {

      // cancel slideshow
      stop();

      next();

    },
    getPos: function() {

      // return current index position
      return index;

    },
    getNumSlides: function() {

      // return total number of slides
      return length;
    },
    kill: function() {

      // cancel slideshow
      stop();

      // reset element
      element.style.width = 'auto';
      element.style.left = 0;

      // reset slides
      var pos = slides.length;
      while(pos--) {

        var slide = slides[pos];
        slide.style.width = '100%';
        slide.style.left = 0;

        if (browser.transitions) translate(pos, 0, 0);

      }

      // removed event listeners
      if (browser.addEventListener) {

        // remove current event listeners
        element.removeEventListener('touchstart', events, false);
        element.removeEventListener('webkitTransitionEnd', events, false);
        element.removeEventListener('msTransitionEnd', events, false);
        element.removeEventListener('oTransitionEnd', events, false);
        element.removeEventListener('otransitionend', events, false);
        element.removeEventListener('transitionend', events, false);
        window.removeEventListener('resize', events, false);

      }
      else {

        window.onresize = null;

      }

    }
  }

}

if ( window.jQuery || window.Zepto ) {
  (function($) {
    $.fn.Swipe = function(params) {
      return this.each(function() {
        $(this).data('Swipe', new Swipe($(this)[0], params));
      });
    }
  })( window.jQuery || window.Zepto )
}
<commit_msg>tidy JS library usage by making a variable.<commit_after>/*
 * Swipe 2.0
 *
 * Brad Birdsall
 * Copyright 2013, MIT License
 *
*/

function Swipe(container, options) {

  "use strict";

  // utilities
  var noop = function() {}; // simple no operation function
  var offloadFn = function(fn) { setTimeout(fn || noop, 0) }; // offload a functions execution
  var jsLib = window.jQuery || window.Zepto;  // jQuery or Zepto

  // check browser capabilities
  var browser = {
    addEventListener: !!window.addEventListener,
    touch: ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch,
    transitions: (function(temp) {
      var props = ['transitionProperty', 'WebkitTransition', 'MozTransition', 'OTransition', 'msTransition'];
      for ( var i in props ) if (temp.style[ props[i] ] !== undefined) return true;
      return false;
    })(document.createElement('swipe'))
  };

  // quit if no root element
  if (!container) return;
  var element = container.children[0];
  var slides, slidePos, width, length;
  options = options || {};
  var index = parseInt(options.startSlide, 10) || 0;
  var speed = options.speed || 300;
  options.continuous = options.continuous !== undefined ? options.continuous : true;

  function setup() {

    // cache slides
    slides = element.children;
    length = slides.length;

    // set continuous to false if only one slide
    if (slides.length < 2) options.continuous = false;

    //special case if two slides
    if (browser.transitions && options.continuous && slides.length < 3) {
      element.appendChild(slides[0].cloneNode(true));
      element.appendChild(element.children[1].cloneNode(true));
      slides = element.children;
    }

    // create an array to store current positions of each slide
    slidePos = new Array(slides.length);

    // determine width of each slide
    width = container.getBoundingClientRect().width || container.offsetWidth;

    element.style.width = (slides.length * width) + 'px';

    // stack elements
    var pos = slides.length;
    while(pos--) {

      var slide = slides[pos];

      slide.style.width = width + 'px';
      slide.setAttribute('data-index', pos);

      if (browser.transitions) {
        slide.style.left = (pos * -width) + 'px';
        move(pos, index > pos ? -width : (index < pos ? width : 0), 0);
      }

    }

    // reposition elements before and after index
    if (options.continuous && browser.transitions) {
      move(circle(index-1), -width, 0);
      move(circle(index+1), width, 0);
    }

    if (!browser.transitions) element.style.left = (index * -width) + 'px';

    container.style.visibility = 'visible';

  }

  function prev() {

    if (options.continuous) slide(index-1);
    else if (index) slide(index-1);

  }

  function next() {

    if (options.continuous) slide(index+1);
    else if (index < slides.length - 1) slide(index+1);

  }

  function circle(index) {

    // a simple positive modulo using slides.length
    return (slides.length + (index % slides.length)) % slides.length;

  }

  function slide(to, slideSpeed) {

    // do nothing if already on requested slide
    if (index == to) return;

    if (browser.transitions) {

      var direction = Math.abs(index-to) / (index-to); // 1: backward, -1: forward

      // get the actual position of the slide
      if (options.continuous) {
        var natural_direction = direction;
        direction = -slidePos[circle(to)] / width;

        // if going forward but to < index, use to = slides.length + to
        // if going backward but to > index, use to = -slides.length + to
        if (direction !== natural_direction) to =  -direction * slides.length + to;

      }

      var diff = Math.abs(index-to) - 1;

      // move all the slides between index and to in the right direction
      while (diff--) move( circle((to > index ? to : index) - diff - 1), width * direction, 0);

      to = circle(to);

      move(index, width * direction, slideSpeed || speed);
      move(to, 0, slideSpeed || speed);

      if (options.continuous) move(circle(to - direction), -(width * direction), 0); // we need to get the next in place

    } else {

      to = circle(to);
      animate(index * -width, to * -width, slideSpeed || speed);
      //no fallback for a circular continuous if the browser does not accept transitions
    }

    index = to;
    offloadFn(options.callback && options.callback(index, slides[index]));
  }

  function move(index, dist, speed) {

    translate(index, dist, speed);
    slidePos[index] = dist;

  }

  function translate(index, dist, speed) {

    var slide = slides[index];
    var style = slide && slide.style;

    if (!style) return;

    style.webkitTransitionDuration =
    style.MozTransitionDuration =
    style.msTransitionDuration =
    style.OTransitionDuration =
    style.transitionDuration = speed + 'ms';

    style.webkitTransform = 'translate(' + dist + 'px,0)' + 'translateZ(0)';
    style.msTransform =
    style.MozTransform =
    style.OTransform = 'translateX(' + dist + 'px)';

  }

  function animate(from, to, speed) {

    // if not an animation, just reposition
    if (!speed) {

      element.style.left = to + 'px';
      return;

    }

    var start = +new Date;

    var timer = setInterval(function() {

      var timeElap = +new Date - start;

      if (timeElap > speed) {

        element.style.left = to + 'px';

        if (delay) begin();

        options.transitionEnd && options.transitionEnd.call(event, index, slides[index]);

        clearInterval(timer);
        return;

      }

      element.style.left = (( (to - from) * (Math.floor((timeElap / speed) * 100) / 100) ) + from) + 'px';

    }, 4);

  }

  // setup auto slideshow
  var delay = options.auto || 0;
  var interval;

  function begin() {

    interval = setTimeout(next, delay);

  }

  function stop() {

    delay = 0;
    clearTimeout(interval);

  }

  // setup initial vars
  var start = {};
  var delta = {};
  var isScrolling;

  // setup event capturing
  var events = {

    handleEvent: function(event) {

      switch (event.type) {
        case 'touchstart': this.start(event); break;
        case 'touchmove': this.move(event); break;
        case 'touchend': offloadFn(this.end(event)); break;
        case 'webkitTransitionEnd':
        case 'msTransitionEnd':
        case 'oTransitionEnd':
        case 'otransitionend':
        case 'transitionend': offloadFn(this.transitionEnd(event)); break;
        case 'resize': offloadFn(setup.call()); break;
      }

      if (options.stopPropagation) event.stopPropagation();

    },
    start: function(event) {

      var touches = event.touches[0];

      // measure start values
      start = {

        // get initial touch coords
        x: touches.pageX,
        y: touches.pageY,

        // store time to determine touch duration
        time: +new Date

      };

      // used for testing first move event
      isScrolling = undefined;

      // reset delta and end measurements
      delta = {};

      // attach touchmove and touchend listeners
      element.addEventListener('touchmove', this, false);
      element.addEventListener('touchend', this, false);

    },
    move: function(event) {

      // ensure swiping with one touch and not pinching
      if ( event.touches.length > 1 || event.scale && event.scale !== 1) return

      if (options.disableScroll) event.preventDefault();

      var touches = event.touches[0];

      // measure change in x and y
      delta = {
        x: touches.pageX - start.x,
        y: touches.pageY - start.y
      }

      // determine if scrolling test has run - one time test
      if ( typeof isScrolling == 'undefined') {
        isScrolling = !!( isScrolling || Math.abs(delta.x) < Math.abs(delta.y) );
      }

      // if user is not trying to scroll vertically
      if (!isScrolling) {

        // prevent native scrolling
        event.preventDefault();

        // stop slideshow
        stop();

        // increase resistance if first or last slide
        if (options.continuous) { // we don't add resistance at the end

          translate(circle(index-1), delta.x + slidePos[circle(index-1)], 0);
          translate(index, delta.x + slidePos[index], 0);
          translate(circle(index+1), delta.x + slidePos[circle(index+1)], 0);

        } else {

          delta.x =
            delta.x /
              ( (!index && delta.x > 0               // if first slide and sliding left
                || index == slides.length - 1        // or if last slide and sliding right
                && delta.x < 0                       // and if sliding at all
              ) ?
              ( Math.abs(delta.x) / width + 1 )      // determine resistance level
              : 1 );                                 // no resistance if false

          // translate 1:1
          translate(index-1, delta.x + slidePos[index-1], 0);
          translate(index, delta.x + slidePos[index], 0);
          translate(index+1, delta.x + slidePos[index+1], 0);
        }

      }

    },
    end: function(event) {

      // measure duration
      var duration = +new Date - start.time;

      // determine if slide attempt triggers next/prev slide
      var isValidSlide =
            Number(duration) < 250               // if slide duration is less than 250ms
            && Math.abs(delta.x) > 20            // and if slide amt is greater than 20px
            || Math.abs(delta.x) > width/2;      // or if slide amt is greater than half the width

      // determine if slide attempt is past start and end
      var isPastBounds =
            !index && delta.x > 0                            // if first slide and slide amt is greater than 0
            || index == slides.length - 1 && delta.x < 0;    // or if last slide and slide amt is less than 0

      if (options.continuous) isPastBounds = false;

      // determine direction of swipe (true:right, false:left)
      var direction = delta.x < 0;

      // if not scrolling vertically
      if (!isScrolling) {

        if (isValidSlide && !isPastBounds) {

          if (direction) {

            if (options.continuous) { // we need to get the next in this direction in place

              move(circle(index-1), -width, 0);
              move(circle(index+2), width, 0);

            } else {
              move(index-1, -width, 0);
            }

            move(index, slidePos[index]-width, speed);
            move(circle(index+1), slidePos[circle(index+1)]-width, speed);
            index = circle(index+1);

          } else {
            if (options.continuous) { // we need to get the next in this direction in place

              move(circle(index+1), width, 0);
              move(circle(index-2), -width, 0);

            } else {
              move(index+1, width, 0);
            }

            move(index, slidePos[index]+width, speed);
            move(circle(index-1), slidePos[circle(index-1)]+width, speed);
            index = circle(index-1);

          }

          options.callback && options.callback(index, slides[index]);

        } else {

          if (options.continuous) {

            move(circle(index-1), -width, speed);
            move(index, 0, speed);
            move(circle(index+1), width, speed);

          } else {

            move(index-1, -width, speed);
            move(index, 0, speed);
            move(index+1, width, speed);
          }

        }

      }

      // kill touchmove and touchend event listeners until touchstart called again
      element.removeEventListener('touchmove', events, false)
      element.removeEventListener('touchend', events, false)

    },
    transitionEnd: function(event) {

      if (parseInt(event.target.getAttribute('data-index'), 10) == index) {

        if (delay) begin();

        options.transitionEnd && options.transitionEnd.call(event, index, slides[index]);

      }

    }

  }

  // trigger setup
  setup();

  // start auto slideshow if applicable
  if (delay) begin();

  // add event listeners
  if (browser.addEventListener) {

    // set touchstart event on element
    if (browser.touch) element.addEventListener('touchstart', events, false);

    if (browser.transitions) {
      element.addEventListener('webkitTransitionEnd', events, false);
      element.addEventListener('msTransitionEnd', events, false);
      element.addEventListener('oTransitionEnd', events, false);
      element.addEventListener('otransitionend', events, false);
      element.addEventListener('transitionend', events, false);
    }

    // set resize event on window
    window.addEventListener('resize', events, false);

  } else {

    window.onresize = function () { setup() }; // to play nice with old IE

  }

  // expose the Swipe API
  return {
    setup: function() {

      setup();

    },
    slide: function(to, speed) {

      // cancel slideshow
      stop();

      slide(to, speed);

    },
    prev: function() {

      // cancel slideshow
      stop();

      prev();

    },
    next: function() {

      // cancel slideshow
      stop();

      next();

    },
    getPos: function() {

      // return current index position
      return index;

    },
    getNumSlides: function() {

      // return total number of slides
      return length;
    },
    kill: function() {

      // cancel slideshow
      stop();

      // reset element
      element.style.width = 'auto';
      element.style.left = 0;

      // reset slides
      var pos = slides.length;
      while(pos--) {

        var slide = slides[pos];
        slide.style.width = '100%';
        slide.style.left = 0;

        if (browser.transitions) translate(pos, 0, 0);

      }

      // removed event listeners
      if (browser.addEventListener) {

        // remove current event listeners
        element.removeEventListener('touchstart', events, false);
        element.removeEventListener('webkitTransitionEnd', events, false);
        element.removeEventListener('msTransitionEnd', events, false);
        element.removeEventListener('oTransitionEnd', events, false);
        element.removeEventListener('otransitionend', events, false);
        element.removeEventListener('transitionend', events, false);
        window.removeEventListener('resize', events, false);

      }
      else {

        window.onresize = null;

      }

    }
  }

}

if ( jsLib ) {
  (function($) {
    $.fn.Swipe = function(params) {
      return this.each(function() {
        $(this).data('Swipe', new Swipe($(this)[0], params));
      });
    }
  })( jsLib )
}
<|endoftext|>


<commit_before>var lame = require('./')
  , fs = require('fs')
  , Parser = require('./lib/parser')
  , BlockStream = require('block-stream')

var f = fs.createReadStream('pigs.f.s16le.acodec.pcm_s16le.ar.44100.ac.2')
  , encoder = lame.createEncoder()
  //, bs = new BlockStream(s, { nopad: true })

f.pipe(encoder);
//encoder.pipe(bs);

var parser = new Parser();
encoder.pipe(parser);

parser.on('header', function (b, meta) {
  console.error('header:', meta);
  process.stdout.write(b);
}).on('frame', function (b) {
  console.error('frame');
  process.stdout.write(b);
});

/*bs.on('data', function (frame) {

  console.error('got frame')
  console.error(frame.length)
  console.error(0, frame.slice(0, 4))
});*/
<commit_msg>Can't use BlockStream.<commit_after>var lame = require('./')
  , fs = require('fs')
  , Parser = require('./lib/parser')

var f = fs.createReadStream('pigs.f.s16le.acodec.pcm_s16le.ar.44100.ac.2')
  , encoder = lame.createEncoder()

f.pipe(encoder);

var parser = new Parser();
encoder.pipe(parser);

parser.on('header', function (b, meta) {
  console.error('header:', meta);
  process.stdout.write(b);
}).on('frame', function (b) {
  console.error('frame');
  process.stdout.write(b);
});
<|endoftext|>


<commit_before>import React from 'react';
import TestUtils from 'react/lib/ReactTestUtils';
import Container from './index';
import assert from 'assert';

describe('Container', () => {
	// TODO: describe use cases
	const Component = (props) =>
;

	it('should create React component', () => {
		const PContainer = Container(Component, {});

		assert.ok(TestUtils.isElement(<PContainer />), 'Container should be a React component');
		assert.equal(PContainer.displayName, 'ComponentContainer', 'Container should have Component\'s name with suffix');
	});

	it('should create React component if enum is used', () => {
		const PContainer = Container({success: Component}, {});

		assert.ok(TestUtils.isElement(<PContainer />), 'Container should be a React component');
		assert.equal(PContainer.displayName, 'ComponentContainer', 'Container should have Component\'s name with suffix');
	});

	it('should raise an error if no components are specified', () => {
		assert.throws(() => Container({success: null}, {}), /Success, Failure and Pending should be React components/);
		assert.throws(() => Container({}, {}), /Success component should be specified/);
	});

	it('should render Pending element by default', () => {
		const Spinner = () =>
Loading...
;
		const PContainer = Container({success: Component, pending: Spinner}, {});
		const ReactShallow = TestUtils.createRenderer();

		ReactShallow.render(<PContainer />);

		assert.ok(TestUtils.isElementOfType(ReactShallow.getRenderOutput(), Spinner), 'Pending component should be rendered');
	});
});
<commit_msg>fixed tests<commit_after>import React from 'react';
import TestUtils from 'react/lib/ReactTestUtils';
import Container from './index';
import assert from 'assert';

describe('Container', () => {
	// TODO: describe use cases
	const Component = (props) =>
;

	it('should create React component', () => {
		const PContainer = Container.create(Component, {});

		assert.ok(TestUtils.isElement(<PContainer />), 'Container should be a React component');
		assert.equal(PContainer.displayName, 'ComponentContainer', 'Container should have Component\'s name with suffix');
	});

	it('should create React component if enum is used', () => {
		const PContainer = Container.create({success: Component}, {});

		assert.ok(TestUtils.isElement(<PContainer />), 'Container should be a React component');
		assert.equal(PContainer.displayName, 'ComponentContainer', 'Container should have Component\'s name with suffix');
	});

	it('should raise an error if no components are specified', () => {
		assert.throws(() => Container.create({success: null}, {}), /Success, Failure and Pending should be React components/);
		assert.throws(() => Container.create({}, {}), /Success component should be specified/);
	});

	it('should render Pending element by default', () => {
		const Spinner = () =>
Loading...
;
		const PContainer = Container.create({success: Component, pending: Spinner}, {});
		const ReactShallow = TestUtils.createRenderer();

		ReactShallow.render(<PContainer />);

		assert.ok(TestUtils.isElementOfType(ReactShallow.getRenderOutput(), Spinner), 'Pending component should be rendered');
	});
});
<|endoftext|>


<commit_before>describe("constructor", function () {
    it("requires an arguments Object", function () {
        chai.expect(function () {
            new FullScreenMario();
        }).to.throw("No arguments Object given to FullScreenMario.");
    });

    it("requires at least a width and height", function () {
        chai.expect(function () {
            new FullScreenMario({});
        }).to.throw("FullScreenMario requires both width and height.");
    });

    it("runs with a small screen size", function () {
        new FullScreenMario({
            "width": 512,
            "height": 464
        });
    });

    it("runs with a medium screen size", function () {
        new FullScreenMario({
            "width": 1024,
            "height": 768
        });
    });

    it("runs with a large screen size", function () {
        new FullScreenMario({
            "width": 2048,
            "height": 1152
        });
    });
});<commit_msg>Added FullScreenMario var to tests.js<commit_after>var FullScreenMario;

describe("constructor", function () {
    it("requires an arguments Object", function () {
        chai.expect(function () {
            new FullScreenMario();
        }).to.throw("No arguments Object given to FullScreenMario.");
    });

    it("requires at least a width and height", function () {
        chai.expect(function () {
            new FullScreenMario({});
        }).to.throw("FullScreenMario requires both width and height.");
    });

    it("runs with a small screen size", function () {
        FullScreenMario = new FullScreenMario({
            "width": 512,
            "height": 464
        });
    });

    it("runs with a large screen size", function () {
        FullScreenMario = new FullScreenMario({
            "width": 2048,
            "height": 1152
        });
    });
});<|endoftext|>


<commit_before>var sightengine = require('./sightengine')('1234','test');
var assert = require('assert');
var fs = require('fs');
var path = require('path');

describe('test feedback', function() {
  it('should return success', function(done) {
    sightengine.feedback('nudity', 'safe', 'https://sightengine.com/assets/img/examples/example5.jpg').then((result) => {
      done(assert.equal('success', result.status))
    })
  });

  it('should return error', function(done) {
    sightengine.feedback('nudity', 'safe', 'https://sightengine.com/assets/img/examples/example99999.jpg').then((result) => {
      done(assert.equal('failure', result.status))
    })
  });
});

describe('test image moderation', function() {
  it('should return success', function(done) {
    sightengine.check(['nudity', 'type', 'properties','wad','faces', 'celebrities']).set_url('https://sightengine.com/assets/img/examples/example5.jpg').then(function(result) {
      done(assert.equal('success', result.status))
    })
  });

  it('should return success', function(done) {
    sightengine.check(['nudity']).set_url('https://sightengine.com/assets/img/examples/example5.jpg').then(function(result) {
      done(assert.equal('success', result.status))
    })
  });

  it('should return success', function(done) {
    sightengine.check(['nudity', 'type', 'properties','wad','faces', 'celebrities']).set_file(path.resolve(__dirname, 'assets', 'image.jpg')).then(function(result) {
      done(assert.equal('success', result.status))
    })
  });

  it('should return success', function(done) {
    sightengine.check(['celebrities']).set_file(path.resolve(__dirname, 'assets', 'image.jpg')).then(function(result) {
      done(assert.equal('success', result.status))
    })
  });

  it('should return success', function(done) {
    var binaryImage = fs.createReadStream(path.resolve(__dirname, 'assets', 'image.jpg'));

    sightengine.check(['nudity']).set_bytes(binaryImage).then(function(result) {
      done(assert.equal('success', result.status))
    })
  });

  it('should return success', function(done) {
    var binaryImage = fs.createReadStream(path.resolve(__dirname, 'assets', 'image.jpg'));

    sightengine.check(['nudity', 'type', 'properties','wad','faces', 'celebrities']).set_bytes(binaryImage).then(function(result) {
      done(assert.equal('success', result.status))
    })
  });

  it('should return error', function(done) {
    sightengine.check(['nudity','wad','properties','type','faces','celebrities']).set_url('https://sightengine.com/assets/img/examples/example99999.jpg').then(function(result) {
      done(assert.equal('failure', result.status))
    })
  });
});

describe('video moderation', function() {
  it('should return success', function(done) {
    sightengine.check(['nudity','wad','properties','type','face','celebrities']).video('https://sightengine.com/assets/stream/examples/funfair.mp4', 'http://requestb.in/1d097l71').then(function(result) {
      this.timeout(60000);
      done(assert.equal('success', result.status))
    })
  });
});

<commit_msg>use setTimeout in tests.js<commit_after>var sightengine = require('./sightengine')('1234','test');
var assert = require('assert');
var fs = require('fs');
var path = require('path');

describe('test feedback', function() {
  it('should return success', function(done) {
    sightengine.feedback('nudity', 'safe', 'https://sightengine.com/assets/img/examples/example5.jpg').then((result) => {
      done(assert.equal('success', result.status))
    })
  });

  it('should return error', function(done) {
    sightengine.feedback('nudity', 'safe', 'https://sightengine.com/assets/img/examples/example99999.jpg').then((result) => {
      done(assert.equal('failure', result.status))
    })
  });
});

describe('test image moderation', function() {
  it('should return success', function(done) {
    sightengine.check(['nudity', 'type', 'properties','wad','faces', 'celebrities']).set_url('https://sightengine.com/assets/img/examples/example5.jpg').then(function(result) {
      done(assert.equal('success', result.status))
    })
  });

  it('should return success', function(done) {
    sightengine.check(['nudity']).set_url('https://sightengine.com/assets/img/examples/example5.jpg').then(function(result) {
      done(assert.equal('success', result.status))
    })
  });

  it('should return success', function(done) {
    sightengine.check(['nudity', 'type', 'properties','wad','faces', 'celebrities']).set_file(path.resolve(__dirname, 'assets', 'image.jpg')).then(function(result) {
      done(assert.equal('success', result.status))
    })
  });

  it('should return success', function(done) {
    sightengine.check(['celebrities']).set_file(path.resolve(__dirname, 'assets', 'image.jpg')).then(function(result) {
      done(assert.equal('success', result.status))
    })
  });

  it('should return success', function(done) {
    var binaryImage = fs.createReadStream(path.resolve(__dirname, 'assets', 'image.jpg'));

    sightengine.check(['nudity']).set_bytes(binaryImage).then(function(result) {
      done(assert.equal('success', result.status))
    })
  });

  it('should return success', function(done) {
    var binaryImage = fs.createReadStream(path.resolve(__dirname, 'assets', 'image.jpg'));

    sightengine.check(['nudity', 'type', 'properties','wad','faces', 'celebrities']).set_bytes(binaryImage).then(function(result) {
      done(assert.equal('success', result.status))
    })
  });

  it('should return error', function(done) {
    sightengine.check(['nudity','wad','properties','type','faces','celebrities']).set_url('https://sightengine.com/assets/img/examples/example99999.jpg').then(function(result) {
      done(assert.equal('failure', result.status))
    })
  });
});

describe('video moderation', function() {
  it('should return success', function(done) {
    sightengine.check(['nudity','wad','properties','type','face','celebrities']).video('https://sightengine.com/assets/stream/examples/funfair.mp4', 'http://requestb.in/1d097l71').then(function(result) {
      this.timeout(60000);
      setTimeout(done(assert.equal('success', result.status)), 60000);
    })
  });
});

<|endoftext|>


<commit_before>/*global
    Nainwaklet, document, QUnit, jslint
 */
/*jslint
    devel: true
 */

(function () {
    'use strict';

    function loadUrl(assert, url, processResponse) {
        var done = assert.async(),
            random = Math.floor(Math.random() * 1000000),
            requestUrl = url + '?v=' + random,  // prevents caching
            options = {},
            getBody = function (body) {
                return body;
            };

        // HTML files: load as a document, but export to text just after
        // this solves encoding problems
        if (url.match(/\.html?$/)) {
            options = {responseType: 'document'};
            getBody = function (document) {
                return document.documentElement.outerHTML;
            };
        }

        Nainwaklet.testing.ajaxRequest(requestUrl, options, function (response) {
            assert.strictEqual(response.status, 200, 'Loading ' + url);
            processResponse(getBody(response.body));
            done();
        });
    }

    /*
    QUnit.test('createApplication', function (assert) {
        assert.ok(Nainwaklet.createApplication, 'Nainwaklet should have an "createApplication" function');
    });
    */

    QUnit.test('pages', function (assert) {
        var pages = Nainwaklet.testing.pages;
        assert.ok(pages, 'Nainwaklet.pages available');
        assert.ok(pages.detect, 'Get page by name');
        assert.strictEqual(pages.getByUrl('http://www.nainwak.com/jeu/detect.php'), pages.detect, 'Get page by url');
    });

    QUnit.test('detect page', function (assert) {
        var detect = Nainwaklet.testing.pages.detect;

        loadUrl(assert, 'fixtures/detect.html', function (response) {
            var info = detect.analyze(response);

            console.log(info);
            assert.deepEqual(info.position, [13, 5], 'Position');
            assert.strictEqual(info.monde, 'Monde des sadiques', 'Monde');

            var nains = info.nains;
            assert.strictEqual(nains.length, 3, 'Nombre de nains');

            // TODO: add more tests about nains
            // ["33966", "avatar_guilde/41ddb8ad2c2be408e27352accf1cc0b6559466bb.png", "Le PheniX", '[Gnouille] [#!]', "13799", "2", "Diablotin(e)", "0", "13", "5", ""Le PheniX est un oiseau qui symbolise l'immortalité et la résurrection." A quoi bon me tuer ?!?", "o", "", "0"];
            assert.deepEqual(nains[0], {
                id: 33966,
                nom: "Le PheniX",
                image: "http://www.nainwak.com/images/avatar_guilde/41ddb8ad2c2be408e27352accf1cc0b6559466bb.png",
                description: "\"Le PheniX est un oiseau qui symbolise l'immortalité et la résurrection.\" A quoi bon me tuer ?!?",
                position: [13, 5],
                cote: "sadique",
                rang: "Diablotin(e)",
                barbe: 137.99,
                guilde: {
                    nom: "#!",
                    couleur: "#91005D"
                }
            }, 'Nain 1');

            // ["33924", "avatar/perso/dab064da974199a53f0e22527f901d523e8869b3.png", "Bourinain", '[G-NOUILLE#sNOUFFF]', "10314", "2", "Cancre (nain-culte)", "0", "13", "5", "Description", "o", "", "0"];
            assert.deepEqual(nains[1], {
                id: 33924,
                nom: "Nainkomp'",
                image: "http://www.nainwak.com/images/avatar/perso/dab064da974199a53f0e22527f901d523e8869b3.png",
                description: "Description",
                position: [14, 5],
                cote: "sadique",
                rang: "Cancre (nain-culte)",
                barbe: 103.14
            }, 'Nain 2');

            // ["71985", "avatar/choix/TOsmuf4.gif", "Bimme65", '', "0", "3", "Rampant Nain-déci", "2", "13", "6", "Bimme65", "", "", "0"];
            assert.deepEqual(nains[2], {
                id: 71985,
                nom: "Bimme65",
                image: "http://www.nainwak.com/images/avatar/choix/TOsmuf4.gif",
                description: "Bimme65",
                position: [13, 6],
                cote: "rampant",
                rang: "Rampant Nain-déci",
                barbe: 0
            }, 'Nain 3');

            var objets = info.objets;
            assert.strictEqual(nains.length, 3, "Nombre d'objets");

            // [3613899, "objets/jouetkinder2_2.gif", "Surprise de Kine d'Heure", 1, 13, 6, "INUTILE", 1271419];
            assert.deepEqual(objets[0], {
                id: 3613899,
                nom: "Surprise de Kine d'Heure",
                image: "http://www.nainwak.com/images/objets/jouetkinder2_2.gif",
                categorie: "inutile",
                position: [13, 6],
                poussiere: 1271419
            }, 'Objet 1');

            //tabobjet[2] = [3613897, "objets/banane_sauteuse.gif", "Banane sauteuse", 1, 13, 6, "VEHICULE", 1271419];
            assert.deepEqual(objets[1], {
                id: 3613897,
                nom: "Banane sauteuse",
                image: "http://www.nainwak.com/images/objets/banane_sauteuse.gif",
                categorie: "vehicule",
                position: [13, 6],
                poussiere: 1271419
            }, 'Objet 2');

            //tabobjet[3] = [3613896, "objets/naindiana.gif", "Panoplie de Naindiana Jones", 2, 13, 7, "RUNE", 1271419];
            assert.deepEqual(objets[2], {
                id: 3613896,
                nom: "Panoplie de Naindiana Jones",
                image: "http://www.nainwak.com/images/objets/naindiana.gif",
                categorie: "rune",
                position: [13, 7],
                poussiere: 1271419
            }, 'Objet 3');
        });
    });

    QUnit.test('JSLint', function (assert) {
        function formatWarnings(analysis, source) {
            var sourceLines = source.split(/\r?\n/g),
                warnings = [];

            analysis.warnings.forEach(function (warning) {
                var str = '@ line ' + warning.line + ' column ' + warning.column + ': '
                        + warning.message + '\n'
                        + sourceLines[warning.line];
                warnings.push(str);
            });

            return warnings.join('\n\n');
        }

        function checkSource(url) {
            loadUrl(assert, url, function (source) {
                var analysis = jslint(source),
                    warnings = formatWarnings(analysis, source);

                assert.strictEqual(warnings, '', 'JSLinting ' + url);
            });
        }

        checkSource('nainwaklet.js');
        checkSource('tests.js');
    });
}());<commit_msg>extracted a cache busting url function<commit_after>/*global
    Nainwaklet, document, QUnit, jslint
 */
/*jslint
    devel: true
 */

(function () {
    'use strict';

    function cacheBustingUrl(url) {
        var random = Math.floor(Math.random() * 1000000);
        return url + '?v=' + random;  // prevents caching
    }

    function loadUrl(assert, url, processResponse) {
        var done = assert.async(),
            requestUrl = cacheBustingUrl(url),
            options = {},
            getBody = function (body) {
                return body;
            };

        // HTML files: load as a document, but export to text just after
        // this solves encoding problems
        if (url.match(/\.html?$/)) {
            options = {responseType: 'document'};
            getBody = function (document) {
                return document.documentElement.outerHTML;
            };
        }

        Nainwaklet.testing.ajaxRequest(requestUrl, options, function (response) {
            assert.strictEqual(response.status, 200, 'Loading ' + url);
            processResponse(getBody(response.body));
            done();
        });
    }

    /*
    QUnit.test('createApplication', function (assert) {
        assert.ok(Nainwaklet.createApplication, 'Nainwaklet should have an "createApplication" function');
    });
    */

    QUnit.test('pages', function (assert) {
        var pages = Nainwaklet.testing.pages;
        assert.ok(pages, 'Nainwaklet.pages available');
        assert.ok(pages.detect, 'Get page by name');
        assert.strictEqual(pages.getByUrl('http://www.nainwak.com/jeu/detect.php'), pages.detect, 'Get page by url');
    });

    QUnit.test('detect page', function (assert) {
        var detect = Nainwaklet.testing.pages.detect;

        loadUrl(assert, 'fixtures/detect.html', function (response) {
            var info = detect.analyze(response);

            console.log(info);
            assert.deepEqual(info.position, [13, 5], 'Position');
            assert.strictEqual(info.monde, 'Monde des sadiques', 'Monde');

            var nains = info.nains;
            assert.strictEqual(nains.length, 3, 'Nombre de nains');

            // TODO: add more tests about nains
            // ["33966", "avatar_guilde/41ddb8ad2c2be408e27352accf1cc0b6559466bb.png", "Le PheniX", '[Gnouille] [#!]', "13799", "2", "Diablotin(e)", "0", "13", "5", ""Le PheniX est un oiseau qui symbolise l'immortalité et la résurrection." A quoi bon me tuer ?!?", "o", "", "0"];
            assert.deepEqual(nains[0], {
                id: 33966,
                nom: "Le PheniX",
                image: "http://www.nainwak.com/images/avatar_guilde/41ddb8ad2c2be408e27352accf1cc0b6559466bb.png",
                description: "\"Le PheniX est un oiseau qui symbolise l'immortalité et la résurrection.\" A quoi bon me tuer ?!?",
                position: [13, 5],
                cote: "sadique",
                rang: "Diablotin(e)",
                barbe: 137.99,
                guilde: {
                    nom: "#!",
                    couleur: "#91005D"
                }
            }, 'Nain 1');

            // ["33924", "avatar/perso/dab064da974199a53f0e22527f901d523e8869b3.png", "Bourinain", '[G-NOUILLE#sNOUFFF]', "10314", "2", "Cancre (nain-culte)", "0", "13", "5", "Description", "o", "", "0"];
            assert.deepEqual(nains[1], {
                id: 33924,
                nom: "Nainkomp'",
                image: "http://www.nainwak.com/images/avatar/perso/dab064da974199a53f0e22527f901d523e8869b3.png",
                description: "Description",
                position: [14, 5],
                cote: "sadique",
                rang: "Cancre (nain-culte)",
                barbe: 103.14
            }, 'Nain 2');

            // ["71985", "avatar/choix/TOsmuf4.gif", "Bimme65", '', "0", "3", "Rampant Nain-déci", "2", "13", "6", "Bimme65", "", "", "0"];
            assert.deepEqual(nains[2], {
                id: 71985,
                nom: "Bimme65",
                image: "http://www.nainwak.com/images/avatar/choix/TOsmuf4.gif",
                description: "Bimme65",
                position: [13, 6],
                cote: "rampant",
                rang: "Rampant Nain-déci",
                barbe: 0
            }, 'Nain 3');

            var objets = info.objets;
            assert.strictEqual(nains.length, 3, "Nombre d'objets");

            // [3613899, "objets/jouetkinder2_2.gif", "Surprise de Kine d'Heure", 1, 13, 6, "INUTILE", 1271419];
            assert.deepEqual(objets[0], {
                id: 3613899,
                nom: "Surprise de Kine d'Heure",
                image: "http://www.nainwak.com/images/objets/jouetkinder2_2.gif",
                categorie: "inutile",
                position: [13, 6],
                poussiere: 1271419
            }, 'Objet 1');

            //tabobjet[2] = [3613897, "objets/banane_sauteuse.gif", "Banane sauteuse", 1, 13, 6, "VEHICULE", 1271419];
            assert.deepEqual(objets[1], {
                id: 3613897,
                nom: "Banane sauteuse",
                image: "http://www.nainwak.com/images/objets/banane_sauteuse.gif",
                categorie: "vehicule",
                position: [13, 6],
                poussiere: 1271419
            }, 'Objet 2');

            //tabobjet[3] = [3613896, "objets/naindiana.gif", "Panoplie de Naindiana Jones", 2, 13, 7, "RUNE", 1271419];
            assert.deepEqual(objets[2], {
                id: 3613896,
                nom: "Panoplie de Naindiana Jones",
                image: "http://www.nainwak.com/images/objets/naindiana.gif",
                categorie: "rune",
                position: [13, 7],
                poussiere: 1271419
            }, 'Objet 3');
        });
    });

    QUnit.test('JSLint', function (assert) {
        function formatWarnings(analysis, source) {
            var sourceLines = source.split(/\r?\n/g),
                warnings = [];

            analysis.warnings.forEach(function (warning) {
                var str = '@ line ' + warning.line + ' column ' + warning.column + ': '
                        + warning.message + '\n'
                        + sourceLines[warning.line];
                warnings.push(str);
            });

            return warnings.join('\n\n');
        }

        function checkSource(url) {
            loadUrl(assert, url, function (source) {
                var analysis = jslint(source),
                    warnings = formatWarnings(analysis, source);

                assert.strictEqual(warnings, '', 'JSLinting ' + url);
            });
        }

        checkSource('nainwaklet.js');
        checkSource('tests.js');
    });
}());<|endoftext|>


<commit_before>// Using the subset of ES6 currently supported by FF Nightly 42.0a1 (2015-08-01)
// For full ES6:
// * replace "var" below with "let"

(function () {
  "use strict";

  if (typeof RegExp.make !== 'function') {
    return;
  }

  // Set up a RegExp subclass so that we can test subclass creation.
  function SubRegExp(source, flags) {
    const re = new RegExp(source, flags);
    Object.setPrototypeOf(re, SubRegExp.prototype);
    return re;
  }
  SubRegExp.prototype = new RegExp();
  SubRegExp.prototype.toString = function () {
    return 'SubRegExp:/' + this.source + '/' + this.flags;
  };
  SubRegExp.make = RegExp.make;

  const test = (
    function testMaker(ctor, flags, x, ...values) {
      if ('object' === typeof x && 'raw' in x) {
        // Produce a test record if called as a string template.
        const template = x;
        return {
          ctor: ctor,
          flags: flags,
          template: template,
          values: values.slice()
        };
      } else {
        var makerCtor = ctor;
        var makerFlags = flags;
        const args = [x, ...values];
        for (var i = 0, n = args.length; i < n; ++i) {
          const arg = args[i];
          switch (typeof arg) {
          case 'function': makerCtor = arg; break;
          case 'string':   makerFlags = arg; break;
          }
        }
        return testMaker.bind(this, makerCtor, makerFlags);
      }
    }
  ).bind(null, RegExp, null);

  /** Python style raw strings. */
  function r(template, ...values) {
    if (values.length !== 0) {
      throw new Error(
          'Interpolation not allowed into r`...` style raw strings');
    }
    return template.raw[0];
  }

  const tests = [
    // No interpolations
    [test`^foo\(bar\);\n$`,
     r`/^foo\(bar\);\n$/`],

    // No interpolations but flags
    [test('gi')`^foo\(bar\);\n$`,
     r`/^foo\(bar\);\n$/gi`],
    // A single string into a block context.
    [test`^${ 'foo' }$`,
     r`/^(?:foo)$/`],
    // Testing transitions between contexts.
    [test('i')`^([${ '\\' }${ /[a-z]/ }]{${ 42 }})${ /$/ }`,
     r`/^([\\a-z]{42})(?:$)/i`, [0, 1]],

    // We allow numbers in counts and don't wrap with (?:...) since those
    // are unnecessary.
    // Simply coercing to string will allow [1,2] as a count value here to
    // have the intuitive meaning.
    // We want to treat empty strings differently here since
    [test`x{3,${''}}`,
     // can be reasonably
     r`/x{3,}/`],
    // while if we allowed the empty string to be interpolated as the
    // empty string, then we would screw up the way postfix operators
    // associate as in
    [test`x${''}*`,
     // where it would be unintuitive for the * to associate with x.
     r`/x(?:)*/`],

    // Back-reference not scoped to containing RegExp
    [test`^(#+)([^#\r\n]*)${ /\1/ }`,
     // Can't use r`...` since \1 triggers an octal-escape strict parse error.
     '/^(#+)([^#\\r\\n]*)(?:\\1)/', [0, 1, 2]],
    // Negated charset into a charset
    [test`[${ /[^A-Z]/ }]`,
     r`/[\u0000-@\[-\uffff]/`],
    // String into a charset
    [test`[${ "A-Z" }]`,
     r`/[A\-Z]/`],
    // String into a negated charset
    [test`[^${ "A-Z" }]`,
     r`/[^A\-Z]/`],
    // Multiple elements into a charset: individual chars, charsets,
    // and special groups.
    [test`[${ /[a]|([c]|b)|d|_/ }]`,
     r`/[_a-d]/`],
    // Multiple case-insensitive elements into a charset: individual chars,
    // charsets, and special groups.
    [test`[${ /[a]|(?:[c]|b)|d|_/i }]`,
     r`/[A-D_a-d]/`],
    // {1,2} does not contribute chars.
    [test`[${ /x{1,2}/ }]`,
     r`/[x]/`],
    // . does contribute chars.
    [test`[${ /.|\r|\n/ }]`,
     r`/[\u0000-\u2027\u202a-\uffff]/`],
    // Rewrite group indices.
    [
    //test`(fo(o))${ /(x)\1(?:\2)/ }bar${ /\1/ }(baz)`,  // Octal esc error
      {
        ctor: RegExp,
        template: { raw: ['(fo(o))', 'bar', '(baz)'] },
        flags: '',
        values: [/(x)\1(?:\2)/, /\1/]
      },
      '/(fo(o))(?:(x)\\3(?:\\2))bar(?:\\1)(baz)/',
      // Group 3 -^ comes from an interpolated group.
      [0, 1, 2, 4]
    ],
    // Rewrite template back-references when interrupted.
    [
      //test`^(${ /(.*)/ }\n(#+)\n${ /(.*)/ }\n\2)\n`,
      {
        ctor: RegExp,
        flags: '',
        template: { raw: ['^(',         '\\n(#+)\\n',         '\\n\\2)\\n'] },
        values: [               /(.*)/,               /(.*)/],
        //                0 1               2                             <- Template groups
        //                0 1   2           3          4                  <- Output groups
      },
      '/^((?:(.*))\\n(#+)\\n(?:(.*))\\n\\3)\\n/',
      [0, 1, 3]
    ],
    // Test that interpolations break tokens.
    // ($x?:x) should not run together into (?:x) when x is empty.
    [test`(${""}?:x)`,
     '/((?:)?:x)/', [0, 1]],
    [test`(${new RegExp('')}?:x)`,
     '/((?:(?:))?:x)/', [0, 1]],

    // Test that interpolation of case-insensitive into case-sensitive
    // expands letters.
    [test`${ /<foo>/i }[a-z0-9_]*${ /<\/foo>/ }`,
     r`/(?:<[Ff][Oo][Oo]>)[a-z0-9_]*(?:<\/foo>)/`],

    // Test that \b means different things in different contexts.
    [test`[${ /[\b\t\n]/ }],[${ /\b|\t|\n/ }]`,
     r`/[\u0008-\u000a],[\u0009\u000a]/`],

    // Treat null and undefined like the empty string
    [test`${null},${undefined},${NaN},${false},${0}`,
     r`/(?:),(?:),(?:NaN),(?:false),(?:0)/`],

    // Test un-bindable back-reference
    [test`${ /\1/ }`, r`/(?:(?:))/`],

    // Subclassing of RegExp
    [test(SubRegExp)`foo`, 'SubRegExp:/foo/'],
    [test(SubRegExp, 'i')`foo`, 'SubRegExp:/foo/i'],

    // TODO: Handle case-folding properly when u flag is present
    // TODO: Test interpolation in middle of charset start.  `[${...}^]`
  ];

  function el(name, parent, opt_text) {
    const elem = document.createElement(name);
    parent.appendChild(elem);
    if (opt_text) {
      elem.appendChild(document.createTextNode(opt_text));
    }
    return elem;
  }

  function stringify(arr) {
    var s = '';
    s += '[';
    for (var i = 0, n = arr.length; i < n; ++i) {
      if (i) { s += ', '; }
      const x = arr[i];
      if (x && 'object' === typeof x) {
        s += x;
      } else {
        s += JSON.stringify(x);
      }
    }
    s += ']';
    return s;
  }

  function markPassFail(passed, el) {
    el.className += (passed ? ' pass' : ' fail');
  }

  const table = el('table', document.body);
  var tr = el('tr', el('thead', table));
  el('th', tr, 'string parts');
  el('th', tr, 'values');
  el('th', tr, 'expected pattern');
  el('th', tr, 'expected groups');
  tr = el('tr', el('thead', table));
  el('th', tr);
  el('th', tr);
  el('th', tr, 'actual pattern');
  el('th', tr, 'actual groups');
  const tbody = el('tbody', table);
  var nPassing = 0, nFailing = 0;
  for (var i = 0, n = tests.length; i < n; ++i) {
    const [
      { template, values, ctor: RegExpCtor, flags },
      expectedPattern,
      expectedGroupsOpt
    ] = tests[i];
    const expectedGroups = expectedGroupsOpt || [0];

    const maker = function (template, ...values) {
      if (flags != null) {
        return RegExpCtor.make(flags)(template, ...values);
      } else {
        return RegExpCtor.make(template, ...values);
      }
    }
    var actualPattern, actualGroups;
    try {
      const re = maker(template, ...values);
      actualPattern = re.toString();
      actualGroups = re.templateGroups;
    } catch (e) {
      actualPattern = '###Error:' + e + '###';
      actualGroups = ['###Error###'];
      console.error(e);
    }

    const passPattern = actualPattern === expectedPattern;
    const passGroups = expectedGroups.join(' ') === actualGroups.join(' ');
    const passAll = passPattern && passGroups;

    tr = el('tr', tbody);
    el('td', tr, JSON.stringify(template.raw)).setAttribute('rowspan', 2);
    el('td', tr, stringify(values)).setAttribute('rowspan', 2);
    el('td', tr, expectedPattern);
    el('td', tr, expectedGroups.join(' '));

    // Position the actual values below the wanted for easy scanning.
    const trActual = el('tr', tbody);
    const actualPatternTd = el('td', trActual, actualPattern);
    const actualGroupsTd = el('td', trActual, actualGroups.join(' '));

    markPassFail(passPattern, actualPatternTd);
    markPassFail(passGroups, actualGroupsTd);
    markPassFail(passAll, tr);
    markPassFail(passAll, trActual);

    if (passAll) {
      ++nPassing;
    } else {
      ++nFailing;
    }
  }

  document.getElementById('warning').style.display = 'none';
  document.title = (nFailing === 0 ? 'PASS' : 'FAIL') + ' : ' + document.title;
}());
<commit_msg>changed SubRegExp inheritance based on example code at https://github.com/paulmillr/es6-shim/blob/master/test/collections.js#L137 pointed out by ljharb<commit_after>// Using the subset of ES6 currently supported by FF Nightly 42.0a1 (2015-08-01)
// For full ES6:
// * replace "var" below with "let"

(function () {
  "use strict";

  if (typeof RegExp.make !== 'function') {
    return;
  }

  // Set up a RegExp subclass so that we can test subclass creation.
  function SubRegExp(source, flags) {
    const re = new RegExp(source, flags);
    Object.setPrototypeOf(re, SubRegExp.prototype);
    return re;
  }
  SubRegExp.prototype = Object.create(RegExp.prototype, {
    constructor: {
      value: SubRegExp
    },
    toString: {
      value: function () {
        return 'SubRegExp:/' + this.source + '/' + this.flags;
      }
    }
  });
  SubRegExp.make = RegExp.make;

  const test = (
    function testMaker(ctor, flags, x, ...values) {
      if ('object' === typeof x && 'raw' in x) {
        // Produce a test record if called as a string template.
        const template = x;
        return {
          ctor: ctor,
          flags: flags,
          template: template,
          values: values.slice()
        };
      } else {
        var makerCtor = ctor;
        var makerFlags = flags;
        const args = [x, ...values];
        for (var i = 0, n = args.length; i < n; ++i) {
          const arg = args[i];
          switch (typeof arg) {
          case 'function': makerCtor = arg; break;
          case 'string':   makerFlags = arg; break;
          }
        }
        return testMaker.bind(this, makerCtor, makerFlags);
      }
    }
  ).bind(null, RegExp, null);

  /** Python style raw strings. */
  function r(template, ...values) {
    if (values.length !== 0) {
      throw new Error(
          'Interpolation not allowed into r`...` style raw strings');
    }
    return template.raw[0];
  }

  const tests = [
    // No interpolations
    [test`^foo\(bar\);\n$`,
     r`/^foo\(bar\);\n$/`],

    // No interpolations but flags
    [test('gi')`^foo\(bar\);\n$`,
     r`/^foo\(bar\);\n$/gi`],
    // A single string into a block context.
    [test`^${ 'foo' }$`,
     r`/^(?:foo)$/`],
    // Testing transitions between contexts.
    [test('i')`^([${ '\\' }${ /[a-z]/ }]{${ 42 }})${ /$/ }`,
     r`/^([\\a-z]{42})(?:$)/i`, [0, 1]],

    // We allow numbers in counts and don't wrap with (?:...) since those
    // are unnecessary.
    // Simply coercing to string will allow [1,2] as a count value here to
    // have the intuitive meaning.
    // We want to treat empty strings differently here since
    [test`x{3,${''}}`,
     // can be reasonably
     r`/x{3,}/`],
    // while if we allowed the empty string to be interpolated as the
    // empty string, then we would screw up the way postfix operators
    // associate as in
    [test`x${''}*`,
     // where it would be unintuitive for the * to associate with x.
     r`/x(?:)*/`],

    // Back-reference not scoped to containing RegExp
    [test`^(#+)([^#\r\n]*)${ /\1/ }`,
     // Can't use r`...` since \1 triggers an octal-escape strict parse error.
     '/^(#+)([^#\\r\\n]*)(?:\\1)/', [0, 1, 2]],
    // Negated charset into a charset
    [test`[${ /[^A-Z]/ }]`,
     r`/[\u0000-@\[-\uffff]/`],
    // String into a charset
    [test`[${ "A-Z" }]`,
     r`/[A\-Z]/`],
    // String into a negated charset
    [test`[^${ "A-Z" }]`,
     r`/[^A\-Z]/`],
    // Multiple elements into a charset: individual chars, charsets,
    // and special groups.
    [test`[${ /[a]|([c]|b)|d|_/ }]`,
     r`/[_a-d]/`],
    // Multiple case-insensitive elements into a charset: individual chars,
    // charsets, and special groups.
    [test`[${ /[a]|(?:[c]|b)|d|_/i }]`,
     r`/[A-D_a-d]/`],
    // {1,2} does not contribute chars.
    [test`[${ /x{1,2}/ }]`,
     r`/[x]/`],
    // . does contribute chars.
    [test`[${ /.|\r|\n/ }]`,
     r`/[\u0000-\u2027\u202a-\uffff]/`],
    // Rewrite group indices.
    [
    //test`(fo(o))${ /(x)\1(?:\2)/ }bar${ /\1/ }(baz)`,  // Octal esc error
      {
        ctor: RegExp,
        template: { raw: ['(fo(o))', 'bar', '(baz)'] },
        flags: '',
        values: [/(x)\1(?:\2)/, /\1/]
      },
      '/(fo(o))(?:(x)\\3(?:\\2))bar(?:\\1)(baz)/',
      // Group 3 -^ comes from an interpolated group.
      [0, 1, 2, 4]
    ],
    // Rewrite template back-references when interrupted.
    [
      //test`^(${ /(.*)/ }\n(#+)\n${ /(.*)/ }\n\2)\n`,
      {
        ctor: RegExp,
        flags: '',
        template: { raw: ['^(',         '\\n(#+)\\n',         '\\n\\2)\\n'] },
        values: [               /(.*)/,               /(.*)/],
        //                0 1               2                             <- Template groups
        //                0 1   2           3          4                  <- Output groups
      },
      '/^((?:(.*))\\n(#+)\\n(?:(.*))\\n\\3)\\n/',
      [0, 1, 3]
    ],
    // Test that interpolations break tokens.
    // ($x?:x) should not run together into (?:x) when x is empty.
    [test`(${""}?:x)`,
     '/((?:)?:x)/', [0, 1]],
    [test`(${new RegExp('')}?:x)`,
     '/((?:(?:))?:x)/', [0, 1]],

    // Test that interpolation of case-insensitive into case-sensitive
    // expands letters.
    [test`${ /<foo>/i }[a-z0-9_]*${ /<\/foo>/ }`,
     r`/(?:<[Ff][Oo][Oo]>)[a-z0-9_]*(?:<\/foo>)/`],

    // Test that \b means different things in different contexts.
    [test`[${ /[\b\t\n]/ }],[${ /\b|\t|\n/ }]`,
     r`/[\u0008-\u000a],[\u0009\u000a]/`],

    // Treat null and undefined like the empty string
    [test`${null},${undefined},${NaN},${false},${0}`,
     r`/(?:),(?:),(?:NaN),(?:false),(?:0)/`],

    // Test un-bindable back-reference
    [test`${ /\1/ }`, r`/(?:(?:))/`],

    // Subclassing of RegExp
    [test(SubRegExp)`foo`, 'SubRegExp:/foo/'],
    [test(SubRegExp, 'i')`foo`, 'SubRegExp:/foo/i'],

    // TODO: Handle case-folding properly when u flag is present
    // TODO: Test interpolation in middle of charset start.  `[${...}^]`
  ];

  function el(name, parent, opt_text) {
    const elem = document.createElement(name);
    parent.appendChild(elem);
    if (opt_text) {
      elem.appendChild(document.createTextNode(opt_text));
    }
    return elem;
  }

  function stringify(arr) {
    var s = '';
    s += '[';
    for (var i = 0, n = arr.length; i < n; ++i) {
      if (i) { s += ', '; }
      const x = arr[i];
      if (x && 'object' === typeof x) {
        s += x;
      } else {
        s += JSON.stringify(x);
      }
    }
    s += ']';
    return s;
  }

  function markPassFail(passed, el) {
    el.className += (passed ? ' pass' : ' fail');
  }

  const table = el('table', document.body);
  var tr = el('tr', el('thead', table));
  el('th', tr, 'string parts');
  el('th', tr, 'values');
  el('th', tr, 'expected pattern');
  el('th', tr, 'expected groups');
  tr = el('tr', el('thead', table));
  el('th', tr);
  el('th', tr);
  el('th', tr, 'actual pattern');
  el('th', tr, 'actual groups');
  const tbody = el('tbody', table);
  var nPassing = 0, nFailing = 0;
  for (var i = 0, n = tests.length; i < n; ++i) {
    const [
      { template, values, ctor: RegExpCtor, flags },
      expectedPattern,
      expectedGroupsOpt
    ] = tests[i];
    const expectedGroups = expectedGroupsOpt || [0];

    const maker = function (template, ...values) {
      if (flags != null) {
        return RegExpCtor.make(flags)(template, ...values);
      } else {
        return RegExpCtor.make(template, ...values);
      }
    }
    var actualPattern, actualGroups;
    try {
      const re = maker(template, ...values);
      actualPattern = re.toString();
      actualGroups = re.templateGroups;
    } catch (e) {
      actualPattern = '###Error:' + e + '###';
      actualGroups = ['###Error###'];
      console.error(e);
    }

    const passPattern = actualPattern === expectedPattern;
    const passGroups = expectedGroups.join(' ') === actualGroups.join(' ');
    const passAll = passPattern && passGroups;

    tr = el('tr', tbody);
    el('td', tr, JSON.stringify(template.raw)).setAttribute('rowspan', 2);
    el('td', tr, stringify(values)).setAttribute('rowspan', 2);
    el('td', tr, expectedPattern);
    el('td', tr, expectedGroups.join(' '));

    // Position the actual values below the wanted for easy scanning.
    const trActual = el('tr', tbody);
    const actualPatternTd = el('td', trActual, actualPattern);
    const actualGroupsTd = el('td', trActual, actualGroups.join(' '));

    markPassFail(passPattern, actualPatternTd);
    markPassFail(passGroups, actualGroupsTd);
    markPassFail(passAll, tr);
    markPassFail(passAll, trActual);

    if (passAll) {
      ++nPassing;
    } else {
      ++nFailing;
    }
  }

  document.getElementById('warning').style.display = 'none';
  document.title = (nFailing === 0 ? 'PASS' : 'FAIL') + ' : ' + document.title;
}());
<|endoftext|>


<commit_before>/*

-----------------------------------
TFTP Protocol "Library"
-----------------------------------

http://tools.ietf.org/html/rfc1350
http://tools.ietf.org/html/rfc2347
http://tools.ietf.org/html/rfc2348

*/

var pack = require('./pack'),
    slog = require('sys').log,
   dgram = require('dgram'),
      fs = require('fs'),
		path = require('path'),
  config = require('./config').config,
      EE = require('events').EventEmitter;
    mapi = require('./mapi'),
     sys = require('sys');

var SERVER_HOST = config.host;
var SERVER_PORT = 69;
var TFTPROOT = '/tftpboot';

var sessions = {};

var OPCODES = (
  { 1: 'RRQ'
  , 2: 'WRQ'
  , 3: 'DATA'
  , 4: 'ACK'
  , 5: 'ERROR'
  , 6: 'OPACK'
  });

var ERR_UNDEFINED = 0;         // Not defined, see error message (if any)
var ERR_FILE_NOT_FOUND = 1;    // File not found
var ERR_ACCESS_VIOLATION = 2;  // Access violation
var ERR_DISK_FULL = 3;         // Disk full or allocation exceeded
var ERR_ILLEGAL_OPERATION = 4; // Illegal TFTP operation
var ERR_UNKNOWN_TRANSFER = 5;  // Unknown transfer ID
var ERR_FILE_EXISTS = 6;       // File already exists
var ERR_NO_SUCH_USER = 7;      // No such user
var ERR_NO_OPTION = 8;         // Option does not exist

var Session = function(client) {
  this.client = client;
  this.filename = null;
  this.mode = null;
  this.options = {};
  this.block = 1;
	var self = this;

  this.on('message', function(data) {
    var opcode = OPCODES[data[1]];
    switch (opcode) {
      case 'RRQ':
        parseRRQ(data);
        break;
      case 'WRQ':
        self.sendError(ERR_ACCESS_VIOLATION, "Read only TFTP");
        break;
      case 'DATA':
        self.sendError(ERR_ACCESS_VIOLATION, "Read only TFTP");
        break;
      case 'ACK':
        parseACK(data);
        break;
      case 'ERROR':
        var err = pack.unpack('nna*', data.toString('binary'));
        slog("< ERROR: " + err);
        break;
    }
  });

  var parseACK = function(data) {
    var ack = pack.unpack('CCn', data.toString('binary'));
    var ackblock = ack[2];
    //slog("[" + self.client.address + ':' + self.client.port + "] < ACK: " + ackblock);
    if (ackblock == (self.block % 65536)) {
      self.block +=1;
      self.sendData();
    }
  }

	var parseRRQ = function(data) {
		var req = pack.unpack('CCa*a*a*a*a*a*a*', data.toString('binary'));
		self.filename = TFTPROOT + '/' + req[2];
		self.mode = req[3];
		self.block = 1;
		var pos = 4;

    // parse the rest of the option in requests
		while (req[pos] != undefined && req[pos] != '') {
			self.options[req[pos]] = req[pos+1];
			console.log(req[pos]);
			switch (req[pos]) {
				case 'tsize':
				  try {
            stats = fs.statSync(self.filename)
            self.options['tsize'] = stats.size;
          }
          catch(err) {
            self.sendError(ERR_FILE_NOT_FOUND, "File not found: " + self.filename);
            return;
          }
				  break;
			}
			pos += 2;
		}

    self.sendOack();
    self.sendData();

	}

}

Session.prototype = new EE;

Session.prototype.buildMenu = function(mac, cb) {
  mapi.getBootParams(mac, function(c) {
    if (c == null) {
      return null;
    }
		var kargs_debug = 'prom_debug=true,map_debug=true,kbm_debug=true';
    var kernel_args = c.kernel_args;
    for (var n in c.physical_networks) {
      kernel_args += "," + n + "_nic=" + c.physical_networks[n];
    }

		cb(
		[ "default=0"
		, "timeout=5"
		, "min_mem64 1024"
		, "color cyan/blue white/blue"
		, ""
		, "title Live 64-bit"
		, "kernel " + c.kernel + " -B " + kernel_args
		, "module " + c.boot_archive
		, ""
		, "title Live 64-bit KMDB"
		, "  kernel " + c.kernel + " -k -B " + kernel_args + ',' + kargs_debug
		, "  module " + c.boot_archive
		, ""
		, "title Live 64-bit Debug"
		, "  kernel " + c.kernel + " -kdv -B " + kernel_args + ',' + kargs_debug
		, "  module " + c.boot_archive
		, ""
		, "title Live 64-bit Rescue (no importing zpool)"
		, "  kernel " + c.kernel + " -kdv -B " + kernel_args + ',noimport=true'
		, "  module " + c.boot_archive
		, ""
		].join('\n'));
  });
}

Session.prototype.sendMenuLst = function() {
  var bsize = parseInt(this.options.blksize || 512);
  var buffer = new Buffer(4 + bsize);
  var start = (this.block -1 ) * bsize;
  var self = this;

  console.log("start=" + start);
  console.log("bsize=" + bsize);
  var end = start + bsize;
  console.log("end=" + end);
  console.log("menuLst.length=" + self.menuLst.length);
  if (end > self.menuLst.length) {
    end = self.menuLst.length;
  }
  console.log("end (after)=" + end);
  var sendLength = 4 + end - start;
  var toSend = '';
  if (sendLength > 0) {
    toSend = self.menuLst.substring(start, end)
  } else {
    sendLength = 4;
  }
  console.log("start=" + start + ", end=" + end + ", length=" + self.menuLst.length + ", send length=" + sendLength);
  buffer.write(pack.pack("CCn", 0, 3, self.block), 0, 'binary');
  buffer.write(self.menuLst.substring(start, end), 4);
  console.log("==\n" + toSend  + "\n==");
  sock.send(buffer, 0, sendLength, self.client.port, self.client.address, function(err, bytes) {
    if (err) throw err;
  });
}

Session.prototype.sendData = function() {
  var self = this;
  var macReg = /menu.lst.01([0-9A-F]{12})/;
	if ( macReg.test(self.filename) ) {
    var mac = macReg.exec(self.filename)[1].match(/.{2}/g).join(':');
    console.log("mac=" + mac);
    if ( !self.menuLst ) {
      console.log("menu.lst requested, building...");
      self.buildMenu(mac, function(menu) {
          self.menuLst = menu;
          self.sendMenuLst();
      });
    } else {
      self.sendMenuLst();
    }
  } else {
    this.sendFile();
  }
}

Session.prototype.sendFile = function() {
  var bsize = this.options.blksize || 512;
  var buffer = new Buffer(4 + parseInt(bsize));
  var pos = (this.block -1 ) * bsize;
  var sendBlk = this.block % 65536;
  var self = this;

  if (this.block == 1) {
    console.log("Sending data, filename="+ self.filename);
  }
  fs.open(self.filename, 'r', function(err, fp) {
    if (err) {
      self.sendError(ERR_FILE_NOT_FOUND, "File not found: " + self.filename);
      return;
    }

    fs.read(fp, buffer, 4, bsize, pos, function(err, bytesRead) {
      if (err) {
        slog("Error reading file: "+ err);
        sendError(ERR_UNDEFINED, err);
        return;
      }
      fs.close(fp);

      buffer.write(pack.pack("CCn", 0, 3, sendBlk), 0, 'binary');
      sock.send(buffer, 0, 4 + bytesRead, self.client.port, self.client.address, function(err, bytes) {
        if (err) throw err;
        //slog("[" + self.client.address + ':' + self.client.port + "] > DATA Wrote " + bytes + " bytes to socket for block " + self.block);
      });
    });
  });

}

Session.prototype.sendOack = function() {
  var msg = pack.pack("CC", 0, 6);
  for (var key in this.options) {
    msg += pack.pack("a*a*", key, this.options[key]);
  }
  var buffer = new Buffer(msg);
	sock.send(buffer, 0, buffer.length, this.client.port, this.client.address);
}

Session.prototype.sendError = function(code, msg) {
	var buffer = new Buffer(4 + msg.length);
	buffer.write(pack.pack("CCnA*", 0, 5, code, msg), 'binary');
	//slog("> ERROR len: " + buffer.length + " block: " + this.block);
	sock.send(buffer, 0, buffer.length, this.client.port, this.client.address);
}

var sock = dgram.createSocket('udp4', function (data, client) {
  var key = client.address + ':' + client.port;
  var session = sessions[key];

  if (session == undefined) {
    var session = new Session(client);
    sessions[key] = session;
  }

  session.emit('message', data);

});

sock.on('listening', function() {
  slog("TFTP Server listening on " + SERVER_HOST + ":" + SERVER_PORT);
});

sock.bind(SERVER_PORT, SERVER_HOST);
<commit_msg>Log timeout packets.<commit_after>/*

-----------------------------------
TFTP Protocol "Library"
-----------------------------------

http://tools.ietf.org/html/rfc1350
http://tools.ietf.org/html/rfc2347
http://tools.ietf.org/html/rfc2348

*/

var pack = require('./pack'),
    slog = require('sys').log,
   dgram = require('dgram'),
      fs = require('fs'),
		path = require('path'),
  config = require('./config').config,
      EE = require('events').EventEmitter;
    mapi = require('./mapi'),
     sys = require('sys');

var SERVER_HOST = config.host;
var SERVER_PORT = 69;
var TFTPROOT = '/tftpboot';

var sessions = {};

var OPCODES = (
  { 1: 'RRQ'
  , 2: 'WRQ'
  , 3: 'DATA'
  , 4: 'ACK'
  , 5: 'ERROR'
  , 6: 'OPACK'
  });

var ERR_UNDEFINED = 0;         // Not defined, see error message (if any)
var ERR_FILE_NOT_FOUND = 1;    // File not found
var ERR_ACCESS_VIOLATION = 2;  // Access violation
var ERR_DISK_FULL = 3;         // Disk full or allocation exceeded
var ERR_ILLEGAL_OPERATION = 4; // Illegal TFTP operation
var ERR_UNKNOWN_TRANSFER = 5;  // Unknown transfer ID
var ERR_FILE_EXISTS = 6;       // File already exists
var ERR_NO_SUCH_USER = 7;      // No such user
var ERR_NO_OPTION = 8;         // Option does not exist

var Session = function(client) {
  this.client = client;
  this.filename = null;
  this.mode = null;
  this.options = {};
  this.block = 1;
	var self = this;

  this.on('message', function(data) {
    var opcode = OPCODES[data[1]];
    switch (opcode) {
      case 'RRQ':
        parseRRQ(data);
        break;
      case 'WRQ':
        self.sendError(ERR_ACCESS_VIOLATION, "Read only TFTP");
        break;
      case 'DATA':
        self.sendError(ERR_ACCESS_VIOLATION, "Read only TFTP");
        break;
      case 'ACK':
        parseACK(data);
        break;
      case 'ERROR':
        var err = pack.unpack('nna*', data.toString('binary'));
        slog("< ERROR: " + err);
        break;
    }
  });

  var parseACK = function(data) {
    var ack = pack.unpack('CCn', data.toString('binary'));
    var ackblock = ack[2];
    //slog("[" + self.client.address + ':' + self.client.port + "] < ACK: " + ackblock);
    if (ackblock == (self.block % 65536)) {
      self.block +=1;
      self.sendData();
    }
  }

	var parseRRQ = function(data) {
		var req = pack.unpack('CCa*a*a*a*a*a*a*', data.toString('binary'));
		self.filename = TFTPROOT + '/' + req[2];
		self.mode = req[3];
		self.block = 1;
		var pos = 4;

    // parse the rest of the option in requests
		while (req[pos] != undefined && req[pos] != '') {
			self.options[req[pos]] = req[pos+1];
			console.log(req[pos]);
			switch (req[pos]) {
				case 'timeout':
					slog("Got a TIMEOUT packet");
					break;
				case 'tsize':
				  try {
            stats = fs.statSync(self.filename)
            self.options['tsize'] = stats.size;
          }
          catch(err) {
            self.sendError(ERR_FILE_NOT_FOUND, "File not found: " + self.filename);
            return;
          }
				  break;
			}
			pos += 2;
		}

    self.sendOack();
    self.sendData();

	}

}

Session.prototype = new EE;

Session.prototype.buildMenu = function(mac, cb) {
  mapi.getBootParams(mac, function(c) {
    if (c == null) {
      return null;
    }
		var kargs_debug = 'prom_debug=true,map_debug=true,kbm_debug=true';
    var kernel_args = c.kernel_args;
    for (var n in c.physical_networks) {
      kernel_args += "," + n + "_nic=" + c.physical_networks[n];
    }

		cb(
		[ "default=0"
		, "timeout=5"
		, "min_mem64 1024"
		, "color cyan/blue white/blue"
		, ""
		, "title Live 64-bit"
		, "kernel " + c.kernel + " -B " + kernel_args
		, "module " + c.boot_archive
		, ""
		, "title Live 64-bit KMDB"
		, "  kernel " + c.kernel + " -k -B " + kernel_args + ',' + kargs_debug
		, "  module " + c.boot_archive
		, ""
		, "title Live 64-bit Debug"
		, "  kernel " + c.kernel + " -kdv -B " + kernel_args + ',' + kargs_debug
		, "  module " + c.boot_archive
		, ""
		, "title Live 64-bit Rescue (no importing zpool)"
		, "  kernel " + c.kernel + " -kdv -B " + kernel_args + ',noimport=true'
		, "  module " + c.boot_archive
		, ""
		].join('\n'));
  });
}

Session.prototype.sendMenuLst = function() {
  var bsize = parseInt(this.options.blksize || 512);
  var buffer = new Buffer(4 + bsize);
  var start = (this.block -1 ) * bsize;
  var self = this;

  console.log("start=" + start);
  console.log("bsize=" + bsize);
  var end = start + bsize;
  console.log("end=" + end);
  console.log("menuLst.length=" + self.menuLst.length);
  if (end > self.menuLst.length) {
    end = self.menuLst.length;
  }
  console.log("end (after)=" + end);
  var sendLength = 4 + end - start;
  var toSend = '';
  if (sendLength > 0) {
    toSend = self.menuLst.substring(start, end)
  } else {
    sendLength = 4;
  }
  console.log("start=" + start + ", end=" + end + ", length=" + self.menuLst.length + ", send length=" + sendLength);
  buffer.write(pack.pack("CCn", 0, 3, self.block), 0, 'binary');
  buffer.write(self.menuLst.substring(start, end), 4);
  console.log("==\n" + toSend  + "\n==");
  sock.send(buffer, 0, sendLength, self.client.port, self.client.address, function(err, bytes) {
    if (err) throw err;
  });
}

Session.prototype.sendData = function() {
  var self = this;
  var macReg = /menu.lst.01([0-9A-F]{12})/;
	if ( macReg.test(self.filename) ) {
    var mac = macReg.exec(self.filename)[1].match(/.{2}/g).join(':');
    console.log("mac=" + mac);
    if ( !self.menuLst ) {
      console.log("menu.lst requested, building...");
      self.buildMenu(mac, function(menu) {
          self.menuLst = menu;
          self.sendMenuLst();
      });
    } else {
      self.sendMenuLst();
    }
  } else {
    this.sendFile();
  }
}

Session.prototype.sendFile = function() {
  var bsize = this.options.blksize || 512;
  var buffer = new Buffer(4 + parseInt(bsize));
  var pos = (this.block -1 ) * bsize;
  var sendBlk = this.block % 65536;
  var self = this;

  if (this.block == 1) {
    console.log("Sending data, filename="+ self.filename);
  }
  fs.open(self.filename, 'r', function(err, fp) {
    if (err) {
      self.sendError(ERR_FILE_NOT_FOUND, "File not found: " + self.filename);
      return;
    }

    fs.read(fp, buffer, 4, bsize, pos, function(err, bytesRead) {
      if (err) {
        slog("Error reading file: "+ err);
        sendError(ERR_UNDEFINED, err);
        return;
      }
      fs.close(fp);

      buffer.write(pack.pack("CCn", 0, 3, sendBlk), 0, 'binary');
      sock.send(buffer, 0, 4 + bytesRead, self.client.port, self.client.address, function(err, bytes) {
        if (err) throw err;
        //slog("[" + self.client.address + ':' + self.client.port + "] > DATA Wrote " + bytes + " bytes to socket for block " + self.block);
      });
    });
  });

}

Session.prototype.sendOack = function() {
  var msg = pack.pack("CC", 0, 6);
  for (var key in this.options) {
    msg += pack.pack("a*a*", key, this.options[key]);
  }
  var buffer = new Buffer(msg);
	sock.send(buffer, 0, buffer.length, this.client.port, this.client.address);
}

Session.prototype.sendError = function(code, msg) {
	var buffer = new Buffer(4 + msg.length);
	buffer.write(pack.pack("CCnA*", 0, 5, code, msg), 'binary');
	//slog("> ERROR len: " + buffer.length + " block: " + this.block);
	sock.send(buffer, 0, buffer.length, this.client.port, this.client.address);
}

var sock = dgram.createSocket('udp4', function (data, client) {
  var key = client.address + ':' + client.port;
  var session = sessions[key];

  if (session == undefined) {
    var session = new Session(client);
    sessions[key] = session;
  }

  session.emit('message', data);

});

sock.on('listening', function() {
  slog("TFTP Server listening on " + SERVER_HOST + ":" + SERVER_PORT);
});

sock.bind(SERVER_PORT, SERVER_HOST);
<|endoftext|>


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

"use strict";

const events = require('events');

const _ = require("iotdb-helpers");

const helpers = require("./helpers");
const band = require("./band");
const band_meta = require("./band_meta");
const band_model = require("./band_model");
const band_state = require("./band_state");
const band_connection = require("./band_connection");

const make = (initd) => {
    const self = Object.assign({}, events.EventEmitter.prototype);

    // variables
    const _initd = _.d.compose.shallow(initd, {
        model: {},
        istate: {},
        ostate: {},
        meta: {},
        connection: {},
    });

    const _bandd = {};

    // make a band object for every band in initd
    _.mapObject(_initd, ( bvalue, bkey ) => {
        if (!_.is.Object(bvalue)) {
            return;
        }

        let band_make = band.make;

        switch (bkey) {
        case "meta": band_make = band_meta.make; break;
        case "model": band_make = band_model.make; break;
        case "istate": band_make = band_state.make; break;
        case "ostate": band_make = band_state.make; break;
        case "connection": band_make = band_connection.make; break;
        }

        _bandd[bkey] = band_make(self, bvalue, bkey);

    });

    // interface
    self.band = (band_name) => _bandd[band_name] || null;
    self.model_id = () => self.band("meta").get("iot:model-id", null, null);
    self.thing_id = () => self.band("meta").get("iot:thing-id", null, null);
    self.set = (key, value) => self.band("ostate").set(key, value);

    self.attribute = (o) => {
        const matchd = helpers.make_match_rule(o);
        const ads = self.band("model").list("iot:attribute", []);

        return _.find(ads, (ad) => _.d.is.superset(ad, matchd));
    }

    return self;
}

/**
 *  API
 */
exports.make = make;
<commit_msg>clean up names<commit_after>/*
 *  thing.js
 *
 *  David Janes
 *  IOTDB
 *  2016-02-13
 *
 *  Copyright [2013-2016] [David P. Janes]
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

"use strict";

const events = require('events');

const _ = require("iotdb-helpers");

const helpers = require("./helpers");
const as = require("./as");
const band = require("./band");
const band_meta = require("./band_meta");
const band_model = require("./band_model");
const band_state = require("./band_state");
const band_connection = require("./band_connection");

const make = (initd) => {
    const self = Object.assign({}, events.EventEmitter.prototype);

    // variables
    const _initd = _.d.compose.shallow(initd, {
        model: {},
        istate: {},
        ostate: {},
        meta: {},
        connection: {},
    });

    const _bandd = {};

    // make a band object for every band in initd
    _.mapObject(_initd, ( bvalue, bkey ) => {
        if (!_.is.Object(bvalue)) {
            return;
        }

        let band_make = band.make;

        switch (bkey) {
        case "meta": band_make = band_meta.make; break;
        case "model": band_make = band_model.make; break;
        case "istate": band_make = band_state.make; break;
        case "ostate": band_make = band_state.make; break;
        case "connection": band_make = band_connection.make; break;
        }

        _bandd[bkey] = band_make(self, bvalue, bkey);

    });

    // interface
    self.band = (band_name) => _bandd[band_name] || null;
    self.model_id = () => self.band("meta").first("iot:model-id", null, null);
    self.thing_id = () => self.band("meta").first("iot:thing-id", null, null);
    self.reachable = () => self.band("connection").first("iot:reachable", as.boolean, false);
    self.set = (key, value, as_type) => self.band("ostate").set(key, value, as_type);
    self.get = (key, as_type, otherwise) => self.band("istate").set(key, as_type, otherwise);

    self.attribute = (key, as_type) => {
        const matchd = helpers.make_match_rule(key);
        const ads = self.band("model").list("iot:attribute", []);

        const ad = _.find(ads, (ad) => _.d.is.superset(ad, matchd));
        if (ad && as_type) {
            return _.d.compose.shallow(as_type, ad);
        } else {
            return ad;
        }
    }

    return self;
}

/**
 *  API
 */
exports.make = make;
<|endoftext|>