<commit_before>/*!
 * Fryr v1.2.2
 * Command location.hash like a cook in the kitchen
 * MIT License
 */

(function (window, factory) {
  'use strict';

  if (typeof define === 'function' && define.amd) {
    define([], factory(window));
  } else if (typeof exports === 'object') {
    module.exports = factory(window);
  } else {
    window.Fryr = factory(window);
  }

})(window, function factory(window) {
  'use strict';

  /**
   * Private variable used to hold the callback function
   * Necessary for the destory method when we decouple the event listener
   * @type {Function}
   */
  var hashCallback;

  /**
   * Remove all traces of a hash if it's blank
   * @private
   * @param {String} hash - The existing hash
   * @see {@link http://stackoverflow.com/a/5298684}
   * @fires history.pushState OR window.onhashchange
   */
  function removeHashIfBlank(hash) {
    if(hash === '#') {
      // Prevent scrolling by storing the page's current scroll offset
      var scrollV = document.body.scrollTop;
      var scrollH = document.body.scrollLeft;

      window.location.hash = '';

      // Restore the scroll offset
      document.body.scrollTop = scrollV;
      document.body.scrollLeft = scrollH;

    } else {
      // If the hash isn't blank, fire onhashchange
      window.location.hash = hash;

    }
  }

  /**
   * Delete value based on key
   * @private
   * @param {String} key - Param to target
   * @param {String|Number} value - Value to delete from param
   */
  function removeValue(key, value) {
    var hash = window.location.hash;
    // check for key, anything between key and value, the value itself, and optionally the trailing comma
    var regex_for_value = new RegExp('(' + key + '=.*)(' + value + ',?)');
    // results come back [<search through value>, <search before value>, <value>]
    var regex_match = hash.match(regex_for_value);
    // replace <search through value> with everything before <value>
    // Key is included in search in case multiple keys have the same value
    hash = hash.replace(regex_match[0], regex_match[1]);

    // Remove trailing commas, ,&, and =,
    hash = hash.replace(/,$|(,(?=&))|((?==),)/, '')

    removeHashIfBlank(hash);
  }

  /**
   * Add value based on key
   * @private
   * @param {String} key - Param to target
   * @param {String|Number} value - Value to add to param
   * @param {Boolean} should_replace_value - if false, value will be appended to the param
   * @fires window.onhashchange
   */
  function addValue(key, value, should_replace_value) {
    var hash = window.location.hash;

    var old_value = param(key);
    var new_value;

    // If it's blank or is the value of the next param
    if(old_value.charAt(0) === '&' || old_value === '') {
      old_value = key + '=';
      new_value = old_value + value;

    } else {
      old_value = key + '=' + old_value;

      // If the value of the param should be replaced, don't append it to the existing value
      new_value = should_replace_value ? (key + '=' + value) : (old_value + ',' + value);
    }

    hash = hash.replace(old_value, new_value);

    window.location.hash = hash;
  }

  /**
   * Remove key from hash. Key's value must be removed prior to executing this function
   * @private
   * @param {String} key - Key to search and destroy
   */
  function removeKey(key) {
    var hash = window.location.hash;
    var key_search = new RegExp('[?&]' + key + '=', 'g');

    hash = hash.replace(key_search, '');
    // if initial key removed, replace ampersand with question
    hash = hash.replace('#&', '#?');

    removeHashIfBlank(hash);
  }

  /**
   * @private
   * @see {@link Fryr#param documentation in the public `param` function}
   */
  function param(key) {
    if(!window.location.hash) {
      return '';
    }

    var hash = window.location.hash;
    var search = new RegExp('#.*[?&]' + key + '=([^&]+)(&|$)');
    var key_value = hash.match(search);

    return (key_value ? key_value[1] : '');
  }

  /**
   * Apply value to variable if it has none
   * @private
   * @param {*} variable Variable to set default to
   * @param {*} value - Default value to attribute to variable
   * @return {*} Existing value or passed value argument
   */
  function setDefault(variable, value){
    return (typeof variable === 'undefined') ? value : variable;
  }

  /**
   * Remove key/value if present in hash; add key/value if not present in hash
   * @private
   * @param {String} key - Param key to query against
   * @param {String|Number} value - Value for param key
   * @param {Boolean} key_is_required - If the key is not required, it will be removed from the hash
   * @param {Boolean} should_replace_value - If false, value will be appended to the key
   * @see {@link Fryr#update}
   * @see {@link Fryr#append}
   * @fires window.onhashchange
   */
  function update(key, value, key_is_required, should_replace_value) {
    var hash = window.location.hash;

    // Ensure key exists in the hash
    if(hash.indexOf(key) !== -1) {
      var key_value = param(key);

      // If the key is required or value isn't blank and is not in key_value
      var value_not_in_key_value = key_value.split(',').indexOf(value) === -1;
      if (key_is_required || (value_not_in_key_value && value !== '')) {

        // add the value, replacing it if necessary
        addValue(key, value, should_replace_value);

      } else {

        // If the value is blank, remove the original value from the key
        if(value === '') {
          removeValue(key, key_value);

        // Otherwise remove the vanilla value if it's different than the original value
        // or value should not be replaced (appended)
        } else {
          if(key_value !== value || !should_replace_value) {
            removeValue(key, value);
          }

        }

        // If key's value is blank, remove it from hash
        if(param(key) === '') {
          removeKey(key);
        }

      }

    // Add key if it doesn't exist
    } else {

      if(window.location.hash && window.location.hash !== '#') {
        window.location.hash += '&' + key + '=' + value;
      } else {
        // Use a question mark if first key
        window.location.hash = '?' + key + '=' + value;
      }

    }
  }

  /**
   * Call once to initialize filtering
   * @param {Function} hashChangeCallback - Called on every hashchange
   *   @param {Object} Updated params
   * @param {Object} [defaults={}] - Key/value pairs for values that should be added on init. Pass {} to skip defaults
   * @param {Boolean} [call_on_init=true] - Execute callback on initialization. Always true if defaults is supplied
   * @return {Fryr}
   */
  function Fryr(hashChangeCallback, defaults, call_on_init) {
    defaults = setDefault(defaults, {});
    call_on_init = setDefault(call_on_init, true);

    // Set for the privateHashChange
    var _this = this;

    /**
     * Very important object holder
     * @type {Object}
     */
    this.params = {};

    /**
     * Callback with new params. Callback defined in initialization
     * @private
     * @fires hashChangeCallback
     */
    function privateHashChange() {
      var params = _this.parse();
      hashChangeCallback.call(_this, params);
    }

    hashCallback = privateHashChange;

    window.addEventListener('hashchange', hashCallback);

    // Apply defaults (if present) to hash, which will file window.onhashchange
    if( Object.keys(defaults).length && window.location.hash === '' ) {
      this.merge(defaults, true);

    // Execute the callback on load
    } else if(call_on_init) {
      privateHashChange.call(this);

    }

    return this;
  }

  Fryr.prototype = {

    /**
     * Replace key/value if present in hash; add key/value if not present in hash
     * @param {String} key - Param key to query against
     * @param {String|Number} value - Value for param key
     * @param {Boolean} [key_is_required=false] - if the key is not required, it will be removed from the hash
     * @see {@link Fryr#append}
     */
    update: function(key, value, key_is_required) {
      key_is_required = setDefault(key_is_required, false);
      update(key, value, key_is_required, true);
    },

    /**
     * Add value to key's value in a comma-delineated list if it's not present in hash
     * @param {String} key - Param key to query against
     * @param {String|Number} value - Value for param key
     * @see {@link Fryr#update}
     */
    append: function(key, value) {
      update(key, value, false, false);
    },

    /**
     * Evaluate the hash
     * @return {Object} Key/value hash of the hash broken down by params
     */
    parse: function() {
      var hash = window.location.hash;
      var params;

      // clear zombie keys and values
      this.params = {};

      if(window.location.hash && /\?/g.test(hash)) {
        params = hash.split('?')[1];
        params = params.split('&');

        // Separate params into key values
        for(var i = 0; i < params.length; i++) {
          var key_value = params[i].split('=');
          var key = key_value[0];
          var value = key_value[1];

          this.params[key] = value;
        }
      }

      return this.params;
    },

    /**
     * Change a JSON object into a string for the hash
     * @param {Object|String} obj - object to convert
     * @return {String|Boolean} For use in window.location.hash. Returns false if param is not object or string
     */
    convert: function(obj) {
      if( obj.constructor === String ) {
        obj = JSON.parse(obj);
      }

      // Escape if we're not dealing with an object
      if( obj.constructor !== Object ) {
        return false;
      }

      var keys = Object.keys(obj);
      // Set start with a ?
      var new_hash = '?';

      // Loop through all keys in the obj
      for(var i = 0; i < keys.length; i++) {
        var key = keys[i];
        var value = obj[ key ];

        if (value === '') {
          continue;
        }

        if( value.constructor === Array ) {
          value = value.join(',');
        }

        // On next key, if it isn't the first, precede with an ampersand
        if(new_hash !== '?') {
          new_hash += '&';
        }

        // Append key/value to new_hash
        new_hash += key + '=' + value;
      }

      if (new_hash === '?') {
        new_hash = '';
      }

      return new_hash;
    },

    /**
     * Wipe out or selectively replace keys in params
     * @param {Object|String} obj - Query to replace
     * @param {Boolean} [replace_all=false] - Whether or not to blast existing params away or replace only changed keys
     * @fires window.onhashchange
     * @return {String} The new hash
     */
    merge: function(obj, replace_all) {
      replace_all = setDefault(replace_all, false);

      // If it's a string, convert to an object
      if( obj.constructor === String ) {
        obj = JSON.parse(obj);
      }

      // Override or add key values from existing params and put them into the object
      if( !replace_all ) {
        var new_params = this.parse();

        var keys = Object.keys(new_params);

        for(var i = 0; i < keys.length; i++) {
          var key = keys[i];
          var value = new_params[ key ];

          if(!obj.hasOwnProperty(key)) {
            obj[key] = value;
          }
        }
      }

      // Change hash to string; if replace_all is false, original value is used
      var new_hash = this.convert(obj);

      window.location.hash = '#' + new_hash;

      return new_hash;
    },

    /**
     * Retrieve a key's value
     * @param {String} key - Param to target
     * @example
     * window.location.hash = '?color=blue'
     * fryr.param('color') // => 'blue'
     * @return {String} The value of the key
     */
    param: function(key) {
      return param(key);
    },

    /**
     * Determine if param is blank or undefined
     * @param {String} key - Param to target
     * @return {Boolean}
     */
    paramPresent: function(key) {
      var value = this.params[key];
      return (typeof value !== 'undefined' && value !== '');
    },

    /**
     * Destroy current initialization, unbind hashchange listener, and reset the hash to an empty state
     * @param {Boolean} [retain_hash=false] - Keep items in hash
     */
    destroy: function(retain_hash){
      retain_hash = setDefault(retain_hash, false);

      window.removeEventListener('hashchange', hashCallback);

      if(!retain_hash) {
        window.location.hash = '';
      }
    }
  };

  return Fryr;

});
<commit_msg>replace deprecated document.body with document.documentElement<commit_after>/*!
 * Fryr v1.2.2
 * Command location.hash like a cook in the kitchen
 * MIT License
 */

