<commit_before>enterUrlMsg = "Paste or drag-and-drop URL of video...";

pauseImgSrc = "//cdn.rawgit.com/iconic/open-iconic/master/png/media-pause-4x.png";
playImgSrc = "//cdn.rawgit.com/iconic/open-iconic/master/png/media-play-4x.png";

var videoUrl;
var videoName;
var videoTime = null;

var videos = {};
var videoCounter = 0;
var videoIteration = 0;
var videoPaused;
var timer;

function Timer(callback, delay) {
  var timerId, start, remaining = delay;

  this.pause = function() {
      window.clearTimeout(timerId);
      remaining -= new Date() - start;
  };

  this.resume = function() {
      start = new Date();
      window.clearTimeout(timerId);
      timerId = window.setTimeout(callback, remaining);
  };

  this.resume();
}

function msConversion(millis) {
  var minutes = Math.floor(millis / 60000);
  var seconds = ((millis % 60000) / 1000).toFixed(0);
  return minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
}

function highlight(i) {
  $("tr:nth-child(" + i + ")").attr("id", "newSelected");
  $("tr.selected").removeClass("selected");
  $("#newSelected").addClass("selected");
  $("#newSelected").removeAttr("id");
}

function playVideo() {
  highlight(videoIteration);
  document.title = "Streamly - " + videos[videoIteration]["name"];

  var embedUrl = videos[videoIteration]["url"].replace("/watch?v=", "/embed/") + "?autoplay=1";
  $("#youtube").attr("src", embedUrl);
  $("#pauseImg").attr("src", pauseImgSrc);
}

function loopVideo() {
  videoIteration++;
  playVideo();
  timer = new Timer(function() {
    if (videoIteration < videoCounter) {
      loopVideo();
    }
    else {
      timer.pause();
      timer = 0;
      $("#youtube").attr("src", "");
      document.title = "Streamly";
    }
  }, videos[videoIteration]["time"] + 2000);
}

function pauseVideo() {
  if (!videoPaused) {
    timer.pause();
    $("#pauseImg").attr("src", playImgSrc);
    videoPaused = true;
  }
  else {
    timer.resume();
    $("#pauseImg").attr("src", pauseImgSrc);
    videoPaused = false;
  }
}

function backVideo() {
  if (videoIteration - 2 > -1) {
    videoIteration = videoIteration - 2;
    if (timer != 0) {
      timer.pause();
    }
    timer = 0;
    loopVideo();
  }
}

function forwardVideo() {
  if (videoIteration + 1 <= videoCounter) {
    if (timer != 0) {
      timer.pause();
    }
    timer = 0;
    loopVideo();
  }
}

function Base64EncodeUrl(str){
  str = window.btoa(str);
  return str.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '');
}

function Base64DecodeUrl(str){
  str = (str + '===').slice(0, str.length + (str.length % 4));
  str = str.replace(/-/g, '+').replace(/_/g, '/');
  return window.atob(str);
}

function setPlaylist() {
  var playlist = JSON.stringify(videos);
  playlist = Base64EncodeUrl(playlist);
  window.location.hash = playlist;
}