(function (window, factory) {
  'use strict';

  if (typeof define === 'function' && define.amd) {
    define([], factory(window));
  } else if (typeof exports === 'object') {
    module.exports = factory(window);
  } else {
    window.Fryr = factory(window);
  }

})(window, function factory(window) {
  'use strict';

  /**
   * Private variable used to hold the callback function
   * Necessary for the destory method when we decouple the event listener
   * @type {Function}
   */
  var hashCallback;

  /**
   * Remove all traces of a hash if it's blank
   * @private
   * @param {String} hash - The existing hash
   * @see {@link http://stackoverflow.com/a/5298684}
   * @fires history.pushState OR window.onhashchange
   */
  function removeHashIfBlank(hash) {
    if(hash === '#') {
      // Prevent scrolling by storing the page's current scroll offset
      var scrollV = document.documentElement.scrollTop;
      var scrollH = document.documentElement.scrollLeft;

      window.location.hash = '';

      // Restore the scroll offset
      document.documentElement.scrollTop = scrollV;
      document.documentElement.scrollLeft = scrollH;

    } else {
      // If the hash isn't blank, fire onhashchange
      window.location.hash = hash;

    }
  }

  /**
   * Delete value based on key
   * @private
   * @param {String} key - Param to target
   * @param {String|Number} value - Value to delete from param
   */
  function removeValue(key, value) {
    var hash = window.location.hash;
    // check for key, anything between key and value, the value itself, and optionally the trailing comma
    var regex_for_value = new RegExp('(' + key + '=.*)(' + value + ',?)');
    // results come back [<search through value>, <search before value>, <value>]
    var regex_match = hash.match(regex_for_value);
    // replace <search through value> with everything before <value>
    // Key is included in search in case multiple keys have the same value
    hash = hash.replace(regex_match[0], regex_match[1]);

    // Remove trailing commas, ,&, and =,
    hash = hash.replace(/,$|(,(?=&))|((?==),)/, '')

    removeHashIfBlank(hash);
  }

  /**
   * Add value based on key
   * @private
   * @param {String} key - Param to target
   * @param {String|Number} value - Value to add to param
   * @param {Boolean} should_replace_value - if false, value will be appended to the param
   * @fires window.onhashchange
   */
  function addValue(key, value, should_replace_value) {
    var hash = window.location.hash;

    var old_value = param(key);
    var new_value;

    // If it's blank or is the value of the next param
    if(old_value.charAt(0) === '&' || old_value === '') {
      old_value = key + '=';
      new_value = old_value + value;

    } else {
      old_value = key + '=' + old_value;

      // If the value of the param should be replaced, don't append it to the existing value
      new_value = should_replace_value ? (key + '=' + value) : (old_value + ',' + value);
    }

    hash = hash.replace(old_value, new_value);

    window.location.hash = hash;
  }

  /**
   * Remove key from hash. Key's value must be removed prior to executing this function
   * @private
   * @param {String} key - Key to search and destroy
   */
  function removeKey(key) {
    var hash = window.location.hash;
    var key_search = new RegExp('[?&]' + key + '=', 'g');

    hash = hash.replace(key_search, '');
    // if initial key removed, replace ampersand with question
    hash = hash.replace('#&', '#?');

    removeHashIfBlank(hash);
  }

  /**
   * @private
   * @see {@link Fryr#param documentation in the public `param` function}
   */
  function param(key) {
    if(!window.location.hash) {
      return '';
    }

    var hash = window.location.hash;
    var search = new RegExp('#.*[?&]' + key + '=([^&]+)(&|$)');
    var key_value = hash.match(search);

    return (key_value ? key_value[1] : '');
  }

  /**
   * Apply value to variable if it has none
   * @private
   * @param {*} variable Variable to set default to
   * @param {*} value - Default value to attribute to variable
   * @return {*} Existing value or passed value argument
   */
  function setDefault(variable, value){
    return (typeof variable === 'undefined') ? value : variable;
  }

  /**
   * Remove key/value if present in hash; add key/value if not present in hash
   * @private
   * @param {String} key - Param key to query against
   * @param {String|Number} value - Value for param key
   * @param {Boolean} key_is_required - If the key is not required, it will be removed from the hash
   * @param {Boolean} should_replace_value - If false, value will be appended to the key
   * @see {@link Fryr#update}
   * @see {@link Fryr#append}
   * @fires window.onhashchange
   */
  function update(key, value, key_is_required, should_replace_value) {
    var hash = window.location.hash;

    // Ensure key exists in the hash
    if(hash.indexOf(key) !== -1) {
      var key_value = param(key);

      // If the key is required or value isn't blank and is not in key_value
      var value_not_in_key_value = key_value.split(',').indexOf(value) === -1;
      if (key_is_required || (value_not_in_key_value && value !== '')) {

        // add the value, replacing it if necessary
        addValue(key, value, should_replace_value);

      } else {

        // If the value is blank, remove the original value from the key
        if(value === '') {
          removeValue(key, key_value);

        // Otherwise remove the vanilla value if it's different than the original value
        // or value should not be replaced (appended)
        } else {
          if(key_value !== value || !should_replace_value) {
            removeValue(key, value);
          }

        }

        // If key's value is blank, remove it from hash
        if(param(key) === '') {
          removeKey(key);
        }

      }

    // Add key if it doesn't exist
    } else {

      if(window.location.hash && window.location.hash !== '#') {
        window.location.hash += '&' + key + '=' + value;
      } else {
        // Use a question mark if first key
        window.location.hash = '?' + key + '=' + value;
      }

    }
  }

  /**
   * Call once to initialize filtering
   * @param {Function} hashChangeCallback - Called on every hashchange
   *   @param {Object} Updated params
   * @param {Object} [defaults={}] - Key/value pairs for values that should be added on init. Pass {} to skip defaults
   * @param {Boolean} [call_on_init=true] - Execute callback on initialization. Always true if defaults is supplied
   * @return {Fryr}
   */
  function Fryr(hashChangeCallback, defaults, call_on_init) {
    defaults = setDefault(defaults, {});
    call_on_init = setDefault(call_on_init, true);

    // Set for the privateHashChange
    var _this = this;

    /**
     * Very important object holder
     * @type {Object}
     */
    this.params = {};

    /**
     * Callback with new params. Callback defined in initialization
     * @private
     * @fires hashChangeCallback
     */
    function privateHashChange() {
      var params = _this.parse();
      hashChangeCallback.call(_this, params);
    }

    hashCallback = privateHashChange;

    window.addEventListener('hashchange', hashCallback);

    // Apply defaults (if present) to hash, which will file window.onhashchange
    if( Object.keys(defaults).length && window.location.hash === '' ) {
      this.merge(defaults, true);

    // Execute the callback on load
    } else if(call_on_init) {
      privateHashChange.call(this);

    }

    return this;
  }

  Fryr.prototype = {

    /**
     * Replace key/value if present in hash; add key/value if not present in hash
     * @param {String} key - Param key to query against
     * @param {String|Number} value - Value for param key
     * @param {Boolean} [key_is_required=false] - if the key is not required, it will be removed from the hash
     * @see {@link Fryr#append}
     */
    update: function(key, value, key_is_required) {
      key_is_required = setDefault(key_is_required, false);
      update(key, value, key_is_required, true);
    },

    /**
     * Add value to key's value in a comma-delineated list if it's not present in hash
     * @param {String} key - Param key to query against
     * @param {String|Number} value - Value for param key
     * @see {@link Fryr#update}
     */
    append: function(key, value) {
      update(key, value, false, false);
    },

    /**
     * Evaluate the hash
     * @return {Object} Key/value hash of the hash broken down by params
     */
    parse: function() {
      var hash = window.location.hash;
      var params;

      // clear zombie keys and values
      this.params = {};

      if(window.location.hash && /\?/g.test(hash)) {
        params = hash.split('?')[1];
        params = params.split('&');

        // Separate params into key values
        for(var i = 0; i < params.length; i++) {
          var key_value = params[i].split('=');
          var key = key_value[0];
          var value = key_value[1];

          this.params[key] = value;
        }
      }

      return this.params;
    },

    /**
     * Change a JSON object into a string for the hash
     * @param {Object|String} obj - object to convert
     * @return {String|Boolean} For use in window.location.hash. Returns false if param is not object or string
     */
    convert: function(obj) {
      if( obj.constructor === String ) {
        obj = JSON.parse(obj);
      }

      // Escape if we're not dealing with an object
      if( obj.constructor !== Object ) {
        return false;
      }

      var keys = Object.keys(obj);
      // Set start with a ?
      var new_hash = '?';

      // Loop through all keys in the obj
      for(var i = 0; i < keys.length; i++) {
        var key = keys[i];
        var value = obj[ key ];

        if (value === '') {
          continue;
        }

        if( value.constructor === Array ) {
          value = value.join(',');
        }

        // On next key, if it isn't the first, precede with an ampersand
        if(new_hash !== '?') {
          new_hash += '&';
        }

        // Append key/value to new_hash
        new_hash += key + '=' + value;
      }

      if (new_hash === '?') {
        new_hash = '';
      }

      return new_hash;
    },

    /**
     * Wipe out or selectively replace keys in params
     * @param {Object|String} obj - Query to replace
     * @param {Boolean} [replace_all=false] - Whether or not to blast existing params away or replace only changed keys
     * @fires window.onhashchange
     * @return {String} The new hash
     */
    merge: function(obj, replace_all) {
      replace_all = setDefault(replace_all, false);

      // If it's a string, convert to an object
      if( obj.constructor === String ) {
        obj = JSON.parse(obj);
      }

      // Override or add key values from existing params and put them into the object
      if( !replace_all ) {
        var new_params = this.parse();

        var keys = Object.keys(new_params);

        for(var i = 0; i < keys.length; i++) {
          var key = keys[i];
          var value = new_params[ key ];

          if(!obj.hasOwnProperty(key)) {
            obj[key] = value;
          }
        }
      }

      // Change hash to string; if replace_all is false, original value is used
      var new_hash = this.convert(obj);

      window.location.hash = '#' + new_hash;

      return new_hash;
    },

    /**
     * Retrieve a key's value
     * @param {String} key - Param to target
     * @example
     * window.location.hash = '?color=blue'
     * fryr.param('color') // => 'blue'
     * @return {String} The value of the key
     */
    param: function(key) {
      return param(key);
    },

    /**
     * Determine if param is blank or undefined
     * @param {String} key - Param to target
     * @return {Boolean}
     */
    paramPresent: function(key) {
      var value = this.params[key];
      return (typeof value !== 'undefined' && value !== '');
    },

    /**
     * Destroy current initialization, unbind hashchange listener, and reset the hash to an empty state
     * @param {Boolean} [retain_hash=false] - Keep items in hash
     */
    destroy: function(retain_hash){
      retain_hash = setDefault(retain_hash, false);

      window.removeEventListener('hashchange', hashCallback);

      if(!retain_hash) {
        window.location.hash = '';
      }
    }
  };

  return Fryr;

});
<|endoftext|>


<commit_before>var HtmlWebpackPlugin = require('html-webpack-plugin');
var webpack = require('webpack');

module.exports = {
  entry: [
    './src/entry.js',
  ],
  resolve: {
    root: __dirname,
  },
  output: {
    path: './build',
    filename: 'bundle-[hash].js'
  },
  module: {
    preLoaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'jscs-loader'
      }, {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'jshint-loader'
      }
    ],
    loaders: [
      {test: /\.pug$/, loader: 'pug-loader'},
      {test: /\.css$/, loader: 'style!css'},
      {test: /\.(jpe?g|png|gif|svg)$/i, loader:'file'},
      {test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file'},
      {test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'file'},
      {test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'file'},
      {test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'file'},
      {test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'file'},
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({ template: 'src/index.pug', }),
    new webpack.optimize.DedupePlugin(), // removes duplicate code
    new webpack.optimize.OccurrenceOrderPlugin(true), // optimises size
  ],
  jscs: {
    preset: 'airbnb',
    requirePaddingNewLinesAfterBlocks: {
      allExcept: ["inCallExpressions", "inNewExpressions", "inArrayExpressions", "inProperties"]
    },
    requireSpacesInAnonymousFunctionExpression: {
      beforeOpeningCurlyBrace: true
    },
    requireSpacesInsideObjectBrackets: false,
    maximumLineLength: {
      value: 140
    },
  },
  jshint: {
    browser: true,
  },
  devServer: {
    host: '0.0.0.0',
  },
};
<commit_msg>use generic name for bundle output<commit_after>var HtmlWebpackPlugin = require('html-webpack-plugin');
var webpack = require('webpack');

module.exports = {
  entry: [
    './src/entry.js',
  ],
  resolve: {
    root: __dirname,
  },
  output: {
    path: './build',
    filename: '[name]-[hash].js'
  },
  module: {
    preLoaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'jscs-loader'
      }, {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'jshint-loader'
      }
    ],
    loaders: [
      {test: /\.pug$/, loader: 'pug-loader'},
      {test: /\.css$/, loader: 'style!css'},
      {test: /\.(jpe?g|png|gif|svg)$/i, loader:'file'},
      {test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file'},
      {test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'file'},
      {test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'file'},
      {test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'file'},
      {test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'file'},
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({ template: 'src/index.pug', }),
    new webpack.optimize.DedupePlugin(), // removes duplicate code
    new webpack.optimize.OccurrenceOrderPlugin(true), // optimises size
  ],
  jscs: {
    preset: 'airbnb',
    requirePaddingNewLinesAfterBlocks: {
      allExcept: ["inCallExpressions", "inNewExpressions", "inArrayExpressions", "inProperties"]
    },
    requireSpacesInAnonymousFunctionExpression: {
      beforeOpeningCurlyBrace: true
    },
    requireSpacesInsideObjectBrackets: false,
    maximumLineLength: {
      value: 140
    },
  },
  jshint: {
    browser: true,
  },
  devServer: {
    host: '0.0.0.0',
  },
};
<|endoftext|>


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

var _ = require('underscore');
var util = require('util');
var url = require('url');
var hash = require('mhash').hash;

function FileStorageDB (db, cfg) {
	this.db = db;
	this.cfg = cfg;
}
util.inherits(FileStorageDB, require('./objects.js').DBSubsystemBase);

FileStorageDB.prototype.handle = function(req, res) {
	var loc = url.parse(req.url, true);
	var fsmatch = loc.pathname.match(this.cfg.fsdb.reqregex);

	if (!fsmatch)
		return false;

	var filename = fsmatch[fsmatch.length - 1];

	this.query('SELECT * FROM httpresources WHERE name = ?', [filename], function(rows) {
		if (rows.length == 0) {
			res.writeHead(404, {'Content-Type': 'text/plain'});
			res.end('Not found');
			return;
		}

		var r = rows[0];
		var headers = {
			'Content-Type': r.mime,
			'Cache-Control': r.cache ? 'max-age=100000000' : 'no-cache',
			'Last-Modified': new Date(r.uploadtime * 1000).toString(),
			'Date': new Date().toString(),
			'X-Sotrade-Hash': r.hash,
			'X-Sotrade-Source-User-ID': r.user,
			'X-Sotrade-Name': r.name,
			'X-Sotrade-Role': r.role,
			'X-Sotrade-Groupassoc': r.groupassoc
		};

		if (r.gzipped)
			headers['Content-Encoding'] = 'gzip';

		if (r.headers)
			headers = _.deepupdate(headers, JSON.parse(r.headers));

		res.writeHead(200, headers);
		res.end(r.content);
	});

	return true;
}

FileStorageDB.prototype.publish = function(query, user, access, cb) {
	var content = query.content;
	var uniqrole = this.cfg.fsdb.uniqroles[query.role];

	if (query.base64)
		content = new Buffer(query.content, 'base64');
	this.query('SELECT SUM(LENGTH(content)) AS total FROM httpresources WHERE user = ?', [user ? user.id : null], function(res) {
		var total = uniqrole ? 0 : res[0].total;
		if (content.length + total > this.cfg.fsdb.userquota && !access.has('filesystem'))
			return cb('publish-quota-exceed');
		if (this.cfg.fsdb.allowroles.indexOf(query.role) == -1 && !access.has('filesystem'))
			return cb('publish-inacceptable-role');
		if (this.cfg.fsdb.allowmime.indexOf(query.mime) == -1 && !access.has('filesystem'))
			return cb('publish-inacceptable-mime');

		var filehash = hash('md5', content);
		if (!query.name) query.name = filehash;
		var filename = (user ? user.id + '-' : '') + ((new Date().getTime()) % 8192) + '-' + query.name.replace(/[^-_+\w\.]/g, '');
		var url = this.cfg.fsdb.puburl.replace(/\{\$hostname\}/g, this.cfg.hostname).replace(/\{\$name\}/g, filename);

		var continueAfterDelPrevious = _.bind(function() {
			this.query('INSERT INTO httpresources(user, name, url, mime, hash, role, uploadtime, content, groupassoc) '+
				'VALUES (?, ?, ?, ?, ?, ?, UNIX_TIMESTAMP(), ?, ?)',
				[user ? user.id : null, filename, url, query.mime, filehash, query.role, content, query.__groupassoc__], function() {
				return cb('publish-success');
			});
		}, this);

		if (uniqrole && user && !(access.has('filesystem') && query.retainOldFiles)) {
			var sql = 'DELETE FROM httpresources WHERE role = ? ';
			var dataarr = [query.role];

			for (var i = 0; i < uniqrole.length; ++i) {
				var fieldname = uniqrole[i];
				sql += 'AND `' + fieldname + '` = ? ';

				switch (fieldname) {
					case 'user': dataarr.push(user.id); break;
					case 'groupassoc': dataarr.push(query.__groupassoc__); break;
					default: this.emit('error', new Error('Unknown uniqrole field: ' + fieldname));
				}
			}

			this.query(sql, dataarr, continueAfterDelPrevious);
		} else {
			continueAfterDelPrevious();
		}
	});
}

exports.FileStorageDB = FileStorageDB;

})();
<commit_msg><commit_after>(function () { "use strict";

var _ = require('underscore');
var util = require('util');
var url = require('url');
var hash = require('mhash').hash;

function FileStorageDB (db, cfg) {
	this.db = db;
	this.cfg = cfg;
}
util.inherits(FileStorageDB, require('./objects.js').DBSubsystemBase);

FileStorageDB.prototype.handle = function(req, res) {
	var loc = url.parse(req.url, true);
	var fsmatch = loc.pathname.match(this.cfg.fsdb.reqregex);

	if (!fsmatch)
		return false;

	var filename = fsmatch[fsmatch.length - 1];

	this.query('SELECT * FROM httpresources WHERE name = ?', [filename], function(rows) {
		if (rows.length == 0) {
			res.writeHead(404, {'Content-Type': 'text/plain'});
			res.end('Not found');
			return;
		}

		assert.equal(rows.length, 1);

		var r = rows[0];
		var headers = {
			'Content-Type': r.mime,
			'Cache-Control': r.cache ? 'max-age=100000000' : 'no-cache',
			'Last-Modified': new Date(r.uploadtime * 1000).toString(),
			'Date': new Date().toString(),
			'X-Sotrade-Hash': r.hash,
			'X-Sotrade-Source-User-ID': r.user,
			'X-Sotrade-Name': r.name,
			'X-Sotrade-Role': r.role,
			'X-Sotrade-Groupassoc': r.groupassoc
		};

		if (r.gzipped)
			headers['Content-Encoding'] = 'gzip';

		if (r.headers)
			headers = _.deepupdate(headers, JSON.parse(r.headers));

		res.writeHead(200, headers);
		res.end(r.content);
	});

	return true;
}

FileStorageDB.prototype.publish = function(query, user, access, cb) {
	var content = query.content;
	var uniqrole = this.cfg.fsdb.uniqroles[query.role];

	if (query.base64)
		content = new Buffer(query.content, 'base64');
	this.query('SELECT SUM(LENGTH(content)) AS total FROM httpresources WHERE user = ?', [user ? user.id : null], function(res) {
		var total = uniqrole ? 0 : res[0].total;
		if (content.length + total > this.cfg.fsdb.userquota && !access.has('filesystem'))
			return cb('publish-quota-exceed');
		if (this.cfg.fsdb.allowroles.indexOf(query.role) == -1 && !access.has('filesystem'))
			return cb('publish-inacceptable-role');
		if (this.cfg.fsdb.allowmime.indexOf(query.mime) == -1 && !access.has('filesystem'))
			return cb('publish-inacceptable-mime');

		var filehash = hash('md5', content);
		if (!query.name) query.name = filehash;
		var filename = (user ? user.id + '-' : '') + ((new Date().getTime()) % 8192) + '-' + query.name.replace(/[^-_+\w\.]/g, '');
		var url = this.cfg.fsdb.puburl.replace(/\{\$hostname\}/g, this.cfg.hostname).replace(/\{\$name\}/g, filename);

		var continueAfterDelPrevious = _.bind(function() {
			this.query('INSERT INTO httpresources(user, name, url, mime, hash, role, uploadtime, content, groupassoc) '+
				'VALUES (?, ?, ?, ?, ?, ?, UNIX_TIMESTAMP(), ?, ?)',
				[user ? user.id : null, filename, url, query.mime, filehash, query.role, content, query.__groupassoc__], function() {
				return cb('publish-success');
			});
		}, this);

		if (uniqrole && user && !(access.has('filesystem') && query.retainOldFiles)) {
			var sql = 'DELETE FROM httpresources WHERE role = ? ';
			var dataarr = [query.role];

			for (var i = 0; i < uniqrole.length; ++i) {
				var fieldname = uniqrole[i];
				sql += 'AND `' + fieldname + '` = ? ';

				switch (fieldname) {
					case 'user': dataarr.push(user.id); break;
					case 'groupassoc': dataarr.push(query.__groupassoc__); break;
					default: this.emit('error', new Error('Unknown uniqrole field: ' + fieldname));
				}
			}

			this.query(sql, dataarr, continueAfterDelPrevious);
		} else {
			continueAfterDelPrevious();
		}
	});
}

exports.FileStorageDB = FileStorageDB;

})();
<|endoftext|>