function getPlaylist() {
  if (window.location.hash.substr(1) !== "") {
    var playlist = window.location.hash.substr(1);
    playlist = Base64DecodeUrl(playlist);
    playlist = JSON.parse(playlist);
    videos = playlist;

    for (var key in videos) {
      videoCounter++;
      var printTime = msConversion(videos[videoCounter]["time"]);
      $("#videosTable").append("
" + videos[videoCounter]["name"] + "	" + printTime + "
");
    }
    loopVideo();
  }
}

function getVideoData() {
  $.ajax({
    url: videoUrl,
    type: 'GET',
    success: function(res) {
      var data = $(res.responseText);
      videoName = data.find("span#eow-title");
      videoName = videoName[0].textContent;
      videoTime = null;
      for (iteration in data) {
        var str = data[iteration].innerHTML;
        if (videoTime == null && typeof str != "undefined") {
          videoTime = str.match(/,"length_seconds":"\d+",/g);
        }
      }
      videoTime = videoTime[0];
      videoTime = videoTime.replace(/,"length_seconds":"/g, "").replace(/",/g, "");
      videoTime = +videoTime * 1000;
    }
  });
}

function addVideo() {
  videoCounter++;
  videos[videoCounter] = {};
  videos[videoCounter]["name"] = videoName;
  videos[videoCounter]["time"] = videoTime;
  videos[videoCounter]["url"] = videoUrl;

  var printTime = msConversion(videos[videoCounter]["time"]);

  $("#videosTable").append("
" + videoName + "	" + printTime + "
");

  setPlaylist();

  if (videoCounter == 1 || timer == 0) {
    loopVideo();
  }
}

function input() {
  switch ($("#inputBox").attr("placeholder")) {
    case enterUrlMsg:
      videoUrl = $("#inputBox").val();
      $("#inputBox").val("");

      getVideoData();

      $(document).ajaxStop(function () {
        addVideo();
      });
      break;
  }
}
<commit_msg>testing<commit_after>enterUrlMsg = "Paste or drag-and-drop URL of video...";

pauseImgSrc = "//cdn.rawgit.com/iconic/open-iconic/master/png/media-pause-4x.png";
playImgSrc = "//cdn.rawgit.com/iconic/open-iconic/master/png/media-play-4x.png";

var videoUrl;
var videoName;
var videoTime = null;

var videos = {};
var videoCounter = 0;
var videoIteration = 0;
var videoPaused;
var timer;

function Timer(callback, delay) {
  var timerId, start, remaining = delay;

  this.pause = function() {
      window.clearTimeout(timerId);
      remaining -= new Date() - start;
  };

  this.resume = function() {
      start = new Date();
      window.clearTimeout(timerId);
      timerId = window.setTimeout(callback, remaining);
  };

  this.resume();
}

function msConversion(millis) {
  var minutes = Math.floor(millis / 60000);
  var seconds = ((millis % 60000) / 1000).toFixed(0);
  return minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
}

function highlight(i) {
  $("tr:nth-child(" + i + ")").attr("id", "newSelected");
  $("tr.selected").removeClass("selected");
  $("#newSelected").addClass("selected");
  $("#newSelected").removeAttr("id");
}

function playVideo() {
  highlight(videoIteration);
  document.title = "Streamly - " + videos[videoIteration]["name"];

  var embedUrl = videos[videoIteration]["url"].replace("/watch?v=", "/embed/") + "?autoplay=1";
  $("#youtube").attr("src", embedUrl);
  $("#pauseImg").attr("src", pauseImgSrc);
}

function loopVideo() {
  videoIteration++;
  playVideo();
  timer = new Timer(function() {
    if (videoIteration < videoCounter) {
      loopVideo();
    }
    else {
      timer.pause();
      timer = 0;
      $("#youtube").attr("src", "");
      document.title = "Streamly";
    }
  }, videos[videoIteration]["time"] + 2000);
}

function pauseVideo() {
  if (!videoPaused) {
    timer.pause();
    $("#pauseImg").attr("src", playImgSrc);
    videoPaused = true;
  }
  else {
    timer.resume();
    $("#pauseImg").attr("src", pauseImgSrc);
    videoPaused = false;
  }
}

function backVideo() {
  if (videoIteration - 2 > -1) {
    videoIteration = videoIteration - 2;
    if (timer != 0) {
      timer.pause();
    }
    timer = 0;
    loopVideo();
  }
}

function forwardVideo() {
  if (videoIteration + 1 <= videoCounter) {
    if (timer != 0) {
      timer.pause();
    }
    timer = 0;
    loopVideo();
  }
}

function Base64EncodeUrl(str){
  str = window.btoa(str);
  return str.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '');
}

function Base64DecodeUrl(str){
  str = (str + '===').slice(0, str.length + (str.length % 4));
  str = str.replace(/-/g, '+').replace(/_/g, '/');
  return window.atob(str);
}

function setPlaylist() {
  var playlist = JSON.stringify(videos);
  playlist = Base64EncodeUrl(playlist);
  window.location.hash = playlist;
}

function getPlaylist() {
  if (window.location.hash.substr(1) !== "") {
    var playlist = window.location.hash.substr(1);
    playlist = Base64DecodeUrl(playlist);
    playlist = JSON.parse(playlist);
    videos = playlist;

    for (var key in videos) {
      videoCounter++;
      var printTime = msConversion(videos[videoCounter]["time"]);
      $("#videosTable").append("
" + videos[videoCounter]["name"] + "	" + printTime + "
");
    }
    loopVideo();
  }
}

function getVideoData() {
  $.ajax({
    url: videoUrl,
    type: 'GET',
    success: function(res) {
      var data = $(res.responseText);
      videoName = data.find("span#eow-title");
      videoName = videoName[0].textContent;
      videoTime = null;
      for (iteration in data) {
        var str = data[iteration].innerHTML;
        if (videoTime == null && typeof str != "undefined") {
          videoTime = str.match(/,"length_seconds":"\d+",/g);
        }
      }
      videoTime = videoTime[0];
      videoTime = videoTime.replace(/,"length_seconds":"/g, "").replace(/",/g, "");
      videoTime = +videoTime * 1000;
    }
  });
}

function addVideo() {
  videoCounter++;
  videos[videoCounter] = {};
  videos[videoCounter]["name"] = videoName;
  videos[videoCounter]["time"] = videoTime;
  videos[videoCounter]["url"] = videoUrl;

  var printTime = msConversion(videos[videoCounter]["time"]);

  $("#videosTable").append("
" + videoName + "	" + printTime + "
");

  setPlaylist();

  if (videoCounter == 1 || timer == 0) {
    loopVideo();
  }
}

function input() {
  switch ($("#inputBox").attr("placeholder")) {
    case enterUrlMsg:
      videoUrl = $("#inputBox").val();
      $("#inputBox").val("");

      getVideoData();

      $(document).ajaxStop(function() {
        alert("Here...");
        addVideo();
      });
      break;
  }
}
<|endoftext|>


<commit_before>/* eslint-disable no-process-env */
var CachedSource = require('webpack-core/lib/CachedSource');
var ConcatSource = require('webpack-core/lib/ConcatSource');
var HtmlWebpackPlugin = require('html-webpack-plugin');

var uglifyJs = require('uglify-js');
var build = require('modernizr').build;
var assign = require('object-assign');

process.env.NODE_ENV = (process.env.NODE_ENV || 'development').trim();

/**
 * es5 class
 * @param {Object} [options] Refer to Modernizr for available options
 * @param {string} [options.filename=modernizr-bundle.js] The output file name including extension
 * @param {boolean} [options.htmlWebPackPluginIntegration=true] Integrate into html-webpack-plugin if begin used
 * @param {boolean} [options.minify] Defaults to NODE_ENV
 * @constructor
 */
function ModernizrPlugin(options) {
  if (options.filename && !options.filename.match(/\.js$/)) {
    options.filename = options.filename + '.js';
  }

  this.options = assign({}, {
    filename: 'modernizr-bundle.js',
    htmlWebPackPluginIntegration: true,
    minify: !(process.env.NODE_ENV === 'development')
  }, options);
}

ModernizrPlugin.prototype._htmlWebpackPluginInject = function (plugin, filename, hash, filesize) {
  var htmlWebPackPluginAssets = plugin.htmlWebpackPluginAssets;
  var oFilename = plugin.options.hash ? plugin.appendHash(filename, hash || '') : filename;
  plugin.htmlWebpackPluginAssets = function () {
    var result = htmlWebPackPluginAssets.apply(plugin, arguments);
    var chunk = {};
    chunk[filename] = {
      entry: oFilename,
      css: [],
      size: filesize || 0
    };
    // get html-webpack-plugin to output modernizr chunk first
    result.chunks = assign({}, chunk, result.chunks);
    return result;
  };
};

ModernizrPlugin.prototype._minifySource = function (source, options) {
  var uglifyOptions = Object.assign({}, options, {fromString: true});
  return uglifyJs.minify(source, uglifyOptions).code;
};

ModernizrPlugin.prototype.apply = function (compiler) {
  var self = this;

  compiler.plugin('after-compile', function (compilation, cb) {
    build(self.options, function (output) {
      if (self.options.minify) {
        output = self._minifySource(output, self.options.minify);
      }
      self.modernizrOutput = output;
      var stats = compilation.getStats().toJson();
      if (self.options.htmlWebPackPluginIntegration) {
        compiler.options.plugins.forEach(function (plugin) {
          if (plugin instanceof HtmlWebpackPlugin) {
            self._htmlWebpackPluginInject(plugin, self.options.filename,
              stats.hash, self.modernizrOutput.length)
          }
        })
      }
      cb();
    })
  });

  compiler.plugin('emit', function (compilation, cb) {
    var source = new ConcatSource();

    source.add(self.modernizrOutput);

    var filename = self.options.filename;
    compilation.assets[filename] = new CachedSource(source);

    cb();
  })
};

module.exports = ModernizrPlugin;
<commit_msg>Fix options bug<commit_after>/* eslint-disable no-process-env */
var CachedSource = require('webpack-core/lib/CachedSource');
var ConcatSource = require('webpack-core/lib/ConcatSource');
var HtmlWebpackPlugin = require('html-webpack-plugin');

var uglifyJs = require('uglify-js');
var build = require('modernizr').build;
var assign = require('object-assign');

process.env.NODE_ENV = (process.env.NODE_ENV || 'development').trim();

/**
 * es5 class
 * @param {Object} [options] Refer to Modernizr for available options
 * @param {string} [options.filename=modernizr-bundle.js] The output file name including extension
 * @param {boolean} [options.htmlWebPackPluginIntegration=true] Integrate into html-webpack-plugin if begin used
 * @param {boolean} [options.minify] Defaults to NODE_ENV
 * @constructor
 */
function ModernizrPlugin(options) {
  if (options && options.filename && !options.filename.match(/\.js$/)) {
    options.filename = options.filename + '.js';
  }

  this.options = assign({}, {
    filename: 'modernizr-bundle.js',
    htmlWebPackPluginIntegration: true,
    minify: !(process.env.NODE_ENV === 'development')
  }, options);
}

ModernizrPlugin.prototype._htmlWebpackPluginInject = function (plugin, filename, hash, filesize) {
  var htmlWebPackPluginAssets = plugin.htmlWebpackPluginAssets;
  var oFilename = plugin.options.hash ? plugin.appendHash(filename, hash || '') : filename;
  plugin.htmlWebpackPluginAssets = function () {
    var result = htmlWebPackPluginAssets.apply(plugin, arguments);
    var chunk = {};
    chunk[filename] = {
      entry: oFilename,
      css: [],
      size: filesize || 0
    };
    // get html-webpack-plugin to output modernizr chunk first
    result.chunks = assign({}, chunk, result.chunks);
    return result;
  };
};

ModernizrPlugin.prototype._minifySource = function (source, options) {
  var uglifyOptions = Object.assign({}, options, {fromString: true});
  return uglifyJs.minify(source, uglifyOptions).code;
};

ModernizrPlugin.prototype.apply = function (compiler) {
  var self = this;

  compiler.plugin('after-compile', function (compilation, cb) {
    build(self.options, function (output) {
      if (self.options.minify) {
        output = self._minifySource(output, self.options.minify);
      }
      self.modernizrOutput = output;
      var stats = compilation.getStats().toJson();
      if (self.options.htmlWebPackPluginIntegration) {
        compiler.options.plugins.forEach(function (plugin) {
          if (plugin instanceof HtmlWebpackPlugin) {
            self._htmlWebpackPluginInject(plugin, self.options.filename,
              stats.hash, self.modernizrOutput.length)
          }
        })
      }
      cb();
    })
  });

  compiler.plugin('emit', function (compilation, cb) {
    var source = new ConcatSource();

    source.add(self.modernizrOutput);

    var filename = self.options.filename;
    compilation.assets[filename] = new CachedSource(source);

    cb();
  })
};

module.exports = ModernizrPlugin;
<|endoftext|>


<commit_before>'use strict';

module.exports = function (PromiseArgument) {
  var Promise;
  function throat(size, fn) {
    var queue = new Queue();
    function run(fn, self, args) {
      if (size) {
        size--;
        var result = new Promise(function (resolve) {
          resolve(fn.apply(self, args));
        });
        result.then(release, release);
        return result;
      } else {
        return new Promise(function (resolve) {
          queue.push(new Delayed(resolve, fn, self, args));
        });
      }
    }
    function release() {
      size++;
      if (!queue.isEmpty()) {
        var next = queue.shift();
        next.resolve(run(next.fn, next.self, next.args));
      }
    }
    if (typeof size === 'function') {
      var temp = fn;
      fn = size;
      size = temp;
    }
    if (typeof size !== 'number') {
      throw new TypeError(
        'Expected throat size to be a number but got ' + typeof size
      );
    }
    if (fn !== undefined && typeof fn !== 'function') {
      throw new TypeError(
        'Expected throat fn to be a function but got ' + typeof fn
      );
    }
    if (typeof fn === 'function') {
      return function () {
        var args = [];
        for (var i = 0; i < arguments.length; i++) {
          args.push(arguments[i]);
        }
        return run(fn, this, args);
      };
    } else {
      return function (fn) {
        if (typeof fn !== 'function') {
          throw new TypeError(
            'Expected throat fn to be a function but got ' + typeof fn
          );
        }
        var args = [];
        for (var i = 1; i < arguments.length; i++) {
          args.push(arguments[i]);
        }
        return run(fn, this, args);
      };
    }
  }
  if (arguments.length === 1 && typeof PromiseArgument === 'function') {
    Promise = PromiseArgument;
    return throat;
  } else {
    Promise = module.exports.Promise;
    if (typeof Promise !== 'function') {
      throw new Error(
        'You must provide a Promise polyfill for this library to work in older environments'
      );
    }
    return throat(arguments[0], arguments[1]);
  }
};

/* istanbul ignore next */
if (typeof Promise === 'function') {
  module.exports.Promise = Promise;
}

function Delayed(resolve, fn, self, args) {
  this.resolve = resolve;
  this.fn = fn;
  this.self = self || null;
  this.args = args;
}

function Queue() {
  this._s1 = [];
  this._s2 = [];
}

Queue.prototype.push = function (value) {
  this._s1.push(value);
};

Queue.prototype.shift = function () {
  if (!this._s2.length) {
    while (this._s1.length) {
      this._s2.push(this._s1.pop());
    }
  }
  return this._s2.pop();
};

Queue.prototype.isEmpty = function () {
  return !this._s1.length && !this._s2.length;
};
<commit_msg>perf(Queue#shift): minor opt (#26)<commit_after>'use strict';

module.exports = function (PromiseArgument) {
  var Promise;
  function throat(size, fn) {
    var queue = new Queue();
    function run(fn, self, args) {
      if (size) {
        size--;
        var result = new Promise(function (resolve) {
          resolve(fn.apply(self, args));
        });
        result.then(release, release);
        return result;
      } else {
        return new Promise(function (resolve) {
          queue.push(new Delayed(resolve, fn, self, args));
        });
      }
    }
    function release() {
      size++;
      if (!queue.isEmpty()) {
        var next = queue.shift();
        next.resolve(run(next.fn, next.self, next.args));
      }
    }
    if (typeof size === 'function') {
      var temp = fn;
      fn = size;
      size = temp;
    }
    if (typeof size !== 'number') {
      throw new TypeError(
        'Expected throat size to be a number but got ' + typeof size
      );
    }
    if (fn !== undefined && typeof fn !== 'function') {
      throw new TypeError(
        'Expected throat fn to be a function but got ' + typeof fn
      );
    }
    if (typeof fn === 'function') {
      return function () {
        var args = [];
        for (var i = 0; i < arguments.length; i++) {
          args.push(arguments[i]);
        }
        return run(fn, this, args);
      };
    } else {
      return function (fn) {
        if (typeof fn !== 'function') {
          throw new TypeError(
            'Expected throat fn to be a function but got ' + typeof fn
          );
        }
        var args = [];
        for (var i = 1; i < arguments.length; i++) {
          args.push(arguments[i]);
        }
        return run(fn, this, args);
      };
    }
  }
  if (arguments.length === 1 && typeof PromiseArgument === 'function') {
    Promise = PromiseArgument;
    return throat;
  } else {
    Promise = module.exports.Promise;
    if (typeof Promise !== 'function') {
      throw new Error(
        'You must provide a Promise polyfill for this library to work in older environments'
      );
    }
    return throat(arguments[0], arguments[1]);
  }
};

/* istanbul ignore next */
if (typeof Promise === 'function') {
  module.exports.Promise = Promise;
}

function Delayed(resolve, fn, self, args) {
  this.resolve = resolve;
  this.fn = fn;
  this.self = self || null;
  this.args = args;
}

function Queue() {
  this._s1 = [];
  this._s2 = [];
}

Queue.prototype.push = function (value) {
  this._s1.push(value);
};

Queue.prototype.shift = function () {
  var s2 = this._s2;
  if (s2.length === 0) {
    var s1 = this._s1;
    if (s1.length === 0) {
      return;
    }
    this._s1 = s2;
    s2 = this._s2 = s1.reverse();
  }
  return s2.pop();
};

Queue.prototype.isEmpty = function () {
  return !this._s1.length && !this._s2.length;
};
<|endoftext|>


<commit_before>function StayDown(target, interval, max, callback) {
    this.target = target;
    this.interval = interval;
    this.intend_down = true;
    this.max = max || 0;
    this.callback = callback;
    this.userScroll = true;

    var staydown = this;

    this.emit('lock');

    var wheelevent = "wheel";
    if (document.onmousewheel !== undefined) {
        wheelevent = 'mousewheel';
    }

    window.addEventListener('resize', function (event) {
        staydown.emit('windowresize');
        staydown.checkdown();
    });

    this.target.addEventListener('scroll', function (event) {
        if (staydown.userScroll) {
            if (staydown.intend_down && !staydown.isdown()) {
                staydown.intend_down = false;
                staydown.emit('release');
            } else if (!staydown.indend_down && staydown.isdown()) {
                staydown.intend_down = true;
                staydown.emit('lock');
            }
        }
        staydown.userScroll = true;
    });

    function checkForImage(el, imgs) {
        var idx;
        imgs = imgs || [];
        if (el.nodeName === 'img' || el.nodeName === 'IMG') {
            return [el];
        } else {
            for (idx = 0; idx < el.children.length; idx++) {
                imgs = imgs.concat(checkForImage(el.children[idx], imgs));
            }
            return imgs;
        }

    }

    function onImageLoad(event) {
        //image loads later, and isn't a mutation
        staydown.emit('imageload');
        staydown.checkdown();
        event.target.removeEventListener(onImageLoad);
    }

    if (window.MutationObserver) {
        //private function for getting images recursively from dom

        //mutation observer for whenever the overflow element changes
        this.mo = new MutationObserver(function (mutations) {
            staydown.userScroll = false;
            //something changed, check scroll
            staydown.checkdown();
            //check to see if image was added, and add onload check
            for (var idx = 0; idx < mutations.length; idx++) {
                var mut = mutations[idx];
                for (var nidx = 0; nidx < mut.addedNodes.length; nidx++) {
                    var imgs = checkForImage(mut.addedNodes[nidx]);
                    imgs.forEach(function (img) {
                        img.addEventListener('load', onImageLoad);
                    });
                }
            }
        });
        this.mo.observe(this.target, {attributes: true, childList: true, characterData: true, subtree: true});
    } else {
        var checkdown = function () {
            staydown.checkdown();
            window.setTimeout(checkdown, staydown.interval);
        };
        checkdown();
    }

}

(function () {

    this.isdown = function () {
        return (this.target.scrollTop + this.target.clientHeight == this.target.scrollHeight);
    };

    this.append = function (newel) {
        this.emit('append');
        this.target.appendChild(newel);
        if (this.intend_down) {
            this.target.scrollTop = this.target.scrollHeight;
            this.emit('scrolldown');
        }
        while (this.max !== 0 && this.target.children.length > this.max) {
            this.target.removeChild(this.target.children[0]);
            this.emit('removechild');
        }
    };

    this.emit = function (type, msg) {
        if (typeof this.callback === 'function') {
            this.callback(type, msg);
        }
    };

    this.checkdown = function () {
        if (this.intend_down &&
            this.target.scrollTop + this.target.clientHeight != this.target.scrollHeight) {
            this.target.scrollTop = this.target.scrollHeight;
            this.userScroll = false;
            this.emit('scrolldown');
        }
    };

}).call(StayDown.prototype);

module.exports = StayDown;
//window.StayDown = StayDown;
<commit_msg>Remove recursive image lookup, since it is possible to get an infinite loop.<commit_after>function StayDown(target, interval, max, callback) {
    this.target = target;
    this.interval = interval;
    this.intend_down = true;
    this.max = max || 0;
    this.callback = callback;
    this.userScroll = true;

    var staydown = this;

    this.emit('lock');

    var wheelevent = "wheel";
    if (document.onmousewheel !== undefined) {
        wheelevent = 'mousewheel';
    }

    window.addEventListener('resize', function (event) {
        staydown.emit('windowresize');
        staydown.checkdown();
    });

    this.target.addEventListener('scroll', function (event) {
        if (staydown.userScroll) {
            if (staydown.intend_down && !staydown.isdown()) {
                staydown.intend_down = false;
                staydown.emit('release');
            } else if (!staydown.indend_down && staydown.isdown()) {
                staydown.intend_down = true;
                staydown.emit('lock');
            }
        }
        staydown.userScroll = true;
    });

    function onImageLoad(event) {
        //image loads later, and isn't a mutation
        staydown.emit('imageload');
        staydown.checkdown();
        event.target.removeEventListener(onImageLoad);
    }

    if (window.MutationObserver) {
        //private function for getting images recursively from dom

        //mutation observer for whenever the overflow element changes
        this.mo = new MutationObserver(function (mutations) {
            staydown.userScroll = false;
            //something changed, check scroll
            staydown.checkdown();
            //check to see if image was added, and add onload check
            for (var idx = 0; idx < mutations.length; idx++) {
                var mut = mutations[idx];
                for (var nidx = 0; nidx < mut.addedNodes.length; nidx++) {
                    var imgs = mut.addedNodes[nidx].getElementsByTagName('img');
                    for (var iidx = 0, ilen = imgs.length; iidx < ilen; i++) {
                        imgs[iidx].addEventListener('load', onImageLoad);
                    }
                }
            }
        });
        this.mo.observe(this.target, {attributes: true, childList: true, characterData: true, subtree: true});
    } else {
        var checkdown = function () {
            staydown.checkdown();
            window.setTimeout(checkdown, staydown.interval);
        };
        checkdown();
    }

}

(function () {

    this.isdown = function () {
        return (this.target.scrollTop + this.target.clientHeight == this.target.scrollHeight);
    };

    this.append = function (newel) {
        this.emit('append');
        this.target.appendChild(newel);
        if (this.intend_down) {
            this.target.scrollTop = this.target.scrollHeight;
            this.emit('scrolldown');
        }
        while (this.max !== 0 && this.target.children.length > this.max) {
            this.target.removeChild(this.target.children[0]);
            this.emit('removechild');
        }
    };

    this.emit = function (type, msg) {
        if (typeof this.callback === 'function') {
            this.callback(type, msg);
        }
    };

    this.checkdown = function () {
        if (this.intend_down &&
            this.target.scrollTop + this.target.clientHeight != this.target.scrollHeight) {
            this.target.scrollTop = this.target.scrollHeight;
            this.userScroll = false;
            this.emit('scrolldown');
        }
    };

}).call(StayDown.prototype);

module.exports = StayDown;
<|endoftext|>


<commit_before>var express = require("express");
var alexa = require("alexa-app");
const request = require('request');
const config = require('./config');

const YelpClient = require('./yelp/client');
let appYelpClient = new YelpClient(config, request);

var PORT = process.env.port || 8080;
var app = express();

// ALWAYS setup the alexa app and attach it to express before anything else.
var alexaApp = new alexa.app("test");

alexaApp.express({
    expressApp: app,

    // verifies requests come from amazon alexa. Must be enabled for production.
    // You can disable this if you're running a dev environment and want to POST
    // things to test behavior. enabled by default.
    checkCert: false,

    // sets up a GET route when set to true. This is handy for testing in
    // development, but not recommended for production. disabled by default
    debug: true
});

// now POST calls to /test in express will be handled by the app.request() function

// from here on you can setup any other express routes or middlewares as normal
app.set("view engine", "ejs");

alexaApp.launch(function (request, response) {
    response.say("You launched the app!");
});

alexaApp.dictionary = {
    "names": ["bob", "tejas", "oskar"],
    foods: ['pizza', 'pasta', 'burgers', 'sushi', 'sandwiches', 'soup', 'asian']
};

alexaApp.intent("foodIntent", {
        "slots": {
            "FOOD": "LITERAL",
            "LOCATION": "LOCATION" //this needs to be defined in the amazon dev portal
        },
        "utterances": [
            "i want to eat {foods|FOOD} in {-|LOCATION}",
            "best place for {foods|FOOD} in {-|LOCATION}"
        ]
    },
    function (request, response) {
        let session = request.getSession(),
            place = request.slot("LOCATION"),
            food = request.slot("FOOD"),
            restaurantLocation = [];

        if (!food) {
            return response.say('You must specify a valid food type!');
        }

        if (!place) {
            return response.say('Cannot determine location');
        }

        return appYelpClient.search(food, place).then((resp)=> {
            let restaurants = resp.businesses.reduce((names, item, index)=> {
                if (!names) {
                    names = [];
                }

                let locationIndex = (index + 1);
                restaurantLocation[locationIndex] = `${item.location.address1} ${item.location.city}`;
                return names.concat(`${locationIndex}. ${item.name}`);
            }, []).join(',');

            if (!restaurants.length) {
                throw Error('Could not get a proper response!');
            }

            restaurantLocation.forEach((item, index)=> {
                session.set('restaurant-' + index, item);
            });

            response.say(`top restaurants in ${place} are ${restaurants}`);
            response.shouldEndSession(false);
        }).catch((err)=> {
            console.error(err);
            response.say('Could not determine top restaurants!');
        });
    }
);

alexaApp.intent("addressFoodIntent", {
        "slots": {
            "NR": "AMAZON.NUMBER"
        },
        "utterances": [
            "address of {-|NR}", "where is number {-|NR}"
        ]
    },
    function (request, response) => {
        let session = request.getSession(),
            restaurantNr = request.slot("NR"),
            restaurantAddress = session.get('restaurant-' + restaurantNr);

        if(!restaurantNr){
            response.say(`You must give a 1 to 5 restaurant!`);
            response.shouldEndSession(false);
            return;
        }

        if (!session.get('restaurant-1')) {
            return response.say('You must require top place first!');
        }

        if (restaurantNr > 5) {
            response.say(`Only using top 5 recomandations!`);
            response.shouldEndSession(false);
            return;
        }

        if (restaurantAddress) {
            response.say(
                `Address of ${restaurantNr} is ${restaurantAddress}.
                Please rate from 1 to 5 your experience.`
            );
            return;
        }

        response.say('Could not determine the location of the restaurant');
        response.card({
            type: "Simple",
            content: `Cannot determine location of ${restaurantNr}`
        });
    }
);

alexaApp.intent("ratingIntent", {
        "slots": {
            "number": "AMAZON.NUMBER"
        },
        "utterances": [
            "{-|number} out of 5"
        ]
    },
    function (request, response) => {
        let rating = request.slot("number");

        if (rating <= 5 && rating >= 1) {
            response.say('Thank you for rating us!')
        }

        return response.say('Invalid rating!');
    }
);

app.listen(PORT);
console.log("Listening on port " + PORT + ", try http://localhost:" + PORT + "/test");
<commit_msg>Removed space operator<commit_after>var express = require("express");
var alexa = require("alexa-app");
const request = require('request');
const config = require('./config');

const YelpClient = require('./yelp/client');
let appYelpClient = new YelpClient(config, request);

var PORT = process.env.port || 8080;
var app = express();

// ALWAYS setup the alexa app and attach it to express before anything else.
var alexaApp = new alexa.app("test");

alexaApp.express({
    expressApp: app,

    // verifies requests come from amazon alexa. Must be enabled for production.
    // You can disable this if you're running a dev environment and want to POST
    // things to test behavior. enabled by default.
    checkCert: false,

    // sets up a GET route when set to true. This is handy for testing in
    // development, but not recommended for production. disabled by default
    debug: true
});

// now POST calls to /test in express will be handled by the app.request() function

// from here on you can setup any other express routes or middlewares as normal
app.set("view engine", "ejs");

alexaApp.launch(function (request, response) {
    response.say("You launched the app!");
});

alexaApp.dictionary = {
    "names": ["bob", "tejas", "oskar"],
    foods: ['pizza', 'pasta', 'burgers', 'sushi', 'sandwiches', 'soup', 'asian']
};

alexaApp.intent("foodIntent", {
        "slots": {
            "FOOD": "LITERAL",
            "LOCATION": "LOCATION" //this needs to be defined in the amazon dev portal
        },
        "utterances": [
            "i want to eat {foods|FOOD} in {-|LOCATION}",
            "best place for {foods|FOOD} in {-|LOCATION}"
        ]
    },
    function (request, response) {
        let session = request.getSession(),
            place = request.slot("LOCATION"),
            food = request.slot("FOOD"),
            restaurantLocation = [];

        if (!food) {
            return response.say('You must specify a valid food type!');
        }

        if (!place) {
            return response.say('Cannot determine location');
        }

        return appYelpClient.search(food, place).then((resp)=> {
            let restaurants = resp.businesses.reduce((names, item, index)=> {
                if (!names) {
                    names = [];
                }

                let locationIndex = (index + 1);
                restaurantLocation[locationIndex] = `${item.location.address1} ${item.location.city}`;
                return names.concat(`${locationIndex}. ${item.name}`);
            }, []).join(',');

            if (!restaurants.length) {
                throw Error('Could not get a proper response!');
            }

            restaurantLocation.forEach((item, index)=> {
                session.set('restaurant-' + index, item);
            });

            response.say(`top restaurants in ${place} are ${restaurants}`);
            response.shouldEndSession(false);
        }).catch((err)=> {
            console.error(err);
            response.say('Could not determine top restaurants!');
        });
    }
);

alexaApp.intent("addressFoodIntent", {
        "slots": {
            "NR": "AMAZON.NUMBER"
        },
        "utterances": [
            "address of {-|NR}", "where is number {-|NR}"
        ]
    },
    function (request, response) {
        let session = request.getSession(),
            restaurantNr = request.slot("NR"),
            restaurantAddress = session.get('restaurant-' + restaurantNr);

        if (!restaurantNr) {
            response.say(`You must give a 1 to 5 restaurant!`);
            response.shouldEndSession(false);
            return;
        }

        if (!session.get('restaurant-1')) {
            return response.say('You must require top place first!');
        }

        if (restaurantNr > 5) {
            response.say(`Only using top 5 recomandations!`);
            response.shouldEndSession(false);
            return;
        }

        if (restaurantAddress) {
            response.say(
                `Address of ${restaurantNr} is ${restaurantAddress}.
                Please rate from 1 to 5 your experience.`
            );
            return;
        }

        response.say('Could not determine the location of the restaurant');
        response.card({
            type: "Simple",
            content: `Cannot determine location of ${restaurantNr}`
        });
    }
);

alexaApp.intent("ratingIntent", {
        "slots": {
            "number": "AMAZON.NUMBER"
        },
        "utterances": [
            "{-|number} out of 5"
        ]
    },
    function (request, response) {
        let rating = request.slot("number");

        if (rating <= 5 && rating >= 1) {
            response.say('Thank you for rating us!')
        }

        return response.say('Invalid rating!');
    }
);

app.listen(PORT);
console.log("Listening on port " + PORT + ", try http://localhost:" + PORT + "/test");
<|endoftext|>


<commit_before>(function() {
  var root = this;

  var tagStart = '<';
  var tagEnd = '>';
  var commentStart = '<!--';
  var commentEnd = '-->';

  var voidTags = [
    "!doctype", "area", "base", "br", "col", "command",
    "embed", "hr", "img", "input", "keygen", "link",
    "meta", "param", "source", "track", "wbr"
  ];
  var closingTags = [
    "colgroup", "dd", "dt", "li", "options", "p",
    "td", "tfoot", "th", "thead", "tr"
  ];
  var childlessTags = ['style', 'script', 'template'];

  function parse(str) {
    return parseUntil(str + '</root>', ['root']).nodes;
  }

  function Node(kind, data) {
    data.type = kind;
    return data;
  }

  function parseUntil(str, stack) {
    var nodes = [];

    while (str.length) {
      var nextTag = str.indexOf(tagStart);
      if (!~nextTag) {
        // only text left
        nodes.push(Node('Text', {
          content: str
        }));
        str = "";
      } else if (nextTag) {
        // text before tag
        nodes.push(Node('Text', {
          content: str.slice(0, nextTag)
        }));
        str = str.slice(nextTag);
      } else {
        if (startsWithCommentStart(str)) {
          // comment
          var end = str.indexOf(commentEnd);
          nodes.push(Node('Comment', {
            content: str.slice(commentStart.length, end)
          }));
          str = str.slice(end + commentEnd.length);
        } else if (str.charAt(nextTag + 1) !== '/') {
          // open tag
          var results = parseTag(str, stack);
          if (results.tag) {
            nodes.push(Node('Element', results.tag));
            str = results.str;
          }
          if (results.stack.length !== stack.length) {
            stack = results.stack;
            break;
          }
        } else {
          // close tag
          var endTagEnd = str.indexOf(tagEnd);
          var tagName = str.slice(2, endTagEnd)
            .trim().split(' ')[0];
          str = str.slice(endTagEnd + 1);
          var loc = stack.lastIndexOf(tagName);
          if (~loc) {
            stack = stack.slice(0, loc);
            break;
          }
        }
      }
    }

    return {
      nodes: nodes,
      stack: stack,
      str: str
    };
  }

  function parseTag(str, stack) {
    var idxTagEnd = str.indexOf(tagEnd);
    var idxSpace = str.indexOf(' ');
    var tagNameEnd = ~idxSpace ?
      Math.min(idxTagEnd, idxSpace) :
      idxTagEnd;
    var tagName = str.slice(1, tagNameEnd);
    var lowTagName = tagName.toLowerCase();

    if (stack[stack.length - 1] === tagName && ~closingTags.indexOf(lowTagName)) {
      return {
        stack: stack.slice(0, -1)
      };
    }

    var attrs = parseAttrs(str.slice(tagNameEnd));
    var tag = {
      tagName: tagName,
      attributes: attrs.attributes
    };
    str = attrs.str;

    if (startsWithSelfClose(str)) {
      str = str.slice(2);
    } else {
      str = str.slice(1);

      if (~childlessTags.indexOf(lowTagName)) {
        var end = '</' + tagName + '>';
        var idx = str.indexOf(end);
        if (!~idx) idx = Infinity;
        tag.content = str.slice(0, idx);
        str = str.slice(idx);
      } else if (!~voidTags.indexOf(lowTagName)) {
        var results = parseUntil(str, stack.concat(tagName));
        tag.children = results.nodes;
        str = results.str;
        stack = results.stack;
      }
    }

    return {
      tag: tag,
      str: str,
      stack: stack
    };
  }

  function parseAttrs(str) {
    var results = tagPairs(str.trim());
    var str = results.str;
    var attributes = results.kvs.map(function(pair) {
      var kv = splitHead(pair.trim(), '=');
      kv[1] = kv[1] ? unquote(kv[1]) : kv[0];
      return kv;
    }).reduce(function(attrs, kv) {
      var property = kv[0];
      var value = kv[1];
      if (property === 'class') {
        attrs.className = value.split(' ');
      } else if (property === 'style') {
        attrs.style = parseStyle(value);
      } else if (startsWithDataDash(property)) {
        attrs.dataset = attrs.dataset || {};
        var key = camelCase(property.slice(5));
        attrs.dataset[key] = castValue(value);
      } else {
        attrs[camelCase(property)] = castValue(value);
      }
      return attrs;
    }, {});
    return {
      str: str,
      attributes: attributes
    };
  }

  function splitHead(str, sep) {
    var idx = str.indexOf(sep);
    if (!~idx) return [str];
    return [str.slice(0, idx), str.slice(idx + sep.length)];
  }

  function tagPairs(str) {
    function _tagPairs(str) {
      var parts = [];
      var start = 0;
      var finish = 0;
      var quote = null;
      for (var i = start; i < str.length; i++) {
        var c = str.charAt(i);
        if (!quote && (c === '/' || c === tagEnd)) {
          if (start !== i) parts.push(str.slice(start, i));
          finish = i;
          break;
        } else if (c === ' ' && !quote) {
          parts.push(str.slice(start, i));
          start = i + 1;
        } else if (c === quote) {
          quote = null;
        } else if (!quote && (c === '"' || c === "'")) {
          quote = c;
        }
      }
      return {
        kvs: parts,
        str: str.slice(finish)
      };
    }

    var result = _tagPairs(str);
    var list = result.kvs.filter(function(x) {
      return x;
    });
    var len = list.length;
    var kvs = [];
    for (var idx = 0; idx < len; idx++) {
      var val = list[idx];
      if (val.indexOf('=') === -1) {
        var second = list[idx + 1];
        var third = list[idx + 2];
        if (second === '=' && third) {
          idx += 2;
          kvs.push(val + '=' + third);
          continue;
        }
      }
      kvs.push(val);
    }
    result.kvs = kvs;
    return result;
  }

  function unquote(str) {
    var car = str.charAt(0);
    var end = str.length - 1;
    if (car === '"' || car === "'" && car === str.charAt(end)) {
      return str.slice(1, end);
    }
    return str;
  }

  function parseStyle(str) {
    return str.trim().split(';').map(function(statement) {
      return statement.trim().split(':');
    }).reduce(function(styles, kv) {
      if (kv[1]) styles[camelCase(kv[0].trim())] = castValue(kv[1].trim());
      return styles;
    }, {});
  }

  function camelCase(str) {
    return str.split('-').reduce(function(str, word) {
      return str + word.charAt(0).toUpperCase() + word.slice(1);
    });
  }

  function castValue(str) {
    if (typeof str !== 'string') return str;
    var num = +str;
    if (!isNaN(num)) return num;
    return str;
  }

  function startsWithCommentStart(s) {
    return (
      s.charAt(0) === '<' &&
      s.charAt(1) === '!' &&
      s.charAt(2) === '-' &&
      s.charAt(3) === '-');
  }

  function startsWithSelfClose(s) {
    return (
      s.charAt(0) === '/' &&
      s.charAt(1) === '>');
  }

  function startsWithDataDash(s) {
    return (
      s.charAt(0) === 'd' &&
      s.charAt(1) === 'a' &&
      s.charAt(2) === 't' &&
      s.charAt(3) === 'a' &&
      s.charAt(4) === '-');
  }

  var himalaya = {
    parse: parse,
    parseTag: parseTag,
    parseUntil: parseUntil,
    parseAttrs: parseAttrs,
    parseStyle: parseStyle
  };

  if (typeof exports !== 'undefined') {
    if (typeof module !== 'undefined' && module.exports) {
      exports = module.exports = himalaya;
    }
    exports.himalaya = himalaya;
  } else {
    root.himalaya = himalaya;
  }
}).call(this);
<commit_msg>rewrote tagPairs() and 0.2.0 => 0.2.1<commit_after>(function() {
  var root = this;

  var tagStart = '<';
  var tagEnd = '>';
  var commentStart = '<!--';
  var commentEnd = '-->';

  var voidTags = [
    "!doctype", "area", "base", "br", "col", "command",
    "embed", "hr", "img", "input", "keygen", "link",
    "meta", "param", "source", "track", "wbr"
  ];
  var closingTags = [
    "colgroup", "dd", "dt", "li", "options", "p",
    "td", "tfoot", "th", "thead", "tr"
  ];
  var childlessTags = ['style', 'script', 'template'];

  function parse(str) {
    return parseUntil(str + '</root>', ['root']).nodes;
  }

  function Node(kind, data) {
    data.type = kind;
    return data;
  }

  function parseUntil(str, stack) {
    var nodes = [];

    while (str.length) {
      var nextTag = str.indexOf(tagStart);
      if (!~nextTag) {
        // only text left
        nodes.push(Node('Text', {
          content: str
        }));
        str = "";
      } else if (nextTag) {
        // text before tag
        nodes.push(Node('Text', {
          content: str.slice(0, nextTag)
        }));
        str = str.slice(nextTag);
      } else {
        if (startsWithCommentStart(str)) {
          // comment
          var end = str.indexOf(commentEnd);
          nodes.push(Node('Comment', {
            content: str.slice(commentStart.length, end)
          }));
          str = str.slice(end + commentEnd.length);
        } else if (str.charAt(nextTag + 1) !== '/') {
          // open tag
          var results = parseTag(str, stack);
          if (results.tag) {
            nodes.push(Node('Element', results.tag));
            str = results.str;
          }
          if (results.stack.length !== stack.length) {
            stack = results.stack;
            break;
          }
        } else {
          // close tag
          var endTagEnd = str.indexOf(tagEnd);
          var tagName = str.slice(2, endTagEnd)
            .trim().split(' ')[0];
          str = str.slice(endTagEnd + 1);
          var loc = stack.lastIndexOf(tagName);
          if (~loc) {
            stack = stack.slice(0, loc);
            break;
          }
        }
      }
    }

    return {
      nodes: nodes,
      stack: stack,
      str: str
    };
  }

  function parseTag(str, stack) {
    var idxTagEnd = str.indexOf(tagEnd);
    var idxSpace = str.indexOf(' ');
    var tagNameEnd = ~idxSpace ?
      Math.min(idxTagEnd, idxSpace) :
      idxTagEnd;
    var tagName = str.slice(1, tagNameEnd);
    var lowTagName = tagName.toLowerCase();

    if (stack[stack.length - 1] === tagName && ~closingTags.indexOf(lowTagName)) {
      return {
        stack: stack.slice(0, -1)
      };
    }

    var attrs = parseAttrs(str.slice(tagNameEnd));
    var tag = {
      tagName: tagName,
      attributes: attrs.attributes
    };
    str = attrs.str;

    if (startsWithSelfClose(str)) {
      str = str.slice(2);
    } else {
      str = str.slice(1);

      if (~childlessTags.indexOf(lowTagName)) {
        var end = '</' + tagName + '>';
        var idx = str.indexOf(end);
        if (!~idx) idx = Infinity;
        tag.content = str.slice(0, idx);
        str = str.slice(idx);
      } else if (!~voidTags.indexOf(lowTagName)) {
        var results = parseUntil(str, stack.concat(tagName));
        tag.children = results.nodes;
        str = results.str;
        stack = results.stack;
      }
    }

    return {
      tag: tag,
      str: str,
      stack: stack
    };
  }

  function parseAttrs(str) {
    str = str.trim();
    var results = tagPairs(str, 0);
    str = str.slice(results.cursor);
    var attributes = results.kvs.map(function(pair) {
      var kv = splitHead(pair.trim(), '=');
      kv[1] = kv[1] ? unquote(kv[1]) : kv[0];
      return kv;
    }).reduce(function(attrs, kv) {
      var property = kv[0];
      var value = kv[1];
      if (property === 'class') {
        attrs.className = value.split(' ');
      } else if (property === 'style') {
        attrs.style = parseStyle(value);
      } else if (startsWithDataDash(property)) {
        attrs.dataset = attrs.dataset || {};
        var key = camelCase(property.slice(5));
        attrs.dataset[key] = castValue(value);
      } else {
        attrs[camelCase(property)] = castValue(value);
      }
      return attrs;
    }, {});
    return {
      str: str,
      attributes: attributes
    };
  }

  function splitHead(str, sep) {
    var idx = str.indexOf(sep);
    if (!~idx) return [str];
    return [str.slice(0, idx), str.slice(idx + sep.length)];
  }

  function tagPairs(str, index) {
    var words = []; // "key", "key=value", "key='value'", etc
    var quote = null; // null, single-, or double-quote
    var cursor = index; // index of parse into str
    var wordBegin = cursor; // index of word start
    var len = str.length;
    while(cursor < len) {
      var char = str.charAt(cursor);
      var isTagEnd = !quote && (char === '/' || char === tagEnd);
      if (isTagEnd) {
        if (cursor !== wordBegin) {
          words.push(str.slice(wordBegin, cursor));
        }
        break;
      }

      var isWordEnd = !quote && char === ' ';
      if (isWordEnd) {
        if (cursor !== wordBegin) {
          words.push(str.slice(wordBegin, cursor));
        }
        wordBegin = cursor + 1;
        cursor++;
        continue;
      }

      var isQuoteEnd = char === quote;
      if (isQuoteEnd) {
        quote = null;
        cursor++;
        continue;
      }

      var isQuoteStart = !quote && (char === '\'' || char === '"');
      if (isQuoteStart) {
        quote = char;
        cursor++;
        continue;
      }

      cursor++;
    }

    var attrs = [];
    var wLen = words.length;
    for (var i = 0; i < wLen; i++) {
      var word = words[i];
      if (!(word && word.length)) continue;
      var isNotPair = word.indexOf('=') === -1;
      if (isNotPair) {
        var secondWord = words[i + 1];
        var thirdWord = words[i + 2];
        var isSpacedPair = secondWord === '=' && thirdWord;
        if (isSpacedPair) {
          var newWord = word + '=' + thirdWord;
          attrs.push(newWord);
          i += 2;
          continue;
        }
      }
      attrs.push(word);
    }

    return {
      cursor: cursor,
      kvs: attrs
    };
  }

  function unquote(str) {
    var car = str.charAt(0);
    var end = str.length - 1;
    if (car === '"' || car === "'" && car === str.charAt(end)) {
      return str.slice(1, end);
    }
    return str;
  }

  function parseStyle(str) {
    return str.trim().split(';').map(function(statement) {
      return statement.trim().split(':');
    }).reduce(function(styles, kv) {
      if (kv[1]) styles[camelCase(kv[0].trim())] = castValue(kv[1].trim());
      return styles;
    }, {});
  }

  function camelCase(str) {
    return str.split('-').reduce(function(str, word) {
      return str + word.charAt(0).toUpperCase() + word.slice(1);
    });
  }

  function castValue(str) {
    if (typeof str !== 'string') return str;
    var num = +str;
    if (!isNaN(num)) return num;
    return str;
  }

  function startsWithCommentStart(s) {
    return (
      s.charAt(0) === '<' &&
      s.charAt(1) === '!' &&
      s.charAt(2) === '-' &&
      s.charAt(3) === '-');
  }

  function startsWithSelfClose(s) {
    return (
      s.charAt(0) === '/' &&
      s.charAt(1) === '>');
  }

  function startsWithDataDash(s) {
    return (
      s.charAt(0) === 'd' &&
      s.charAt(1) === 'a' &&
      s.charAt(2) === 't' &&
      s.charAt(3) === 'a' &&
      s.charAt(4) === '-');
  }

  var himalaya = {
    parse: parse,
    parseTag: parseTag,
    parseUntil: parseUntil,
    parseAttrs: parseAttrs,
    parseStyle: parseStyle
  };

  if (typeof exports !== 'undefined') {
    if (typeof module !== 'undefined' && module.exports) {
      exports = module.exports = himalaya;
    }
    exports.himalaya = himalaya;
  } else {
    root.himalaya = himalaya;
  }
}).call(this);
<|endoftext|>


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

var ALL_HEADERS = [
  'X-Content-Security-Policy',
  'Content-Security-Policy',
  'X-WebKit-CSP'
];

var DIRECTIVES = [
  'default-src',
  'script-src',
  'object-src',
  'img-src',
  'media-src',
  'frame-src',
  'font-src',
  'connect-src',
  'style-src',
  'report-uri',
  'sandbox'
];

var MUST_BE_QUOTED = [
  'none',
  'self',
  'unsafe-inline',
  'unsafe-eval'
];

module.exports = function csp(options) {

  options = _.clone(options) || { 'default-src': ["'self'"] };
  var reportOnly = options.reportOnly || false;
  var setAllHeaders = options.setAllHeaders || false;
  var safari5 = options.safari5 || false;

  DIRECTIVES.forEach(function (directive) {
    // normalize camelCase to spinal-case
    var cameledKey = camelize(directive);
    var cameledValue = options[cameledKey];
    if (cameledValue && (cameledKey !== directive)) {
      if (options[directive]) {
        throw new Error(directive + ' and ' + cameledKey + ' specified. Specify just one.');
      }
      options[directive] = cameledValue;
    }

    var value = options[directive];
    if (!value) {
      return;
    }

    // expand space separated source list
    var shouldWrapInArray = (_(value).isString()) && (
      (directive !== 'sandbox') ||
      ((directive === 'sandbox') && (value !== true))
    );
    if (shouldWrapInArray) {
      options[directive] = value.split(/\s/g);
    }
  });

  // check quoted source
  _.each(options, function (value) {
    if (Array.isArray(value)) {
      MUST_BE_QUOTED.forEach(function (must) {
        if (value.indexOf(must) !== -1) {
          throw new Error(value + ' must be quoted');
        }
      });
    } else {
      MUST_BE_QUOTED.forEach(function (must) {
        if (value === must) {
          throw new Error(value + ' must be quoted');
        }
      });
    }
  });

  if (reportOnly && !options['report-uri']) {
    throw new Error('Please remove reportOnly or add a report-uri.');
  }

  return function csp(req, res, next) {

    var headers = [];
    var policy = {};

    var browser = platform.parse(req.headers['user-agent']);
    var version = parseFloat(browser.version);
    var unknownBrowser = false;

    DIRECTIVES.forEach(function (directive) {
      var value = options[directive];
      if ((value !== null) && (value !== undefined)) {
        policy[directive] = value;
      }
    });

    switch (browser.name) {
      case 'IE':
        if (version >= 10) {
          headers.push('X-Content-Security-Policy');
          if (!setAllHeaders) {
            if (policy.sandbox) {
              policy = { sandbox: policy.sandbox };
            } else {
              policy = {};
            }
          }
        }
        break;

      case 'Firefox':
        if (version >= 23) {
          headers.push('Content-Security-Policy');
        } else if ((version >= 4) && (version < 23)) {
          headers.push('X-Content-Security-Policy');

          policy['default-src'] = policy['default-src'] || ['*'];

          Object.keys(options).forEach(function (key) {
            var value = options[key];
            if (Array.isArray(value)) {
              // Clone the array so we don't later mutate `options` by mistake
              value = value.slice();
            }

            if (key === 'connect-src') {
              policy['xhr-src'] = value;
            } else if (key === 'default-src') {
              if (version < 5) {
                policy.allow = value;
              } else {
                policy['default-src'] = value;
              }
            } else if (key !== 'sandbox') {
              policy[key] = value;
            }

            if (Array.isArray(policy[key])) {
              var index;
              if ((index = policy[key].indexOf("'unsafe-inline'")) !== -1) {
                if (key === 'script-src') {
                  policy[key][index] = "'inline-script'";
                } else {
                  policy[key].splice(index, 1);
                }
              }
              if ((index = policy[key].indexOf("'unsafe-eval'")) !== -1) {
                if (key === 'script-src') {
                  policy[key][index] = "'eval-script'";
                } else {
                  policy[key].splice(index, 1);
                }
              }
            }
          });
        }
        break;

      case 'Chrome':
        if ((version >= 14) && (version < 25)) {
          headers.push('X-WebKit-CSP');
        } else if (version >= 25) {
          headers.push('Content-Security-Policy');
        }
        break;

      case 'Safari':
        if (version >= 7) {
          headers.push('Content-Security-Policy');
        } else if ((version >= 6) || ((version >= 5.1) && safari5)) {
          headers.push('X-WebKit-CSP');
        }
        break;

      case 'Opera':
        if (version >= 15) {
          headers.push('Content-Security-Policy');
        }
        break;

      case 'Chrome Mobile':
        if (version >= 14) {
          headers.push('Content-Security-Policy');
        }
        break;

      default:
        unknownBrowser = true;
    }

    var policyString = _.map(policy, function (value, key) {
      if ((key === 'sandbox') && (value === true)) {
        return 'sandbox';
      } else if (Array.isArray(value)) {
        return key + ' ' + value.join(' ');
      } else {
        return key + ' ' + value;
      }
    }).join(';');

    if (setAllHeaders || unknownBrowser) {
      headers = ALL_HEADERS;
    }

    if (policyString) {
      headers.forEach(function (header) {
        var headerName = header;
        if (reportOnly) {
          headerName += '-Report-Only';
        }
        res.setHeader(headerName, policyString);
      });
    }
    next();
  };
};
<commit_msg>Normalize source list to array<commit_after>var _ = require('underscore');
var camelize = require('camelize');
var platform = require('platform');

var ALL_HEADERS = [
  'X-Content-Security-Policy',
  'Content-Security-Policy',
  'X-WebKit-CSP'
];

var DIRECTIVES = [
  'default-src',
  'script-src',
  'object-src',
  'img-src',
  'media-src',
  'frame-src',
  'font-src',
  'connect-src',
  'style-src',
  'report-uri',
  'sandbox'
];

var MUST_BE_QUOTED = [
  'none',
  'self',
  'unsafe-inline',
  'unsafe-eval'
];

module.exports = function csp(options) {

  options = _.clone(options) || { 'default-src': ["'self'"] };
  var reportOnly = options.reportOnly || false;
  var setAllHeaders = options.setAllHeaders || false;
  var safari5 = options.safari5 || false;

  DIRECTIVES.forEach(function (directive) {
    // Normalize camelCase to spinal-case
    var cameledKey = camelize(directive);
    var cameledValue = options[cameledKey];
    if (cameledValue && (cameledKey !== directive)) {
      if (options[directive]) {
        throw new Error(directive + ' and ' + cameledKey + ' specified. Specify just one.');
      }
      options[directive] = cameledValue;
    }

    var value = options[directive];
    if (!value) {
      return;
    }

    // Normalize to array
    if (!Array.isArray(value)) {
      if (directive === 'sandbox' && value === true) {
        options[directive] = [];
      } else if (_.isString(value)) {
        options[directive] = value.split(/\s/g);
      } else {
        throw new Error('Invalid directive: ' + directive + ' ' + value);
      }
      value = options[directive];
    }

    // Check quoted source
    MUST_BE_QUOTED.forEach(function (must) {
      if (value.indexOf(must) !== -1) {
        throw new Error(value + ' must be quoted');
      }
    });
  });

  if (reportOnly && !options['report-uri']) {
    throw new Error('Please remove reportOnly or add a report-uri.');
  }

  return function csp(req, res, next) {

    var headers = [];
    var policy = {};

    var browser = platform.parse(req.headers['user-agent']);
    var version = parseFloat(browser.version);
    var unknownBrowser = false;

    DIRECTIVES.forEach(function (directive) {
      var value = options[directive];
      if (value) {
        // Clone the array so we don't later mutate `options` by mistake
        policy[directive] = value.slice();
      }
    });

    switch (browser.name) {
      case 'IE':
        if (version >= 10) {
          headers.push('X-Content-Security-Policy');
          if (!setAllHeaders) {
            if (policy.sandbox) {
              policy = { sandbox: policy.sandbox };
            } else {
              policy = {};
            }
          }
        }
        break;

      case 'Firefox':
        if (version >= 23) {
          headers.push('Content-Security-Policy');
        } else if ((version >= 4) && (version < 23)) {
          headers.push('X-Content-Security-Policy');

          policy['default-src'] = policy['default-src'] || ['*'];

          Object.keys(policy).forEach(function (key) {
            var value = policy[key];
            if (key === 'connect-src') {
              policy['xhr-src'] = value;
            } else if (key === 'default-src') {
              if (version < 5) {
                policy.allow = value;
              } else {
                policy['default-src'] = value;
              }
            } else if (key !== 'sandbox') {
              policy[key] = value;
            }

            var index;
            if ((index = policy[key].indexOf("'unsafe-inline'")) !== -1) {
              if (key === 'script-src') {
                policy[key][index] = "'inline-script'";
              } else {
                policy[key].splice(index, 1);
              }
            }
            if ((index = policy[key].indexOf("'unsafe-eval'")) !== -1) {
              if (key === 'script-src') {
                policy[key][index] = "'eval-script'";
              } else {
                policy[key].splice(index, 1);
              }
            }
          });
        }
        break;

      case 'Chrome':
        if ((version >= 14) && (version < 25)) {
          headers.push('X-WebKit-CSP');
        } else if (version >= 25) {
          headers.push('Content-Security-Policy');
        }
        break;

      case 'Safari':
        if (version >= 7) {
          headers.push('Content-Security-Policy');
        } else if ((version >= 6) || ((version >= 5.1) && safari5)) {
          headers.push('X-WebKit-CSP');
        }
        break;

      case 'Opera':
        if (version >= 15) {
          headers.push('Content-Security-Policy');
        }
        break;

      case 'Chrome Mobile':
        if (version >= 14) {
          headers.push('Content-Security-Policy');
        }
        break;

      default:
        unknownBrowser = true;
    }

    var policyString = _.map(policy, function (value, key) {
      return [key].concat(value).join(' ');
    }).join(';');

    if (setAllHeaders || unknownBrowser) {
      headers = ALL_HEADERS;
    }

    if (policyString) {
      headers.forEach(function (header) {
        var headerName = header;
        if (reportOnly) {
          headerName += '-Report-Only';
        }
        res.setHeader(headerName, policyString);
      });
    }
    next();
  };
};
<|endoftext|>


<commit_before>var fs = require('fs');
var Q = require('q');

module.exports = function (chai, utils) {
    //convert the weird  selenium promise to a Q promise
    function promise(selPromise) {
        var defer = Q.defer();

        selPromise.then(function () {
            defer.resolve.apply(defer, arguments);
        });
        selPromise.thenCatch(function () {
            defer.reject.apply(defer, arguments);
        });

        return defer.promise;
    };

    function assertElementExists(elementPromise) {
        return elementPromise.fail(function (err) {
            throw new Error('element does not exist');
        });
    }

    chai.Assertion.addProperty('larger', function () {
        utils.flag(this, 'parseNumber', true);
        utils.flag(this, 'larger', true);
    });

    chai.Assertion.addProperty('smaller', function () {
        utils.flag(this, 'parseNumber', true);
        utils.flag(this, 'smaller', true);
    });

    chai.Assertion.overwriteMethod('match', function (_super) {
        return function (matcher) {
            var self = this;

            if (utils.flag(this, 'dom')) {
                return assertElementExists(self._obj).then(function (el) {
                    return el.getText().then(function (text) {
                        self.assert(matcher.test(text), 'Expected element <#{this}> to match regular expression "#{exp}", but it contains "#{act}".', 'Expected element <#{this}> not to match regular expression "#{exp}"; it contains "#{act}".', matcher, text);
                    });
                });
            }
            else {
                return _super.call(this, matcher);
            }
        };
    });

    chai.Assertion.addProperty('present', function () {
        var self = this;
        var present = function (isPresent) {
            return function () {
                self.assert(isPresent, "Element should be presented.", "Element should not be presented.");
            }
        }
        self._obj.then(present(true), present(false));
    });

    chai.Assertion.addMethod('displayed', function () {
        var self = this;

        var assert = function (condition) {
            self.assert(condition, 'Expected #{this} to be displayed but it is not', 'Expected #{this} to not be displayed but it is');
        };

        return assertElementExists(self._obj).then(function (el) {
            return el.isDisplayed().then(function (displayed) {
                return assert(displayed);
            });
        }, function (err) {
            if (utils.flag(self, 'negate')) {
                return assert(false);
            }
            throw err;
        });
    });

    chai.Assertion.addMethod('visible', function () {
        var self = this;

        var assert = function (condition) {
            self.assert(condition, 'Expected #{this} to be visible but it is not', 'Expected #{this} to not be visible but it is');
        };

        return assertElementExists(self._obj).then(function (el) {
            return el.isDisplayed().then(function (visible) {
                //selenium may say it's visible even though it's off-screen
                if (visible) {
                    return promise(el.getDriver().manage().window().getSize()).then(function (winSize) {
                        return el.getSize().then(function (size) {
                            return el.getLocation().then(function (loc) {
                                return assert(loc.x > -size.width && loc.y > -size.height && loc.y < winSize.height && loc.x < winSize.width);
                            });
                        });
                    });
                }
                else {
                    return assert(visible);
                }
            });
        }, function (err) {
            if (utils.flag(self, 'negate')) {
                return assert(false);
            }
            throw err;
        });
    });
    chai.Assertion.addMethod('count', function (length) {
        var self = this;

        return self._obj.then(function (els) {
            if (utils.flag(self, 'larger')) {
                self.assert(els.length >= length, 'Expected #{this} to appear more than #{exp} times, but it appeared #{act} times.', 'Expected #{this} not to appear more than #{exp} times, but it appeared #{act} times.', length, els.length);
            }
            else if (utils.flag(self, 'smaller')) {
                self.assert(els.length <= length, 'Expected #{this} to appear less than #{exp} times, but it appeared #{act} times.', 'Expected #{this} not to appear less than #{exp} times, but it appeared #{act} times.', length, els.length);
            }
            else {
                self.assert(els.length === length, 'Expected #{this} to appear #{exp} times, but it appeared #{act} times.', 'Expected #{this} not to appear #{exp} times, but it did.', length, els.length);
            }
        });
    });
    chai.Assertion.addChainableMethod('text', function (matcher) {
        var self = this;

        return assertElementExists(self._obj).then(function (el) {
            return el.getText().then(function (text) {
                if (matcher instanceof RegExp) {
                    self.assert(matcher.test(text), 'Expected element <#{this}> to match regular expression "#{exp}", but it contains "#{act}".', 'Expected element <#{this}> not to match regular expression "#{exp}"; it contains "#{act}".', matcher, text);
                }
                else if (utils.flag(self, 'contains')) {
                    self.assert(~text.indexOf(matcher), 'Expected element <#{this}> to contain text "#{exp}", but it contains "#{act}" instead.', 'Expected element <#{this}> not to contain text "#{exp}", but it contains "#{act}".', matcher, text);
                }
                else if (utils.flag(self, 'parseNumber')) {
                    text = text.length;

                    if (utils.flag(self, 'larger')) {
                        self.assert(text >= matcher, 'Expected length of text of element <#{this}> to be larger than #{exp}, but it was #{act}.', 'Expected length of text of element <#{this}> to not be larger than #{exp}, but it was #{act}.', matcher, text);
                    }
                    else if (utils.flag(self, 'smaller')) {
                        self.assert(text <= matcher, 'Expected length of text of element <#{this}> to be smaller than #{exp}, but it was #{act}.', 'Expected length of text of element <#{this}> to not be smaller than #{exp}, but it was #{act}.', matcher, text);
                    }
                }
                else {
                    self.assert(text === matcher, 'Expected text of element <#{this}> to be "#{exp}", but it was "#{act}" instead.', 'Expected text of element <#{this}> not to be "#{exp}", but it was.', matcher, text);
                }
            });
        });
    }, function () {
        utils.flag(this, 'dom', true);
    });

    chai.Assertion.addMethod('style', function (property, value) {
        var self = this;

        return assertElementExists(self._obj).then(function (el) {
            return el.getCssValue(property).then(function (style) {
                if (utils.flag(self, 'parseNumber')) {
                    style = parseFloat(style);

                    if (utils.flag(self, 'larger')) {
                        self.assert(style >= value, 'Expected style ' + property + ' of element <#{this}> to be larger than #{exp}, but it was #{act}.', 'Expected style ' + property + ' of element <#{this}> not to be larger than #{exp}, but it was #{act}.', value, style);
                    }
                    else if (utils.flag(self, 'smaller')) {
                        self.assert(style <= value, 'Expected style ' + property + ' of element <#{this}> to be smaller than #{exp}, but it was #{act}.', 'Expected style ' + property + ' of element <#{this}> not to be smaller than #{exp}, but it was #{act}.', value, style);
                    }
                }
                else {
                    self.assert(style === value.toString(), 'Expected style ' + property + ' of element <#{this}> to be #{exp}, but it was #{act}.', 'Expected ' + property + ' of element <#{this}> to not be #{exp}, but it was.');
                }
            });
        });
    });

    chai.Assertion.addMethod('value', function (value) {
        var self = this;

        return assertElementExists(self._obj).then(function (el) {
            return el.getAttribute('value').then(function (actualValue) {
                if (utils.flag(self, 'parseNumber')) {
                    actualValue = parseFloat(actualValue);

                    if (utils.flag(self, 'larger')) {
                        self.assert(actualValue >= value, 'Expected value of element <#{this}> to be larger than #{exp}, but it was #{act}.', 'Expected value of element <#{this}> not to be larger than #{exp}, but it was #{act}.', value, actualValue);
                    }
                    else if (utils.flag(self, 'smaller')) {
                        self.assert(actualValue <= value, 'Expected value of element <#{this}> to be smaller than #{exp}, but it was #{act}.', 'Expected value of element <#{this}> not to be smaller than #{exp}, but it was #{act}.', value, actualValue);
                    }
                }
                else {
                    self.assert(value === actualValue, 'Expected value of element <#{this}> to be #{exp}, but it was #{act}.', 'Expected value of element <#{this}> to not be #{exp}, but it was.', value, actualValue);
                }
            });
        });
    });

    chai.Assertion.addMethod('disabled', function () {
        var self = this;

        return assertElementExists(self._obj).then(function (el) {
            return el.getAttribute('disabled').then(function (disabled) {
                self.assert(disabled, 'Expected #{this} to be disabled but it is not', 'Expected #{this} to not be disabled but it is');
            });
        });
    });

    chai.Assertion.addMethod('class', function (value) {
        var self = this;

        return assertElementExists(self._obj).then(function (el) {
            return el.getAttribute('class').then(function (classList) {
                self.assert(~classList.indexOf(value), "Expected " + classList + " to contain " + value + ", but it does not.");
            });
        });
    });

    return chai.Assertion.addMethod('attribute', function (attribute, value) {
        var self = this;

        return assertElementExists(self._obj).then(function (el) {
            return el.getAttribute(attribute).then(function (actual) {
                if (utils.flag(self, 'parseNumber')) {
                    actual = parseFloat(actual);

                    if (utils.flag(self, 'larger')) {
                        self.assert(actual >= value, 'Expected attribute ' + attribute + ' of element <#{this}> to be larger than #{exp}, but it was #{act}.', 'Expected attribute ' + attribute + ' of element <#{this}> not to be larger than #{exp}, but it was #{act}.', value, actual);
                    }
                    else if (utils.flag(self, 'smaller')) {
                        self.assert(actual <= value, 'Expected attribute ' + attribute + ' of element <#{this}> to be smaller than #{exp}, but it was #{act}.', 'Expected attribute ' + attribute + ' of element <#{this}> not to be smaller than #{exp}, but it was #{act}.', value, actual);
                    }
                }
                else {
                    if (typeof value === 'undefined') {
                        self.assert(typeof actual === 'string', 'Expected attribute ' + attribute + ' of element <#{this}> to exist.', 'Expected attribute ' + attribute + ' of element <#{this}> not to exist.', value, actual);
                    }
                    else {
                        self.assert(actual === value, 'Expected attribute ' + attribute + ' of element <#{this}> to be #{exp}, but it was #{act}.', 'Expected attribute ' + attribute + ' of element <#{this}> not to be #{act}, but it was.', value, actual);
                    }
                }
            });
        });
    });
};
<commit_msg>Unwrapped `#visible` promise, seems to cause test issues.<commit_after>var fs = require('fs');
var Q = require('q');

module.exports = function (chai, utils) {
    //convert the weird  selenium promise to a Q promise
    function promise(selPromise) {
        var defer = Q.defer();

        selPromise.then(function () {
            defer.resolve.apply(defer, arguments);
        });
        selPromise.thenCatch(function () {
            defer.reject.apply(defer, arguments);
        });

        return defer.promise;
    };

    function assertElementExists(elementPromise) {
        return elementPromise.fail(function (err) {
            throw new Error('element does not exist');
        });
    }

    chai.Assertion.addProperty('larger', function () {
        utils.flag(this, 'parseNumber', true);
        utils.flag(this, 'larger', true);
    });

    chai.Assertion.addProperty('smaller', function () {
        utils.flag(this, 'parseNumber', true);
        utils.flag(this, 'smaller', true);
    });

    chai.Assertion.overwriteMethod('match', function (_super) {
        return function (matcher) {
            var self = this;

            if (utils.flag(this, 'dom')) {
                return assertElementExists(self._obj).then(function (el) {
                    return el.getText().then(function (text) {
                        self.assert(matcher.test(text), 'Expected element <#{this}> to match regular expression "#{exp}", but it contains "#{act}".', 'Expected element <#{this}> not to match regular expression "#{exp}"; it contains "#{act}".', matcher, text);
                    });
                });
            }
            else {
                return _super.call(this, matcher);
            }
        };
    });

    chai.Assertion.addProperty('present', function () {
        var self = this;
        var present = function (isPresent) {
            return function () {
                self.assert(isPresent, "Element should be presented.", "Element should not be presented.");
            }
        }
        self._obj.then(present(true), present(false));
    });

    chai.Assertion.addMethod('displayed', function () {
        var self = this;

        var assert = function (condition) {
            self.assert(condition, 'Expected #{this} to be displayed but it is not', 'Expected #{this} to not be displayed but it is');
        };

        return assertElementExists(self._obj).then(function (el) {
            return el.isDisplayed().then(function (displayed) {
                return assert(displayed);
            });
        }, function (err) {
            if (utils.flag(self, 'negate')) {
                return assert(false);
            }
            throw err;
        });
    });

    chai.Assertion.addMethod('visible', function () {
        var self = this;

        var assert = function (condition) {
            self.assert(condition, 'Expected #{this} to be visible but it is not', 'Expected #{this} to not be visible but it is');
        };

        return assertElementExists(self._obj).then(function (el) {
            return el.isDisplayed().then(function (visible) {
                //selenium may say it's visible even though it's off-screen
                if (visible) {
                    return el.getDriver().manage().window().getSize().then(function (winSize) {
                        return el.getSize().then(function (size) {
                            return el.getLocation().then(function (loc) {
                                return assert(loc.x > -size.width && loc.y > -size.height && loc.y < winSize.height && loc.x < winSize.width);
                            });
                        });
                    });
                }
                else {
                    return assert(visible);
                }
            });
        }, function (err) {
            if (utils.flag(self, 'negate')) {
                return assert(false);
            }
            throw err;
        });
    });
    chai.Assertion.addMethod('count', function (length) {
        var self = this;

        return self._obj.then(function (els) {
            if (utils.flag(self, 'larger')) {
                self.assert(els.length >= length, 'Expected #{this} to appear more than #{exp} times, but it appeared #{act} times.', 'Expected #{this} not to appear more than #{exp} times, but it appeared #{act} times.', length, els.length);
            }
            else if (utils.flag(self, 'smaller')) {
                self.assert(els.length <= length, 'Expected #{this} to appear less than #{exp} times, but it appeared #{act} times.', 'Expected #{this} not to appear less than #{exp} times, but it appeared #{act} times.', length, els.length);
            }
            else {
                self.assert(els.length === length, 'Expected #{this} to appear #{exp} times, but it appeared #{act} times.', 'Expected #{this} not to appear #{exp} times, but it did.', length, els.length);
            }
        });
    });
    chai.Assertion.addChainableMethod('text', function (matcher) {
        var self = this;

        return assertElementExists(self._obj).then(function (el) {
            return el.getText().then(function (text) {
                if (matcher instanceof RegExp) {
                    self.assert(matcher.test(text), 'Expected element <#{this}> to match regular expression "#{exp}", but it contains "#{act}".', 'Expected element <#{this}> not to match regular expression "#{exp}"; it contains "#{act}".', matcher, text);
                }
                else if (utils.flag(self, 'contains')) {
                    self.assert(~text.indexOf(matcher), 'Expected element <#{this}> to contain text "#{exp}", but it contains "#{act}" instead.', 'Expected element <#{this}> not to contain text "#{exp}", but it contains "#{act}".', matcher, text);
                }
                else if (utils.flag(self, 'parseNumber')) {
                    text = text.length;

                    if (utils.flag(self, 'larger')) {
                        self.assert(text >= matcher, 'Expected length of text of element <#{this}> to be larger than #{exp}, but it was #{act}.', 'Expected length of text of element <#{this}> to not be larger than #{exp}, but it was #{act}.', matcher, text);
                    }
                    else if (utils.flag(self, 'smaller')) {
                        self.assert(text <= matcher, 'Expected length of text of element <#{this}> to be smaller than #{exp}, but it was #{act}.', 'Expected length of text of element <#{this}> to not be smaller than #{exp}, but it was #{act}.', matcher, text);
                    }
                }
                else {
                    self.assert(text === matcher, 'Expected text of element <#{this}> to be "#{exp}", but it was "#{act}" instead.', 'Expected text of element <#{this}> not to be "#{exp}", but it was.', matcher, text);
                }
            });
        });
    }, function () {
        utils.flag(this, 'dom', true);
    });

    chai.Assertion.addMethod('style', function (property, value) {
        var self = this;

        return assertElementExists(self._obj).then(function (el) {
            return el.getCssValue(property).then(function (style) {
                if (utils.flag(self, 'parseNumber')) {
                    style = parseFloat(style);

                    if (utils.flag(self, 'larger')) {
                        self.assert(style >= value, 'Expected style ' + property + ' of element <#{this}> to be larger than #{exp}, but it was #{act}.', 'Expected style ' + property + ' of element <#{this}> not to be larger than #{exp}, but it was #{act}.', value, style);
                    }
                    else if (utils.flag(self, 'smaller')) {
                        self.assert(style <= value, 'Expected style ' + property + ' of element <#{this}> to be smaller than #{exp}, but it was #{act}.', 'Expected style ' + property + ' of element <#{this}> not to be smaller than #{exp}, but it was #{act}.', value, style);
                    }
                }
                else {
                    self.assert(style === value.toString(), 'Expected style ' + property + ' of element <#{this}> to be #{exp}, but it was #{act}.', 'Expected ' + property + ' of element <#{this}> to not be #{exp}, but it was.');
                }
            });
        });
    });

    chai.Assertion.addMethod('value', function (value) {
        var self = this;

        return assertElementExists(self._obj).then(function (el) {
            return el.getAttribute('value').then(function (actualValue) {
                if (utils.flag(self, 'parseNumber')) {
                    actualValue = parseFloat(actualValue);

                    if (utils.flag(self, 'larger')) {
                        self.assert(actualValue >= value, 'Expected value of element <#{this}> to be larger than #{exp}, but it was #{act}.', 'Expected value of element <#{this}> not to be larger than #{exp}, but it was #{act}.', value, actualValue);
                    }
                    else if (utils.flag(self, 'smaller')) {
                        self.assert(actualValue <= value, 'Expected value of element <#{this}> to be smaller than #{exp}, but it was #{act}.', 'Expected value of element <#{this}> not to be smaller than #{exp}, but it was #{act}.', value, actualValue);
                    }
                }
                else {
                    self.assert(value === actualValue, 'Expected value of element <#{this}> to be #{exp}, but it was #{act}.', 'Expected value of element <#{this}> to not be #{exp}, but it was.', value, actualValue);
                }
            });
        });
    });

    chai.Assertion.addMethod('disabled', function () {
        var self = this;

        return assertElementExists(self._obj).then(function (el) {
            return el.getAttribute('disabled').then(function (disabled) {
                self.assert(disabled, 'Expected #{this} to be disabled but it is not', 'Expected #{this} to not be disabled but it is');
            });
        });
    });

    chai.Assertion.addMethod('class', function (value) {
        var self = this;

        return assertElementExists(self._obj).then(function (el) {
            return el.getAttribute('class').then(function (classList) {
                self.assert(~classList.indexOf(value), "Expected " + classList + " to contain " + value + ", but it does not.");
            });
        });
    });

    return chai.Assertion.addMethod('attribute', function (attribute, value) {
        var self = this;

        return assertElementExists(self._obj).then(function (el) {
            return el.getAttribute(attribute).then(function (actual) {
                if (utils.flag(self, 'parseNumber')) {
                    actual = parseFloat(actual);

                    if (utils.flag(self, 'larger')) {
                        self.assert(actual >= value, 'Expected attribute ' + attribute + ' of element <#{this}> to be larger than #{exp}, but it was #{act}.', 'Expected attribute ' + attribute + ' of element <#{this}> not to be larger than #{exp}, but it was #{act}.', value, actual);
                    }
                    else if (utils.flag(self, 'smaller')) {
                        self.assert(actual <= value, 'Expected attribute ' + attribute + ' of element <#{this}> to be smaller than #{exp}, but it was #{act}.', 'Expected attribute ' + attribute + ' of element <#{this}> not to be smaller than #{exp}, but it was #{act}.', value, actual);
                    }
                }
                else {
                    if (typeof value === 'undefined') {
                        self.assert(typeof actual === 'string', 'Expected attribute ' + attribute + ' of element <#{this}> to exist.', 'Expected attribute ' + attribute + ' of element <#{this}> not to exist.', value, actual);
                    }
                    else {
                        self.assert(actual === value, 'Expected attribute ' + attribute + ' of element <#{this}> to be #{exp}, but it was #{act}.', 'Expected attribute ' + attribute + ' of element <#{this}> not to be #{act}, but it was.', value, actual);
                    }
                }
            });
        });
    });
};
<|endoftext|>


<commit_before>/**
 * Author: petar bojinov - @pbojinov
 * Date: 01/27/16
 */

'use strict';

/**
 * Get client IP address
 *
 * Will return 127.0.0.1 when testing locally
 * Useful when you need the user ip for geolocation or serving localized content
 *
 * @method getClientIp
 * @param req
 * @returns {string} ip
 */
function getClientIp(req) {

    // the ipAddress we return
    var ipAddress;

    // workaround to get real client IP
    // most likely because our app will be behind a [reverse] proxy or load balancer
    var clientIp = req.headers['x-client-ip'];
    var forwardedForAlt = req.headers['x-forwarded-for'];
    var realIp = req.headers['x-real-ip'];

    // more obsure ones below
    var clusterClientIp = req.headers['x-cluster-client-ip'];
    var forwardedAlt = req.headers['x-forwarded'];
    var forwardedFor = req.headers['forwarded-for'];
    var forwarded = req.headers['forwarded'];

    // remote address check
    var reqConnectionRemoteAddress = req.connection ? req.connection.remoteAddress : null;
    var reqSocketRemoteAddress = req.socket ? req.socket.remoteAddress : null;
    var reqConnectionSocketRemoteAddress = (req.connection && req.connection.socket) ? req.connection.socket.remoteAddress : null;
    var reqInfoRemoteAddress = req.info ? req.info.remoteAddress : null;

    // x-client-ip
    if (clientIp) {
        ipAddress = clientIp;
    }

    // x-forwarded-for
    // (typically when your node app is behind a load-balancer (eg. AWS ELB) or proxy)
    else if (forwardedForAlt) {
        // x-forwarded-for may return multiple IP addresses in the format:
        // "client IP, proxy 1 IP, proxy 2 IP"
        // Therefore, the right-most IP address is the IP address of the most recent proxy
        // and the left-most IP address is the IP address of the originating client.
        // source: http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/x-forwarded-headers.html
        var forwardedIps = forwardedForAlt.split(',');
        ipAddress = forwardedIps[0];
    }

    // x-real-ip
    // (default nginx proxy/fcgi)
    else if (realIp) {
        // alternative to x-forwarded-for, used by some proxies
        ipAddress = realIp;
    }

    // x-cluster-client-ip
    // (Rackspace LB and Riverbed's Stingray)
    // http://www.rackspace.com/knowledge_center/article/controlling-access-to-linux-cloud-sites-based-on-the-client-ip-address
    // https://splash.riverbed.com/docs/DOC-1926
    else if (clusterClientIp) {
        ipAddress = clusterClientIp;
    }

    // x-forwarded
    else if (forwardedAlt) {
        ipAddress = forwardedAlt;
    }

    // forwarded-for
    else if (forwardedFor) {
        ipAddress = forwardedFor;
    }

    // forwarded
    else if (forwarded) {
        ipAddress = forwarded;
    }

    // remote address checks
    else if (reqConnectionRemoteAddress) {
        ipAddress = reqConnectionRemoteAddress;
    }
    else if (reqSocketRemoteAddress) {
        ipAddress = reqSocketRemoteAddress
    }
    else if (reqConnectionSocketRemoteAddress) {
        ipAddress = reqConnectionSocketRemoteAddress
    }
    else if (reqInfoRemoteAddress) {
        ipAddress = reqInfoRemoteAddress
    }

    // return null if we cannot find an address
    else {
        ipAddress = null;
    }

    return ipAddress;
}

/**
 * Expose mode public functions
 */
exports.getClientIp = getClientIp;

/**
 * Expose a default implemtation for a connect middleware
 *
 * @options.attributeName - name of attribute to augment request object with
 */
exports.mw = function(options) {
    if (!options) options = {};
    var attr = options.attributeName || "clientIp";
    return function(req, res, next) {
        req[attr] = getClientIp(req);
        next();
    }
};
<commit_msg>Return once we find something<commit_after>/**
 * Author: petar bojinov - @pbojinov
 * Date: 01/27/16
 */

'use strict';

/**
 * Get client IP address
 *
 * Will return 127.0.0.1 when testing locally
 * Useful when you need the user ip for geolocation or serving localized content
 *
 * @method getClientIp
 * @param req
 * @returns {string} ip
 */
function getClientIp(req) {

    // the ipAddress we return
    var ipAddress;

    // workaround to get real client IP
    // most likely because our app will be behind a [reverse] proxy or load balancer
    if (req.headers) {
        if ((ipAddress = req.headers['x-client-ip'])) {
            return ipAddress;
        }

        var forwardedForAlt = req.headers['x-forwarded-for'];
        // (typically when your node app is behind a load-balancer (eg. AWS ELB) or proxy)
        if (forwardedForAlt) {
            // x-forwarded-for may return multiple IP addresses in the format:
            // "client IP, proxy 1 IP, proxy 2 IP"
            // Therefore, the right-most IP address is the IP address of the most recent proxy
            // and the left-most IP address is the IP address of the originating client.
            // source: http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/x-forwarded-headers.html
            var forwardedIps = forwardedForAlt.split(',');
            return forwardedIps[0];
        }

        // (default nginx proxy/fcgi)
        // alternative to x-forwarded-for, used by some proxies
        if ((ipAddress = req.headers['x-real-ip'])) {
            return ipAdress;
        }

        // (Rackspace LB and Riverbed's Stingray)
        // http://www.rackspace.com/knowledge_center/article/controlling-access-to-linux-cloud-sites-based-on-the-client-ip-address
        // https://splash.riverbed.com/docs/DOC-1926
        if ((ipAddress = req.headers['x-cluster-client-ip'])) {
            return ipAddress;
        }

        if ((ipAddress = req.headers['x-forwarded'])) {
            return ipAddress;
        }

        if ((ipAddress = req.headers['forwarded-for'])) {
            return ipAddress;
        }

        if ((ipAddress = req.headers['forwarded'])) {
            return ipAddress;
        }
    }

    // remote address check
    var reqConnectionRemoteAddress = req.connection ? req.connection.remoteAddress : null;
    var reqSocketRemoteAddress = req.socket ? req.socket.remoteAddress : null;
    var reqConnectionSocketRemoteAddress = (req.connection && req.connection.socket) ? req.connection.socket.remoteAddress : null;
    var reqInfoRemoteAddress = req.info ? req.info.remoteAddress : null;

    // remote address checks
    if ((ipAddress = req.connection && req.connection.remoteAddress)) {
        return ipAddress;
    }
    if ((ipAddress = req.socket && req.socket.remoteAddress)) {
        return ipAddress;
    }
    if ((ipAddress = req.connection && req.connection.socket && req.connection.socket.remoteAddress)) {
        return ipAddress;
    }
    if ((ipAddress = req.info && req.info.remoteAddress)) {
        return ipAddress;
    }

    // return null if we cannot find an address
    return null;
}

/**
 * Expose mode public functions
 */
exports.getClientIp = getClientIp;

/**
 * Expose a default implemtation for a connect middleware
 *
 * @options.attributeName - name of attribute to augment request object with
 */
exports.mw = function(options) {
    if (!options) options = {};
    var attr = options.attributeName || "clientIp";
    return function(req, res, next) {
        req[attr] = getClientIp(req);
        next();
    }
};
<|endoftext|>