<commit_before>/* eslint-env mocha */
/* eslint-disable */

const {expect} = require('chai')
const BFX = require('../index')
const _ = require('lodash')

describe('Errors', function () {
  const bfx = new BFX()
  const bfx_rest = bfx.rest
  this.timeout(5000)
  it('should error out if a bad endpoint is given', () => {
    expect(bfx_rest.make_public_request).to.throw(Error)
  })
  it('should fail on authenticated requests if no api_key and api_secret', () => {
    expect(bfx_rest.account_infos).to.throw(Error)
  })
})
describe('Public Endpoints', function () {
  const bfx = new BFX()
  const bfx_rest = bfx.rest
  this.timeout(5000)
  it('should get a ticker', (done) => {
    bfx_rest.ticker('BTCUSD', (error, data) => {
      expect(data).to.exist
      expect(_.has(data, ['mid',
        'bid',
        'ask',
        'last_price',
        'low',
        'high',
        'volume',
        'timestamp']))
      done()
    })
  })
  it('should get the today endpoint', (done) => {
    bfx_rest.today('BTCUSD', (error, data) => {
      expect(data).to.exist
      done()
    })
  })
  it('should get the stats', (done) => {
    bfx_rest.stats('BTCUSD', (error, data) => {
      expect(data).to.exist
      expect(_.has(data[0], ['period', 'volume']))
      expect(_.has(data[1], ['period', 'volume']))
      expect(_.has(data[2], ['period', 'volume']))
      done()
    })
  })
  it('should get the fundingbook', (done) => {
    bfx_rest.fundingbook('USD', (error, data) => {
      expect(data).to.exist
      expect(_.has(data, ['bids', 'asks']))
      expect(_.keys(data.bids[0])).is.eql(['rate', 'amount', 'period', 'timestamp', 'frr'])
      expect(_.keys(data.asks[0])).is.eql(['rate', 'amount', 'period', 'timestamp', 'frr'])
      expect(
                _.every(
                    [data.asks[0] + data.bids[0]]
                ), !NaN).ok
      done()
    })
  })

  it('should get the orderbook', (done) => {
    bfx_rest.orderbook('BTCUSD', (error, data) => {
      expect(data).to.exist
      expect(_.keys(data)).is.eql(['bids', 'asks'])
      expect(_.keys(data.bids[0])).is.eql(['price', 'amount', 'timestamp'])
      expect(_.keys(data.asks[0])).is.eql(['price', 'amount', 'timestamp'])
      expect(
                _.every(
                    [data.asks[0] + data.bids[0]]
                ), !NaN).ok
      done()
    })
  })
    // TODO API returns 1000 instead of 50`
  it.skip('should get recent trades', (done) => {
    bfx_rest.trades('BTCUSD', (error, data) => {
      expect(data).is.an.array
      expect(data.length).to.eql(50)
      expect(_.keys(data[0])).to.eql(['timestamp', 'tid', 'price', 'amount', 'exchange', 'type'])
      expect(
                _.map(
                    _.values(
                        data[0]
                    ), (v) => typeof (v)
                )).is.eql(['number', 'number', 'string', 'string', 'string', 'string'])
      done()
    })
  })
  it('should get recent lends', (done) => {
    bfx_rest.lends('USD', (error, data) => {
      expect(data).to.exist
      expect(data).is.an.array
      expect(data.length).to.eql(50)
      expect(_.keys(data[0])).to.eql(['rate', 'amount_lent', 'amount_used', 'timestamp'])
      expect(
                _.map(
                    _.values(
                        data[0]
                    ), (v) => typeof (v)
                )).is.eql(['string', 'string', 'string', 'number'])
      done()
    })
  })
  it('should get symbols', (done) => {
    bfx_rest.get_symbols((error, data) => {
      expect(data[0]).to.eql('btcusd')
      done()
    })
  })
  it('should get symbol details', (done) => {
    bfx_rest.symbols_details((error, data) => {
      expect(data).to.exist
      expect(data[0]).to.eql({
        pair: 'btcusd',
        price_precision: 5,
        initial_margin: '30.0',
        minimum_margin: '15.0',
        maximum_order_size: '2000.0',
        minimum_order_size: '0.01',
        expiration: 'NA'
      })
      done()
    })
  })
})
<commit_msg>test: fix test depending on live env<commit_after>/* eslint-env mocha */
/* eslint-disable */

const {expect} = require('chai')
const BFX = require('../index')
const _ = require('lodash')

describe('Errors', function () {
  const bfx = new BFX()
  const bfx_rest = bfx.rest
  this.timeout(5000)
  it('should error out if a bad endpoint is given', () => {
    expect(bfx_rest.make_public_request).to.throw(Error)
  })
  it('should fail on authenticated requests if no api_key and api_secret', () => {
    expect(bfx_rest.account_infos).to.throw(Error)
  })
})
describe('Public Endpoints', function () {
  const bfx = new BFX()
  const bfx_rest = bfx.rest
  this.timeout(5000)
  it('should get a ticker', (done) => {
    bfx_rest.ticker('BTCUSD', (error, data) => {
      expect(data).to.exist
      expect(_.has(data, ['mid',
        'bid',
        'ask',
        'last_price',
        'low',
        'high',
        'volume',
        'timestamp']))
      done()
    })
  })
  it('should get the today endpoint', (done) => {
    bfx_rest.today('BTCUSD', (error, data) => {
      expect(data).to.exist
      done()
    })
  })
  it('should get the stats', (done) => {
    bfx_rest.stats('BTCUSD', (error, data) => {
      expect(data).to.exist
      expect(_.has(data[0], ['period', 'volume']))
      expect(_.has(data[1], ['period', 'volume']))
      expect(_.has(data[2], ['period', 'volume']))
      done()
    })
  })
  it('should get the fundingbook', (done) => {
    bfx_rest.fundingbook('USD', (error, data) => {
      expect(data).to.exist
      expect(_.has(data, ['bids', 'asks']))
      expect(_.keys(data.bids[0])).is.eql(['rate', 'amount', 'period', 'timestamp', 'frr'])
      expect(_.keys(data.asks[0])).is.eql(['rate', 'amount', 'period', 'timestamp', 'frr'])
      expect(
                _.every(
                    [data.asks[0] + data.bids[0]]
                ), !NaN).ok
      done()
    })
  })

  it('should get the orderbook', (done) => {
    bfx_rest.orderbook('BTCUSD', (error, data) => {
      expect(data).to.exist
      expect(_.keys(data)).is.eql(['bids', 'asks'])
      expect(_.keys(data.bids[0])).is.eql(['price', 'amount', 'timestamp'])
      expect(_.keys(data.asks[0])).is.eql(['price', 'amount', 'timestamp'])
      expect(
                _.every(
                    [data.asks[0] + data.bids[0]]
                ), !NaN).ok
      done()
    })
  })
    // TODO API returns 1000 instead of 50`
  it.skip('should get recent trades', (done) => {
    bfx_rest.trades('BTCUSD', (error, data) => {
      expect(data).is.an.array
      expect(data.length).to.eql(50)
      expect(_.keys(data[0])).to.eql(['timestamp', 'tid', 'price', 'amount', 'exchange', 'type'])
      expect(
                _.map(
                    _.values(
                        data[0]
                    ), (v) => typeof (v)
                )).is.eql(['number', 'number', 'string', 'string', 'string', 'string'])
      done()
    })
  })
  it('should get recent lends', (done) => {
    bfx_rest.lends('USD', (error, data) => {
      expect(data).to.exist
      expect(data).is.an.array
      expect(data.length).to.eql(50)
      expect(_.keys(data[0])).to.eql(['rate', 'amount_lent', 'amount_used', 'timestamp'])
      expect(
                _.map(
                    _.values(
                        data[0]
                    ), (v) => typeof (v)
                )).is.eql(['string', 'string', 'string', 'number'])
      done()
    })
  })
  it('should get symbols', (done) => {
    bfx_rest.get_symbols((error, data) => {
      expect(data[0]).to.eql('btcusd')
      done()
    })
  })
  it('should get symbol details', (done) => {
    bfx_rest.symbols_details((error, data) => {
      expect(data).to.exist
      expect(data[0].pair).to.eql('btcusd')
      done()
    })
  })
})
<|endoftext|>


<commit_before>const webpack = require('webpack')
const path = require('path')
const validate = require('webpack-validator')
const merge = require('webpack-merge')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const parts = require('./webpack.parts')

const PORTS = {
  devServer: 3000
}

const PATHS = {
  build: path.join(__dirname, 'build'),
  modules: path.join(__dirname, 'node_modules'),
  publicPath: `http://localhost:${PORTS.devServer}/`,
  src: path.join(__dirname, 'src')
}

const ENTRIES = {
  dev: [ PATHS.src ],
  prod: PATHS.src
}

// Common config to all of our webpack builds, we can extend or modify it
// using merge (see below)
const common = {
  output: {
    path: PATHS.build,
    filename: 'mantecao.js',
    publicPath: PATHS.publicPath
  },

  module: {
    loaders: [
      {
        test: /.js$/,
        include: PATHS.src,
        exclude: PATHS.modules,
        loader: 'babel-loader', /* Converts ES6 to JS */
        query: {
          cacheDirectory: true
        }
      }
    ],
    preLoaders: [
      {
        test: /\.js$/,
        loaders: ['eslint'],
        include: PATHS.src
      }
    ]
  },

  resolve: {
    // Include the node_modules folder in the root path
    root: [
      path.join(__dirname, 'src')
    ],
    modulesDirectories: [
      path.join(__dirname, 'node_modules')
    ],
    extensions: ['', '.js', '.jsx']
  },

  plugins: [
    new HtmlWebpackPlugin({
      title: 'Mantecao'
    })
  ]
}

var config

// Here is where we modify our config based on which npm process started it
switch (process.env.npm_lifecycle_event) {
  case 'build':
    config = merge(
      common,
      {
        entry: ENTRIES.prod,
        devtool: 'source-map'
      }
    )
    break

  default:
    config = merge(
      common,
      { entry: ENTRIES.dev },
      { devtool: 'eval-source-map' },
      parts.devCSS(PATHS.src),
      parts.devServer({
        host: 'localhost',
        port: PORTS.devServer
      })
    )
}

module.exports = validate(config)
<commit_msg>Fix sass task on deve server<commit_after>const webpack = require('webpack')
const path = require('path')
const validate = require('webpack-validator')
const merge = require('webpack-merge')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const parts = require('./webpack.parts')

const PORTS = {
  devServer: 3000
}

const PATHS = {
  build: path.join(__dirname, 'build'),
  modules: path.join(__dirname, 'node_modules'),
  publicPath: `http://localhost:${PORTS.devServer}/`,
  src: path.join(__dirname, 'src')
}

const ENTRIES = {
  dev: [ PATHS.src ],
  prod: PATHS.src
}

// Common config to all of our webpack builds, we can extend or modify it
// using merge (see below)
const common = {
  output: {
    path: PATHS.build,
    filename: 'mantecao.js',
    publicPath: PATHS.publicPath
  },

  module: {
    loaders: [
      {
        test: /.js$/,
        include: PATHS.src,
        exclude: PATHS.modules,
        loader: 'babel-loader', /* Converts ES6 to JS */
        query: {
          cacheDirectory: true
        }
      }
    ],
    preLoaders: [
      {
        test: /\.js$/,
        loaders: ['eslint'],
        include: PATHS.src
      }
    ]
  },

  resolve: {
    // Include the node_modules folder in the root path
    root: [
      path.join(__dirname, 'src')
    ],
    modulesDirectories: [
      path.join(__dirname, 'node_modules')
    ],
    extensions: ['', '.js', '.jsx', '.scss']
  },

  plugins: [
    new HtmlWebpackPlugin({
      title: 'Mantecao'
    })
  ]
}

var config

// Here is where we modify our config based on which npm process started it
switch (process.env.npm_lifecycle_event) {
  case 'build':
    config = merge(
      common,
      {
        entry: ENTRIES.prod,
        devtool: 'source-map'
      }
    )
    break

  default:
    config = merge(
      common,
      { entry: ENTRIES.dev },
      { devtool: 'eval-source-map' },
      parts.devCSS(PATHS.src),
      parts.devServer({
        host: 'localhost',
        port: PORTS.devServer
      })
    )
}

module.exports = validate(config)
<|endoftext|>


<commit_before>'use strict';

var webpackVersion = require('webpack/package.json').version;
var typescript = require('typescript');
var execSync = require('child_process').execSync;

console.log('Using webpack version ' + webpackVersion);
console.log('Using typescript version ' + typescript.version);

execSync('npm run comparison-tests', { stdio: 'inherit' });
execSync('npm run execution-tests', { stdio: 'inherit' });
<commit_msg>Made execution tests run first as less likely to fail<commit_after>'use strict';

var webpackVersion = require('webpack/package.json').version;
var typescript = require('typescript');
var execSync = require('child_process').execSync;

console.log('Using webpack version ' + webpackVersion);
console.log('Using typescript version ' + typescript.version);

execSync('npm run execution-tests', { stdio: 'inherit' });
execSync('npm run comparison-tests', { stdio: 'inherit' });
<|endoftext|>


<commit_before>/*eslint no-console: 0*/
/*global __DEVELOPMENT__ webpackIsomorphicTools */
import 'babel-polyfill'
import Compression from 'compression'
import Express from 'express'
import path from 'path'

import React from 'react'
import ReactDOMServer from 'react-dom/server'
//import ReactDOMStream from 'react-dom-stream/server'
import createLocation from 'history/lib/createLocation'
//import DocumentMeta from 'react-document-meta'
import { RouterContext, match, createMemoryHistory } from 'react-router'
import Promise from 'bluebird'
import httpProxy from 'http-proxy'

import configureStore from '../src/store/configureStore'
import crateRoutes from '../src/routes/index'

import { Provider } from 'react-redux'
import config from './config'

import { NotFoundError } from '../src/lib/custom-error'
import { SITE_NAME, LINK_PREFIX, SITE_META } from '../src/constants/'
import _ from 'lodash'

const server = new Express()
const targetUrl = 'http://' + config.apiHost + ':' + config.apiPort
// create a proxy server to serve the API requests
const proxy = httpProxy.createProxyServer({
  target: targetUrl
})

server.set('views', path.join(__dirname, 'views'))
server.set('view engine', 'ejs')
server.use(Compression())
server.use(Express.static(path.join(__dirname, '../static')))
server.use(function (req, res, next) {
  res.header('Access-Control-Allow-Origin', 'http://www.twreporter.org/')
  res.header('Access-Control-Allow-Headers', 'X-Requested-With')
  next()
})

// mock apis
//server.get('/questions', (req, res)=> {
//  let { questions } = require('./mock_api');
//  res.send(questions);
//});
//
server.get('/robots.txt', (req, res) => {
  res.format({
    'text/plain': function () {
      res.status(200).render('robots')
    }
  })
})
// proxy to the API server
server.use('/api', (req, res) => {
  proxy.web(req, res)
})

// added the error handling to avoid https://github.com/nodejitsu/node-http-proxy/issues/527
proxy.on('error', (error, req, res) => {
  let json
  if (error.code !== 'ECONNRESET') {
    console.error('proxy error', error)
  }
  if (!res.headersSent) {
    res.writeHead(500, { 'content-type': 'application/json' })
  }
  json = { error: 'proxy_error', reason: error.message }
  res.end(JSON.stringify(json))
})

server.get('*', async function (req, res) {
  if (__DEVELOPMENT__) {
    // Do not cache webpack stats: the script file would change since
    // hot module replacement is enabled in the development env
    webpackIsomorphicTools.refresh()
  }
  let history = createMemoryHistory()
  let store = configureStore()

  let routes = crateRoutes(history)

  let location = createLocation(req.url)

  match({ routes, location }, (error, redirectLocation, renderProps) => {
    if (redirectLocation) {
      res.redirect(301, redirectLocation.pathname + redirectLocation.search)
    } else if (error) {
      res.status(500).render('500')
    } else if (renderProps == null) {
      res.status(404).render('404')
    } else {

      let [ getCurrentUrl, unsubscribe ] = subscribeUrl()
      let reqUrl = location.pathname + location.search
      store.dispatch({
        type: 'DETECT_DEVICE',
        headers: _.get(req, [ 'headers', 'user-agent' ])
      })

      const getReduxPromise = function () {
        let { query, params } = renderProps
        let comp = renderProps.components[renderProps.components.length - 1].WrappedComponent
        let promise = comp.fetchData ?
          comp.fetchData({ query, params, store, history }) :
          Promise.resolve()

        return promise
      }

      getReduxPromise().then(()=> {
        let fatalError = store.getState().fatalError
        if (fatalError) {
          throw fatalError
        }
        let assets = webpackIsomorphicTools.assets()
        {/* styles (will be present only in production with webpack extract text plugin) */}
        let styles = ''
        {
          Object.keys(assets.styles).map((style, key) => {
            styles += ReactDOMServer.renderToString(<link async href={assets.styles[style]} key={key} media="screen, projection" rel="stylesheet" type="text/css" charSet="UTF-8"/>)
          }
        )}
        let pageState = store.getState()
        let ogImage = SITE_META.LOGO
        let title = SITE_NAME.FULL
        let canonical = SITE_META.URL
        let desc = SITE_META.DESC
        let ogType = 'website'
        if (pageState['selectedArticle']['id']) {
          let currentArticle = _.get(pageState, [ 'entities', 'articles', _.get(pageState, 'selectedArticle.id') ], null)
          if (currentArticle) {
            canonical = SITE_META.URL + LINK_PREFIX.ARTICLE + _.get(currentArticle, 'slug', '')
            title = _.get(currentArticle, 'title', title)
            desc = _.get(currentArticle, 'ogDescription', desc)
            ogType = 'article'
            if (currentArticle['heroImage']) {
              ogImage = _.get(currentArticle, 'heroImage.image.url', '')
            }
          }
        }

        if ( getCurrentUrl() === reqUrl ) {
          //res.render('index', { html, reduxState, styles, javascript: assets.javascript.main })
          res.write(`
            <!DOCTYPE html>

                  <title>${title}</title>
                  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
                  <meta http-equiv="Cache-control" content="public">
                  <meta name='viewport' content='width=device-width, user-scalable=no, maximum-scale=1, initial-scale=1'/>
                  <meta name="apple-mobile-web-app-capable" content="yes"/>
                  <meta name="keywords" content=${SITE_META.KEYWORDS}/>
                  <meta name="description" content=${desc} data-rdm/>
                  <meta property="og:rich_attachment" content="true"/>
                  <meta property="og:type" content=${ogType}/>
                  <meta property="og:title" content=${title} data-rdm/>
                  <meta property="og:site_name" content=${SITE_NAME.SHORT}/>
                  <meta property="og:image" content=${ogImage} data-rdm/>
                  <meta property="og:image:type" content="image/png" />
                  <meta property="og:image:width" content="960" />
                  <meta property="og:image:height" content="720" />
                  <meta name="twitter:card" content="summary_large_image" />
                  <meta name="twitter:image" content=${ogImage} />
                  <meta name="twitter:title" content=${title} data-rdm/>
                  <meta name="twitter:description" content="" data-rdm/>
                  <meta name="theme-color" content="#E30B20">
                  <link rel="canonical" href=${canonical} data-rdm/>
                  <link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="https://www.twreporter.org/a/rss2.xml" />

                  <link rel="stylesheet" async type="text/css" href="https://www.twreporter.org/asset/reset.css">

                  <link href="/asset/favicon.png"  rel="shortcut icon" />
                  ${styles}

          `)
          let html = ReactDOMServer.renderToString(
            <Provider store={store} >
              { <RouterContext {...renderProps} /> }
            </Provider>
          )
          let reduxState = escape(JSON.stringify(store.getState()))
          res.write(`

${html}

              </script>

          `)
          res.end()
          //DocumentMeta.rewind()   // render custom ducument title
        } else {
          res.redirect(302, getCurrentUrl())
        }
        unsubscribe()
      }).catch((err) => {
        console.log(err.stack)
        if (err instanceof NotFoundError) {
          res.status(404)
          res.render('404')
          return
        }
        res.status(500)
        let errStack = err.stack.split('\n')
        res.render('500', { error: errStack })
      })
    }
  })

  function subscribeUrl() {
    let currentUrl = location.pathname + location.search
    let unsubscribe = history.listen((newLoc) => {
      if (newLoc.action === 'PUSH') {
        currentUrl = newLoc.pathname + newLoc.search
      }
    })
    return [
      ()=> currentUrl,
      unsubscribe
    ]
  }
})

if (config.port) {
  server.listen(config.port, (err) => {
    if (err) {
      console.error(err)
    }
    console.info('----\n==> ✅  %s is running, talking to API server on %s.', config.app.title, config.apiPort)
    console.info('==> 💻  Open http://%s:%s in a browser to view the app.', config.host, config.port)
  })
} else {
  console.error('==>     ERROR: No PORT environment variable has been specified')
}

module.exports = server
<commit_msg>use lodash to get the meta data<commit_after>/*eslint no-console: 0*/
/*global __DEVELOPMENT__ webpackIsomorphicTools */
import 'babel-polyfill'
import Compression from 'compression'
import Express from 'express'
import path from 'path'

import React from 'react'
import ReactDOMServer from 'react-dom/server'
//import ReactDOMStream from 'react-dom-stream/server'
import createLocation from 'history/lib/createLocation'
//import DocumentMeta from 'react-document-meta'
import { RouterContext, match, createMemoryHistory } from 'react-router'
import Promise from 'bluebird'
import httpProxy from 'http-proxy'

import configureStore from '../src/store/configureStore'
import crateRoutes from '../src/routes/index'

import { Provider } from 'react-redux'
import config from './config'

import { NotFoundError } from '../src/lib/custom-error'
import { SITE_NAME, LINK_PREFIX, SITE_META } from '../src/constants/'
import _ from 'lodash'

const server = new Express()
const targetUrl = 'http://' + config.apiHost + ':' + config.apiPort
// create a proxy server to serve the API requests
const proxy = httpProxy.createProxyServer({
  target: targetUrl
})

server.set('views', path.join(__dirname, 'views'))
server.set('view engine', 'ejs')
server.use(Compression())
server.use(Express.static(path.join(__dirname, '../static')))
server.use(function (req, res, next) {
  res.header('Access-Control-Allow-Origin', 'http://www.twreporter.org/')
  res.header('Access-Control-Allow-Headers', 'X-Requested-With')
  next()
})

// mock apis
//server.get('/questions', (req, res)=> {
//  let { questions } = require('./mock_api');
//  res.send(questions);
//});
//
server.get('/robots.txt', (req, res) => {
  res.format({
    'text/plain': function () {
      res.status(200).render('robots')
    }
  })
})
// proxy to the API server
server.use('/api', (req, res) => {
  proxy.web(req, res)
})

// added the error handling to avoid https://github.com/nodejitsu/node-http-proxy/issues/527
proxy.on('error', (error, req, res) => {
  let json
  if (error.code !== 'ECONNRESET') {
    console.error('proxy error', error)
  }
  if (!res.headersSent) {
    res.writeHead(500, { 'content-type': 'application/json' })
  }
  json = { error: 'proxy_error', reason: error.message }
  res.end(JSON.stringify(json))
})

server.get('*', async function (req, res) {
  if (__DEVELOPMENT__) {
    // Do not cache webpack stats: the script file would change since
    // hot module replacement is enabled in the development env
    webpackIsomorphicTools.refresh()
  }
  let history = createMemoryHistory()
  let store = configureStore()

  let routes = crateRoutes(history)

  let location = createLocation(req.url)

  match({ routes, location }, (error, redirectLocation, renderProps) => {
    if (redirectLocation) {
      res.redirect(301, redirectLocation.pathname + redirectLocation.search)
    } else if (error) {
      res.status(500).render('500')
    } else if (renderProps == null) {
      res.status(404).render('404')
    } else {

      let [ getCurrentUrl, unsubscribe ] = subscribeUrl()
      let reqUrl = location.pathname + location.search
      store.dispatch({
        type: 'DETECT_DEVICE',
        headers: _.get(req, [ 'headers', 'user-agent' ])
      })

      const getReduxPromise = function () {
        let { query, params } = renderProps
        let comp = renderProps.components[renderProps.components.length - 1].WrappedComponent
        let promise = comp.fetchData ?
          comp.fetchData({ query, params, store, history }) :
          Promise.resolve()

        return promise
      }

      getReduxPromise().then(()=> {
        let fatalError = store.getState().fatalError
        if (fatalError) {
          throw fatalError
        }
        let assets = webpackIsomorphicTools.assets()
        {/* styles (will be present only in production with webpack extract text plugin) */}
        let styles = ''
        {
          Object.keys(assets.styles).map((style, key) => {
            styles += ReactDOMServer.renderToString(<link async href={assets.styles[style]} key={key} media="screen, projection" rel="stylesheet" type="text/css" charSet="UTF-8"/>)
          }
        )}
        let pageState = store.getState()
        let ogImage = SITE_META.LOGO
        let title = SITE_NAME.FULL
        let canonical = SITE_META.URL
        let desc = SITE_META.DESC
        let ogType = 'website'
        if (pageState['selectedArticle']['id']) {
          let currentArticle = _.get(pageState, [ 'entities', 'articles', _.get(pageState, 'selectedArticle.id') ], null)
          if (currentArticle) {
            canonical = SITE_META.URL + LINK_PREFIX.ARTICLE + _.get(currentArticle, 'slug', '')
            title = _.get(currentArticle, 'title', title)
            desc = _.get(currentArticle, 'ogDescription', desc)
            ogType = 'article'
            if (currentArticle['heroImage']) {
              ogImage = _.get(currentArticle, 'heroImage.image.url', '')
            }
          } else {
            res.status(500).render('500')
          }
        }

        if ( getCurrentUrl() === reqUrl ) {
          //res.render('index', { html, reduxState, styles, javascript: assets.javascript.main })
          res.write(`
            <!DOCTYPE html>

                  <title>${title}</title>
                  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
                  <meta http-equiv="Cache-control" content="public">
                  <meta name='viewport' content='width=device-width, user-scalable=no, maximum-scale=1, initial-scale=1'/>
                  <meta name="apple-mobile-web-app-capable" content="yes"/>
                  <meta name="keywords" content=${SITE_META.KEYWORDS}/>
                  <meta name="description" content=${desc} data-rdm/>
                  <meta property="og:rich_attachment" content="true"/>
                  <meta property="og:type" content=${ogType}/>
                  <meta property="og:title" content=${title} data-rdm/>
                  <meta property="og:site_name" content=${SITE_NAME.SHORT}/>
                  <meta property="og:image" content=${ogImage} data-rdm/>
                  <meta property="og:image:type" content="image/png" />
                  <meta property="og:image:width" content="960" />
                  <meta property="og:image:height" content="720" />
                  <meta name="twitter:card" content="summary_large_image" />
                  <meta name="twitter:image" content=${ogImage} />
                  <meta name="twitter:title" content=${title} data-rdm/>
                  <meta name="twitter:description" content="" data-rdm/>
                  <meta name="theme-color" content="#E30B20">
                  <link rel="canonical" href=${canonical} data-rdm/>
                  <link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="https://www.twreporter.org/a/rss2.xml" />

                  <link rel="stylesheet" async type="text/css" href="https://www.twreporter.org/asset/reset.css">

                  <link href="/asset/favicon.png"  rel="shortcut icon" />
                  ${styles}

          `)
          let html = ReactDOMServer.renderToString(
            <Provider store={store} >
              { <RouterContext {...renderProps} /> }
            </Provider>
          )
          let reduxState = escape(JSON.stringify(store.getState()))
          res.write(`

${html}

              </script>

          `)
          res.end()
          //DocumentMeta.rewind()   // render custom ducument title
        } else {
          res.redirect(302, getCurrentUrl())
        }
        unsubscribe()
      }).catch((err) => {
        console.log(err.stack)
        if (err instanceof NotFoundError) {
          res.status(404)
          res.render('404')
          return
        }
        res.status(500)
        let errStack = err.stack.split('\n')
        res.render('500', { error: errStack })
      })
    }
  })

  function subscribeUrl() {
    let currentUrl = location.pathname + location.search
    let unsubscribe = history.listen((newLoc) => {
      if (newLoc.action === 'PUSH') {
        currentUrl = newLoc.pathname + newLoc.search
      }
    })
    return [
      ()=> currentUrl,
      unsubscribe
    ]
  }
})

if (config.port) {
  server.listen(config.port, (err) => {
    if (err) {
      console.error(err)
    }
    console.info('----\n==> ✅  %s is running, talking to API server on %s.', config.app.title, config.apiPort)
    console.info('==> 💻  Open http://%s:%s in a browser to view the app.', config.host, config.port)
  })
} else {
  console.error('==>     ERROR: No PORT environment variable has been specified')
}

module.exports = server
<|endoftext|>


<commit_before>var MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
	entry: ["./js/app.js", "./css/main.scss"],
	output: {
		path: __dirname + "/build",
		filename: "app.js",
		publicPath: "/build",
	},
	module: {
    rules: [
      {
        test: /\.(png|gif|ttf|eot|svg|woff|woff2)(\?[a-z0-9]+)?$/,
        use: [
          {
            loader: 'file-loader',
          },
        ],
      },
      {
        test: /\.(png|gif|ttf|eot|svg|woff|woff2)(\?[a-z0-9=]+)?$/,
        use: [
          {
            loader: 'file-loader',
          },
        ],
      },
      {
        test: /\.scss$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
	},
	plugins: [
      new MiniCssExtractPlugin()
	],
};
<commit_msg>Retab file<commit_after>var MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  entry: ["./js/app.js", "./css/main.scss"],
  output: {
    path: __dirname + "/build",
    filename: "app.js",
    publicPath: "/build",
  },
  module: {
    rules: [
      {
        test: /\.(png|gif|ttf|eot|svg|woff|woff2)(\?[a-z0-9]+)?$/,
        use: [
          {
            loader: 'file-loader',
          },
        ],
      },
      {
        test: /\.(png|gif|ttf|eot|svg|woff|woff2)(\?[a-z0-9=]+)?$/,
        use: [
          {
            loader: 'file-loader',
          },
        ],
      },
      {
        test: /\.scss$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin()
  ],
};
<|endoftext|>


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

var U = require("../tools/node");
var path = require("path");
var fs = require("fs");
var assert = require("assert");
var sys = require("util");

var tests_dir = path.dirname(module.filename);
var failures = 0;
var failed_files = {};

run_compress_tests();
if (failures) {
    sys.error("\n!!! Failed " + failures + " test cases.");
    sys.error("!!! " + Object.keys(failed_files).join(", "));
    process.exit(1);
}

var run_ast_conversion_tests = require("./mozilla-ast");

run_ast_conversion_tests({
    iterations: 1000
});

/* -----[ utils ]----- */

function tmpl() {
    return U.string_template.apply(this, arguments);
}

function log() {
    var txt = tmpl.apply(this, arguments);
    sys.puts(txt);
}

function log_directory(dir) {
    log("*** Entering [{dir}]", { dir: dir });
}

function log_start_file(file) {
    log("--- {file}", { file: file });
}

function log_test(name) {
    log("    Running test [{name}]", { name: name });
}

function find_test_files(dir) {
    var files = fs.readdirSync(dir).filter(function(name){
        return /\.js$/i.test(name);
    });
    if (process.argv.length > 2) {
        var x = process.argv.slice(2);
        files = files.filter(function(f){
            return x.indexOf(f) >= 0;
        });
    }
    return files;
}

function test_directory(dir) {
    return path.resolve(tests_dir, dir);
}

function as_toplevel(input) {
    if (input instanceof U.AST_BlockStatement) input = input.body;
    else if (input instanceof U.AST_Statement) input = [ input ];
    else throw new Error("Unsupported input syntax");
    var toplevel = new U.AST_Toplevel({ body: input });
    toplevel.figure_out_scope();
    return toplevel;
}

function run_compress_tests() {
    var dir = test_directory("compress");
    log_directory("compress");
    var files = find_test_files(dir);
    function test_file(file) {
        log_start_file(file);
        function test_case(test) {
            log_test(test.name);
            var options = U.defaults(test.options, {
                warnings: false
            });
            var cmp = new U.Compressor(options, true);
            var expect;
            if (test.expect) {
                expect = make_code(as_toplevel(test.expect), false);
            } else {
                expect = test.expect_exact;
            }
            var input = as_toplevel(test.input);
            var input_code = make_code(test.input);
            var output = input.transform(cmp);
            output.figure_out_scope();
            output = make_code(output, false);
            if (expect != output) {
                log("!!! failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n---EXPECTED---\n{expected}\n\n", {
                    input: input_code,
                    output: output,
                    expected: expect
                });
                failures++;
                failed_files[file] = 1;
            }
        }
        var tests = parse_test(path.resolve(dir, file));
        for (var i in tests) if (tests.hasOwnProperty(i)) {
            test_case(tests[i]);
        }
    }
    files.forEach(function(file){
        test_file(file);
    });
}

function parse_test(file) {
    var script = fs.readFileSync(file, "utf8");
    var ast = U.parse(script, {
        filename: file
    });
    var tests = {};
    var tw = new U.TreeWalker(function(node, descend){
        if (node instanceof U.AST_LabeledStatement
            && tw.parent() instanceof U.AST_Toplevel) {
            var name = node.label.name;
            tests[name] = get_one_test(name, node.body);
            return true;
        }
        if (!(node instanceof U.AST_Toplevel)) croak(node);
    });
    ast.walk(tw);
    return tests;

    function croak(node) {
        throw new Error(tmpl("Can't understand test file {file} [{line},{col}]\n{code}", {
            file: file,
            line: node.start.line,
            col: node.start.col,
            code: make_code(node, false)
        }));
    }

    function get_one_test(name, block) {
        var test = { name: name, options: {} };
        var tw = new U.TreeWalker(function(node, descend){
            if (node instanceof U.AST_Assign) {
                if (!(node.left instanceof U.AST_SymbolRef)) {
                    croak(node);
                }
                var name = node.left.name;
                test[name] = evaluate(node.right);
                return true;
            }
            if (node instanceof U.AST_LabeledStatement) {
                assert.ok(
                    node.label.name == "input" || node.label.name == "expect" || node.label.name == "expect_exact",
                    tmpl("Unsupported label {name} [{line},{col}]", {
                        name: node.label.name,
                        line: node.label.start.line,
                        col: node.label.start.col
                    })
                );
                var stat = node.body;
                if (stat instanceof U.AST_BlockStatement) {
                    if (stat.body.length == 1) stat = stat.body[0];
                    else if (stat.body.length == 0) stat = new U.AST_EmptyStatement();
                }
                if (node.label.name === "expect_exact") {
                    if (!(stat.TYPE === "SimpleStatement" && stat.body.TYPE === "String")) {
                        throw new Error(
                            "The value of the expect_exact clause should be a string, " +
                            "like `expect_exact: \"some.exact.javascript;\"`");
                    }
                    test[node.label.name] = stat.body.start.value
                } else {
                    test[node.label.name] = stat;
                }
                return true;
            }
        });
        block.walk(tw);
        return test;
    };
}

function make_code(ast, beautify) {
    if (arguments.length == 1) beautify = true;
    var stream = U.OutputStream({ beautify: beautify });
    ast.print(stream);
    return stream.get();
}

function evaluate(code) {
    if (code instanceof U.AST_Node)
        code = make_code(code);
    return new Function("return(" + code + ")")();
}
<commit_msg>Replace util.puts in run-tests with console.log<commit_after>#! /usr/bin/env node

var U = require("../tools/node");
var path = require("path");
var fs = require("fs");
var assert = require("assert");
var sys = require("util");

var tests_dir = path.dirname(module.filename);
var failures = 0;
var failed_files = {};

run_compress_tests();
if (failures) {
    sys.error("\n!!! Failed " + failures + " test cases.");
    sys.error("!!! " + Object.keys(failed_files).join(", "));
    process.exit(1);
}

var run_ast_conversion_tests = require("./mozilla-ast");

run_ast_conversion_tests({
    iterations: 1000
});

/* -----[ utils ]----- */

function tmpl() {
    return U.string_template.apply(this, arguments);
}

function log() {
    var txt = tmpl.apply(this, arguments);
    console.log("%s", txt);
}

function log_directory(dir) {
    log("*** Entering [{dir}]", { dir: dir });
}

function log_start_file(file) {
    log("--- {file}", { file: file });
}

function log_test(name) {
    log("    Running test [{name}]", { name: name });
}

function find_test_files(dir) {
    var files = fs.readdirSync(dir).filter(function(name){
        return /\.js$/i.test(name);
    });
    if (process.argv.length > 2) {
        var x = process.argv.slice(2);
        files = files.filter(function(f){
            return x.indexOf(f) >= 0;
        });
    }
    return files;
}

function test_directory(dir) {
    return path.resolve(tests_dir, dir);
}

function as_toplevel(input) {
    if (input instanceof U.AST_BlockStatement) input = input.body;
    else if (input instanceof U.AST_Statement) input = [ input ];
    else throw new Error("Unsupported input syntax");
    var toplevel = new U.AST_Toplevel({ body: input });
    toplevel.figure_out_scope();
    return toplevel;
}

function run_compress_tests() {
    var dir = test_directory("compress");
    log_directory("compress");
    var files = find_test_files(dir);
    function test_file(file) {
        log_start_file(file);
        function test_case(test) {
            log_test(test.name);
            var options = U.defaults(test.options, {
                warnings: false
            });
            var cmp = new U.Compressor(options, true);
            var expect;
            if (test.expect) {
                expect = make_code(as_toplevel(test.expect), false);
            } else {
                expect = test.expect_exact;
            }
            var input = as_toplevel(test.input);
            var input_code = make_code(test.input);
            var output = input.transform(cmp);
            output.figure_out_scope();
            output = make_code(output, false);
            if (expect != output) {
                log("!!! failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n---EXPECTED---\n{expected}\n\n", {
                    input: input_code,
                    output: output,
                    expected: expect
                });
                failures++;
                failed_files[file] = 1;
            }
        }
        var tests = parse_test(path.resolve(dir, file));
        for (var i in tests) if (tests.hasOwnProperty(i)) {
            test_case(tests[i]);
        }
    }
    files.forEach(function(file){
        test_file(file);
    });
}

function parse_test(file) {
    var script = fs.readFileSync(file, "utf8");
    var ast = U.parse(script, {
        filename: file
    });
    var tests = {};
    var tw = new U.TreeWalker(function(node, descend){
        if (node instanceof U.AST_LabeledStatement
            && tw.parent() instanceof U.AST_Toplevel) {
            var name = node.label.name;
            tests[name] = get_one_test(name, node.body);
            return true;
        }
        if (!(node instanceof U.AST_Toplevel)) croak(node);
    });
    ast.walk(tw);
    return tests;

    function croak(node) {
        throw new Error(tmpl("Can't understand test file {file} [{line},{col}]\n{code}", {
            file: file,
            line: node.start.line,
            col: node.start.col,
            code: make_code(node, false)
        }));
    }

    function get_one_test(name, block) {
        var test = { name: name, options: {} };
        var tw = new U.TreeWalker(function(node, descend){
            if (node instanceof U.AST_Assign) {
                if (!(node.left instanceof U.AST_SymbolRef)) {
                    croak(node);
                }
                var name = node.left.name;
                test[name] = evaluate(node.right);
                return true;
            }
            if (node instanceof U.AST_LabeledStatement) {
                assert.ok(
                    node.label.name == "input" || node.label.name == "expect" || node.label.name == "expect_exact",
                    tmpl("Unsupported label {name} [{line},{col}]", {
                        name: node.label.name,
                        line: node.label.start.line,
                        col: node.label.start.col
                    })
                );
                var stat = node.body;
                if (stat instanceof U.AST_BlockStatement) {
                    if (stat.body.length == 1) stat = stat.body[0];
                    else if (stat.body.length == 0) stat = new U.AST_EmptyStatement();
                }
                if (node.label.name === "expect_exact") {
                    if (!(stat.TYPE === "SimpleStatement" && stat.body.TYPE === "String")) {
                        throw new Error(
                            "The value of the expect_exact clause should be a string, " +
                            "like `expect_exact: \"some.exact.javascript;\"`");
                    }
                    test[node.label.name] = stat.body.start.value
                } else {
                    test[node.label.name] = stat;
                }
                return true;
            }
        });
        block.walk(tw);
        return test;
    };
}

function make_code(ast, beautify) {
    if (arguments.length == 1) beautify = true;
    var stream = U.OutputStream({ beautify: beautify });
    ast.print(stream);
    return stream.get();
}

function evaluate(code) {
    if (code instanceof U.AST_Node)
        code = make_code(code);
    return new Function("return(" + code + ")")();
}
<|endoftext|>


<commit_before>// (C) Copyright 2014-2015 Hewlett-Packard Development Company, L.P.

var compression = require('compression');
var express = require('express');
var http = require("http");
var router = express.Router();
var morgan = require('morgan');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var path = require('path');
var httpProxy = require('http-proxy');

var proxy = httpProxy.createProxyServer({
  target: 'ws://localhost:8010',
  ws: true
});

var request = require('request');

var docs = require('./docs');
var ctoAppTuner = require('./cto-app-tuner');
var todoAppModular = require('./todo-app-modular');
var cabler = require('./cabler');

var PORT = 8000;

var app = express();

app.use(compression());

app.use(cookieParser());

if (!process.env.SILENT_MODE) {
  app.use(morgan('tiny'));
}

router.get('/', function (req, res) {
  res.redirect('/docs');
});

app.use('/', function(req, res, next) {
  var acceptLanguageHeader = req.headers['accept-language'];

  if (acceptLanguageHeader) {
    var acceptedLanguages = acceptLanguageHeader.match(/[a-zA-z\-]{2,10}/g);
    if (acceptedLanguages) {
      res.cookie('languages', JSON.stringify(acceptedLanguages));
    }
  }

  next();
});

app.use('/tour/', function (req, res) {
  res.redirect('/medium-app');
});

// Redirect referneces to the original HPE sticker sheet
// to the new master HPE sticker sheet.
app.get('/assets/design/grommet_sticker_sheet.ai', function (req, res) {
  res.redirect(301, '/assets/design/hpe/grommet-hpe-master.ai');
});

var mediumAppPath = '/medium-app';

app.use(mediumAppPath, function(req, res) {
  if (req.originalUrl === mediumAppPath) {
    res.redirect(301, req.originalUrl + '/');
  } else {
    proxy.web(req, res, { target: 'http://localhost:8010/medium-app' });
  }
});

app.use('/people-finder', function(req, res) {
  proxy.web(req, res, { target: 'http://localhost:8020/' });
});

app.use('/ldap', function(req, res) {
  proxy.web(req, res, { target: 'http://localhost:8020/ldap' });
});

app.use('/rest', function(req, res) {
  proxy.web(req, res, { target: 'http://localhost:8010/rest' });
});

app.use('/slackin', function(req, res) {
  proxy.web(req, res, { target: 'http://localhost:3000/' });
});

app.use('/socket.io', function(req, res) {
  proxy.web(req, res, { target: 'http://localhost:3000/socket.io' });
});

app.use('/invite', bodyParser.json(), function(req, res) {
  var data = req.body;
  if (!data.channels) {
    data.channels = ['general'];
  }
  request.post({uri: 'http://localhost:3000/invite', json: data}).pipe(res);
});

app.get('/assets/design/:name', function(req, res) {
  var options = {
    root: path.join(__dirname, '/../docs/dist/assets/design'),
    dotfiles: 'deny',
    headers: {
        'x-timestamp': Date.now(),
        'x-sent': true
    }
  };

  // Express uses the mime.lookup() method in the node-mime
  // https://github.com/broofa/node-mime project to determine
  // a file's mime type.  This method returns the mime type
  // of 'application/postscript' for Adobe Illustrator files
  // and this results in Safari attempting to show a preview of
  // the file in the browser.  So we'll check for Illustrator
  // files and handle them as a special case for now.
  if (/\.ai$/.test(req.params.name) ) {
    res.type('application/illustrator');
  } else {
    res.type(req.params.name);
  }

  res.sendFile(req.params.name, options);
});

app.
  use('/docs', docs).
  use('/cto-app-tuner', ctoAppTuner).
  use('/todo-app-modular', todoAppModular).
  use('/cabler', cabler).
  use('/hello-world', express.static(path.join(__dirname, '/../examples/hello-world'))).
  use('/assets', express.static(path.join(__dirname, '/../docs/dist/assets'))).
  use('/assets', express.static('/usr/local/lib/node_modules/slackin/lib/assets')).
  use('', router);

var server = http.createServer(app);

server.on('upgrade', function (req, socket, head) {
  proxy.ws(req, socket, head);
});

server.listen(PORT);

console.log('Server started, listening at: http://localhost:' + PORT + '...');
<commit_msg>Check for req ip and redirect to the most likely theme<commit_after>// (C) Copyright 2014-2015 Hewlett-Packard Development Company, L.P.

var compression = require('compression');
var express = require('express');
var http = require("http");
var router = express.Router();
var morgan = require('morgan');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var path = require('path');
var httpProxy = require('http-proxy');

var proxy = httpProxy.createProxyServer({
  target: 'ws://localhost:8010',
  ws: true
});

var request = require('request');

var docs = require('./docs');
var ctoAppTuner = require('./cto-app-tuner');
var todoAppModular = require('./todo-app-modular');
var cabler = require('./cabler');

var PORT = 8000;

var app = express();

app.use(compression());

app.use(cookieParser());

if (!process.env.SILENT_MODE) {
  app.use(morgan('tiny'));
}

router.get('/', function (req, res) {
  console.log("'" + req.ip + "'");
  if ( req.ip.match(/^16\./) ) {
    res.redirect('/docs/hpe');
  }
  else if ( req.ip.match(/^15\./) ) {
    res.redirect('/docs/hpinc');
  }
  else {
    res.redirect('/docs');
  }
});

app.use('/', function(req, res, next) {
  var acceptLanguageHeader = req.headers['accept-language'];

  if (acceptLanguageHeader) {
    var acceptedLanguages = acceptLanguageHeader.match(/[a-zA-z\-]{2,10}/g);
    if (acceptedLanguages) {
      res.cookie('languages', JSON.stringify(acceptedLanguages));
    }
  }

  next();
});

app.use('/tour/', function (req, res) {
  res.redirect('/medium-app');
});

// Redirect referneces to the original HPE sticker sheet
// to the new master HPE sticker sheet.
app.get('/assets/design/grommet_sticker_sheet.ai', function (req, res) {
  res.redirect(301, '/assets/design/hpe/grommet-hpe-master.ai');
});

var mediumAppPath = '/medium-app';

app.use(mediumAppPath, function(req, res) {
  if (req.originalUrl === mediumAppPath) {
    res.redirect(301, req.originalUrl + '/');
  } else {
    proxy.web(req, res, { target: 'http://localhost:8010/medium-app' });
  }
});

app.use('/people-finder', function(req, res) {
  proxy.web(req, res, { target: 'http://localhost:8020/' });
});

app.use('/ldap', function(req, res) {
  proxy.web(req, res, { target: 'http://localhost:8020/ldap' });
});

app.use('/rest', function(req, res) {
  proxy.web(req, res, { target: 'http://localhost:8010/rest' });
});

app.use('/slackin', function(req, res) {
  proxy.web(req, res, { target: 'http://localhost:3000/' });
});

app.use('/socket.io', function(req, res) {
  proxy.web(req, res, { target: 'http://localhost:3000/socket.io' });
});

app.use('/invite', bodyParser.json(), function(req, res) {
  var data = req.body;
  if (!data.channels) {
    data.channels = ['general'];
  }
  request.post({uri: 'http://localhost:3000/invite', json: data}).pipe(res);
});

app.get('/assets/design/:name', function(req, res) {
  var options = {
    root: path.join(__dirname, '/../docs/dist/assets/design'),
    dotfiles: 'deny',
    headers: {
        'x-timestamp': Date.now(),
        'x-sent': true
    }
  };

  // Express uses the mime.lookup() method in the node-mime
  // https://github.com/broofa/node-mime project to determine
  // a file's mime type.  This method returns the mime type
  // of 'application/postscript' for Adobe Illustrator files
  // and this results in Safari attempting to show a preview of
  // the file in the browser.  So we'll check for Illustrator
  // files and handle them as a special case for now.
  if (/\.ai$/.test(req.params.name) ) {
    res.type('application/illustrator');
  } else {
    res.type(req.params.name);
  }

  res.sendFile(req.params.name, options);
});

app.
  use('/docs', docs).
  use('/cto-app-tuner', ctoAppTuner).
  use('/todo-app-modular', todoAppModular).
  use('/cabler', cabler).
  use('/hello-world', express.static(path.join(__dirname, '/../examples/hello-world'))).
  use('/assets', express.static(path.join(__dirname, '/../docs/dist/assets'))).
  use('/assets', express.static('/usr/local/lib/node_modules/slackin/lib/assets')).
  use('', router);

var server = http.createServer(app);

server.on('upgrade', function (req, socket, head) {
  proxy.ws(req, socket, head);
});

server.listen(PORT);

console.log('Server started, listening at: http://localhost:' + PORT + '...');
<|endoftext|>


<commit_before>const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

const plugins = [new ExtractTextPlugin('styles.css')];

if (process.env.NODE_ENV === 'production') {
  plugins.push(new webpack.optimize.ModuleConcatenationPlugin());

  plugins.push(
    new HtmlWebpackPlugin({
      hash: true,
      minify: {
        html5: true,
        collapseWhitespace: true,
        removeComments: true,
      },
      template: './index.html',
    })
  );

  plugins.push(new OptimizeCSSAssetsPlugin({
    cssProcessor: require('cssnano'),
    cssProcessorOptions: {
      discardComments: {
        removeAll: true
      }
    },
    canPrint:	true
  }));

  plugins.push(new webpack.optimize.UglifyJsPlugin());
} else {
  plugins.push(
    new HtmlWebpackPlugin({
      hash: true,
      template: './index.html',
    })
  );
}

module.exports = {
  devtool: 'source-map',
  entry: {
    app: './src/js/main.js',
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: [/node_module/],
        use: [{
          loader: 'babel-loader',
        }],
      },
      {
        test: /\.styl$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: ['css-loader', 'postcss-loader', 'stylus-loader'],
        }),
      },
    ],
  },
  plugins,
};
<commit_msg>add sourcemaps<commit_after>const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

const plugins = [new ExtractTextPlugin('styles.css')];

if (process.env.NODE_ENV === 'production') {
  plugins.push(new webpack.optimize.ModuleConcatenationPlugin());

  plugins.push(
    new HtmlWebpackPlugin({
      hash: true,
      minify: {
        html5: true,
        collapseWhitespace: true,
        removeComments: true,
      },
      template: './index.html',
    })
  );

  plugins.push(new OptimizeCSSAssetsPlugin({
    cssProcessor: require('cssnano'),
    cssProcessorOptions: {
      discardComments: {
        removeAll: true
      }
    },
    canPrint:	true
  }));

  plugins.push(new webpack.optimize.UglifyJsPlugin());
} else {
  plugins.push(
    new HtmlWebpackPlugin({
      hash: true,
      template: './index.html',
    })
  );
}

module.exports = {
  devtool: 'source-map',
  entry: {
    app: './src/js/main.js',
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: [/node_module/],
        use: [{
          loader: 'babel-loader',
        }],
      },
      {
        test: /\.styl$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: [
            { loader: 'css-loader', options: { sourceMap: true } },
            { loader: 'postcss-loader', options: { sourceMap: true } },
            { loader: 'stylus-loader', options: { sourceMap: true } },
          ],
        }),
      },
    ],
  },
  plugins,
};
<|endoftext|>