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

function matchArrayQuery(key) {
  return key.match(/(\w+)\[((\w+:[<\w>]+?)?(,\w+:[<\w>]+)*)\]/);
}

function matchObjectQuery(key) {
  return key.match(/(\w+)\(((\w+:[<\w>]+?)?(,\w+:[<\w>]+)*)\)/);
}

function isQuery(key) {
  return key.match(/\w+(\(.*\)|\[.*\])/);
}

function getShape(queryDef) {
  if (_.isArray(queryDef) || _.isEmpty(queryDef)) {
    return queryDef;
  }

  var shape = {};
  _.each(queryDef, function (value, key) {
    if (isQuery(key)) { // TODO: And is not a mutation. We should not allow a query to fill it's children if they are mutations.
      var parsedQueryKey = parseQueryKey(key);
      if (_.isArray(parsedQueryKey.returnType)) {
        shape[parsedQueryKey.name] = [getShape(value)];
      } else {
        shape[parsedQueryKey.name] = getShape(value);
      }
    } else if (_.isPlainObject(value)) {
      shape[key] = getShape(value);
    } else {
      shape[key] = value;
    }
  });
  return shape;
}

function parseQueryKey(queryKey) {
  if (!isQuery(queryKey)) {
    return {};
  }

  var parsed = {
    name: queryKey,
    queryParams: {},
    returnType: {}
  };

  var match;
  if (match = matchObjectQuery(queryKey)) {
    parsed.returnType = {}
  } else if (match = matchArrayQuery(queryKey)) {
    parsed.returnType = []
  }
  parsed.name = match[1];
  if (!_.isEmpty(match[2])) {
    _.each(match[2].split(','), function (arg) {
      var pair = arg.split(':');
      parsed.queryParams[pair[0]] = pair[1];
    });
  }
  return parsed;
}

function findQueries(nestedQueryDef, pathSoFar) {
  //traverse the nested query definition looking for executable queries.
  if (_.isEmpty(pathSoFar)) {
    pathSoFar = [];
  }

  var queries = [];
  if (_.isArray(nestedQueryDef)) {
    // Should we allow this?
  } else {
    queries = _.flatten(_.map(nestedQueryDef, function (queryDef, key) {
      var queryDef = nestedQueryDef[key];
      var path = _.cloneDeep(pathSoFar);
      var qs = [];
      if (isQuery(key)) {
        var parsed = parseQueryKey(key);
        path.push(key);
        qs = [{
          name: parsed.name,
          queryKey: key,
          queryParams: parsed.queryParams,
          path: path,
          shape: getShape(queryDef)
        }];
      } else {
        path.push(key);
        if (!_.isEmpty(queryDef)) {
          qs = [{
            name: key,
            path: path,
            shape: getShape(queryDef)
          }];
        }
      }
      return qs.concat(findQueries(queryDef, path));
    }));
  }
  return queries;
}

var _handlers = {
  'root': function (query, input) {
    return Promise.resolve({});
  },
  'posts': function (query, input) {
    //console.log('posts received input', input);
    return Promise.resolve([{id: 1, text: 'iamtext'}, {id: 2, text: 'ibetext'}]);
  },
  'user': function (query, input) {
    //console.log('user received input', input);
    return Promise.resolve(query.shape);
  },
  'cogs': function (query, input) {
    //console.log('cogs received input', input);
    return Promise.resolve({name: 'iamcog'});
  },
  'x': function (query, input) {
    //console.log('x received input', input);
    return Promise.resolve(query.shape);
  },
  'hmm': function (query, input) {
    //console.log('x received input', input);
    return Promise.resolve(123);
  }
};

function getHandler(name) {
  return _handlers[name] ? _handlers[name] : function (query, input) {
    return new Promise(function (resolve, reject) {
      if (query.queryKey) {
        //console.log('rejecting', query.queryKey);
        reject(new Error('Query requires handler, but no handler found named ' + name));
      } else {
        //console.log('resolving query shape', query.shape);
        //console.log('resolving', query, query.queryKey);
        resolve(query.shape);
      }
    });
  }
}

function runQueries(queries) {
  var sortedQueries = _.sortBy(queries, 'path');

  var tree = {};
  var queries = {}

  _.each(sortedQueries, function (q) {
    var parent = q.path.length <= 1 ? 'root' : _.take(q.path, q.path.length - 1).join('.');
    var child = q.path.join('.');
    queries[child] = q;
    tree[parent] = tree[parent] || [];
    tree[parent].push(child);
  });

  function processChildren(query, children, input, output) {
    var newInput = _.cloneDeep(input);
    newInput[query.name] = _.cloneDeep(output);
    return Promise.all(_.map(children, function (child) {
      return runTask(child, newInput).then(function (childOutput) {
        return {
          input: newInput,
          query: queries[child],
          output: childOutput
        }
      });
    })).then(function (summaries) {
      return _.reduce(summaries, function (acc, summary) {
        acc[summary.query.name] = summary.output;
        return acc;
      }, output)
    });
  }

  function runTask(key, input) {
    var query = key === 'root' ? {name: 'root', shape: {}} : queries[key];

    //console.log('key', key);
    //console.log('query.name', query.name);
    //console.log('query.path', query.path);
    //console.log('query.queryKey', query.queryKey);

    var children = tree[key];
    var handler = getHandler(query.name);
    return handler(query, input).then(function (output) {
      if (_.isArray(output)) {
        //console.log('runTask, output array, now running children');
        return Promise.all(_.map(output, function (out) {
          if (!_.isPlainObject(out)) {
            return out;
          }
          return processChildren(query, children, input, out);
        }));
      } else if (_.isPlainObject(output)) {
        return processChildren(query, children, input, output);
      } else {
        return output;
      }
    });
  }

  return runTask('root', {});
}

function matchShape(shape, output) {
  var outputShape = _.cloneDeep(shape);

  if (_.isPlainObject(output)) {
    if (outputShape === null) {
      outputShape = output;
    } else {
      if (!outputShape) {
        throw new Error('cannot match output '
          + JSON.stringify(output) + ' to output shape '
          + JSON.stringify(outputShape));
      }
      _.each(output, function (value, key) {
        outputShape[key] = matchShape(shape[key], value);
      });
      outputShape = _.pick(outputShape, _.keys(shape));
      _.each(outputShape, function (value, key) {
        if (value === null) {
          throw new Error('Query output does not contain expected key ' + key);
        }
      });
    }
  } else if (_.isArray(output)) {
    if (!_.isArray(shape)) {
      throw new Error('Output from handler was array, which does not match expected shape ' + JSON.stringify(shape));
    }
    if (shape.length === 1 && _.isPlainObject(shape[0])) {
      var s = shape[0];
      outputShape = _.map(output, function (o) {
        return matchShape(s, o);
      });
    } else {
      outputShape = output;
    }
  } else {
    outputShape = output;
  }
  return outputShape;
}

module.exports = function (handlers) {
  _handlers = handlers;
  return {
    _getShape: getShape,
    _findQueries: findQueries,

    run: function (query) {
      return runQueries(findQueries(query)).then(function (output) {
        var shape = getShape(query);
        return matchShape(shape, output);
      });
    }
  }
};

<commit_msg>remove default handlers<commit_after>var _ = require('lodash');

function matchArrayQuery(key) {
  return key.match(/(\w+)\[((\w+:[<\w>]+?)?(,\w+:[<\w>]+)*)\]/);
}

function matchObjectQuery(key) {
  return key.match(/(\w+)\(((\w+:[<\w>]+?)?(,\w+:[<\w>]+)*)\)/);
}

function isQuery(key) {
  return key.match(/\w+(\(.*\)|\[.*\])/);
}

function getShape(queryDef) {
  if (_.isArray(queryDef) || _.isEmpty(queryDef)) {
    return queryDef;
  }

  var shape = {};
  _.each(queryDef, function (value, key) {
    if (isQuery(key)) { // TODO: And is not a mutation. We should not allow a query to fill it's children if they are mutations.
      var parsedQueryKey = parseQueryKey(key);
      if (_.isArray(parsedQueryKey.returnType)) {
        shape[parsedQueryKey.name] = [getShape(value)];
      } else {
        shape[parsedQueryKey.name] = getShape(value);
      }
    } else if (_.isPlainObject(value)) {
      shape[key] = getShape(value);
    } else {
      shape[key] = value;
    }
  });
  return shape;
}

function parseQueryKey(queryKey) {
  if (!isQuery(queryKey)) {
    return {};
  }

  var parsed = {
    name: queryKey,
    queryParams: {},
    returnType: {}
  };

  var match;
  if (match = matchObjectQuery(queryKey)) {
    parsed.returnType = {}
  } else if (match = matchArrayQuery(queryKey)) {
    parsed.returnType = []
  }
  parsed.name = match[1];
  if (!_.isEmpty(match[2])) {
    _.each(match[2].split(','), function (arg) {
      var pair = arg.split(':');
      parsed.queryParams[pair[0]] = pair[1];
    });
  }
  return parsed;
}

function findQueries(nestedQueryDef, pathSoFar) {
  //traverse the nested query definition looking for executable queries.
  if (_.isEmpty(pathSoFar)) {
    pathSoFar = [];
  }

  var queries = [];
  if (_.isArray(nestedQueryDef)) {
    // Should we allow this?
  } else {
    queries = _.flatten(_.map(nestedQueryDef, function (queryDef, key) {
      var queryDef = nestedQueryDef[key];
      var path = _.cloneDeep(pathSoFar);
      var qs = [];
      if (isQuery(key)) {
        var parsed = parseQueryKey(key);
        path.push(key);
        qs = [{
          name: parsed.name,
          queryKey: key,
          queryParams: parsed.queryParams,
          path: path,
          shape: getShape(queryDef)
        }];
      } else {
        path.push(key);
        if (!_.isEmpty(queryDef)) {
          qs = [{
            name: key,
            path: path,
            shape: getShape(queryDef)
          }];
        }
      }
      return qs.concat(findQueries(queryDef, path));
    }));
  }
  return queries;
}

var _handlers = {};

function getHandler(name) {
  return _handlers[name] ? _handlers[name] : function (query, input) {
    return new Promise(function (resolve, reject) {
      if (query.queryKey) {
        //console.log('rejecting', query.queryKey);
        reject(new Error('Query requires handler, but no handler found named ' + name));
      } else {
        //console.log('resolving query shape', query.shape);
        //console.log('resolving', query, query.queryKey);
        resolve(query.shape);
      }
    });
  }
}

function runQueries(queries) {
  var sortedQueries = _.sortBy(queries, 'path');

  var tree = {};
  var queries = {}

  _.each(sortedQueries, function (q) {
    var parent = q.path.length <= 1 ? 'root' : _.take(q.path, q.path.length - 1).join('.');
    var child = q.path.join('.');
    queries[child] = q;
    tree[parent] = tree[parent] || [];
    tree[parent].push(child);
  });

  function processChildren(query, children, input, output) {
    var newInput = _.cloneDeep(input);
    newInput[query.name] = _.cloneDeep(output);
    return Promise.all(_.map(children, function (child) {
      return runTask(child, newInput).then(function (childOutput) {
        return {
          input: newInput,
          query: queries[child],
          output: childOutput
        }
      });
    })).then(function (summaries) {
      return _.reduce(summaries, function (acc, summary) {
        acc[summary.query.name] = summary.output;
        return acc;
      }, output)
    });
  }

  function runTask(key, input) {
    var query = key === 'root' ? {name: 'root', shape: {}} : queries[key];

    //console.log('key', key);
    //console.log('query.name', query.name);
    //console.log('query.path', query.path);
    //console.log('query.queryKey', query.queryKey);

    var children = tree[key];
    var handler = getHandler(query.name);
    return handler(query, input).then(function (output) {
      if (_.isArray(output)) {
        //console.log('runTask, output array, now running children');
        return Promise.all(_.map(output, function (out) {
          if (!_.isPlainObject(out)) {
            return out;
          }
          return processChildren(query, children, input, out);
        }));
      } else if (_.isPlainObject(output)) {
        return processChildren(query, children, input, output);
      } else {
        return output;
      }
    });
  }

  return runTask('root', {});
}

function matchShape(shape, output) {
  var outputShape = _.cloneDeep(shape);

  if (_.isPlainObject(output)) {
    if (outputShape === null) {
      outputShape = output;
    } else {
      if (!outputShape) {
        throw new Error('cannot match output '
          + JSON.stringify(output) + ' to output shape '
          + JSON.stringify(outputShape));
      }
      _.each(output, function (value, key) {
        outputShape[key] = matchShape(shape[key], value);
      });
      outputShape = _.pick(outputShape, _.keys(shape));
      _.each(outputShape, function (value, key) {
        if (value === null) {
          throw new Error('Query output does not contain expected key ' + key);
        }
      });
    }
  } else if (_.isArray(output)) {
    if (!_.isArray(shape)) {
      throw new Error('Output from handler was array, which does not match expected shape ' + JSON.stringify(shape));
    }
    if (shape.length === 1 && _.isPlainObject(shape[0])) {
      var s = shape[0];
      outputShape = _.map(output, function (o) {
        return matchShape(s, o);
      });
    } else {
      outputShape = output;
    }
  } else {
    outputShape = output;
  }
  return outputShape;
}

module.exports = function (handlers) {
  _handlers = handlers;
  return {
    _getShape: getShape,
    _findQueries: findQueries,

    run: function (query) {
      return runQueries(findQueries(query)).then(function (output) {
        var shape = getShape(query);
        return matchShape(shape, output);
      });
    }
  }
};

<|endoftext|>


<commit_before>// This is included with the Parsley library itself,
// thus there is no use in adding it to your project.
import Parsley from '../parsley/main';

Parsley.addMessages('hu', {
  defaultMessage: "Érvénytelen mező.",
  type: {
    email:        "Érvénytelen email cím.",
    url:          "Érvénytelen URL cím.",
    number:       "Érvénytelen szám.",
    integer:      "Érvénytelen egész szám.",
    digits:       "Érvénytelen szám.",
    alphanum:     "Érvénytelen alfanumerikus érték."
  },
  notblank:       "Ez a mező nem maradhat üresen.",
  required:       "A mező kitöltése kötelező.",
  pattern:        "Érvénytelen érték.",
  min:            "A mező értéke nagyobb vagy egyenlő kell legyen mint %s.",
  max:            "A mező értéke kisebb vagy egyenlő kell legyen mint %s.",
  range:          "A mező értéke %s és %s közé kell essen.",
  minlength:      "Legalább %s karakter megadása szükséges.",
  maxlength:      "Legfeljebb %s karakter megadása engedélyezett.",
  length:         "Nem megfelelő karakterszám. Minimum %s, maximum %s karakter adható meg.",
  mincheck:       "Legalább %s értéket kell kiválasztani.",
  maxcheck:       "Maximum %s értéket lehet kiválasztani.",
  check:          "Legalább %s, legfeljebb %s értéket kell kiválasztani.",
  equalto:        "A mező értéke nem egyező."
});

Parsley.setLocale('hu');
<commit_msg>Whitespace<commit_after>// This is included with the Parsley library itself,
// thus there is no use in adding it to your project.
import Parsley from '../parsley/main';

Parsley.addMessages('hu', {
  defaultMessage: "Érvénytelen mező.",
  type: {
    email:        "Érvénytelen email cím.",
    url:          "Érvénytelen URL cím.",
    number:       "Érvénytelen szám.",
    integer:      "Érvénytelen egész szám.",
    digits:       "Érvénytelen szám.",
    alphanum:     "Érvénytelen alfanumerikus érték."
  },
  notblank:       "Ez a mező nem maradhat üresen.",
  required:       "A mező kitöltése kötelező.",
  pattern:        "Érvénytelen érték.",
  min:            "A mező értéke nagyobb vagy egyenlő kell legyen mint %s.",
  max:            "A mező értéke kisebb vagy egyenlő kell legyen mint %s.",
  range:          "A mező értéke %s és %s közé kell essen.",
  minlength:      "Legalább %s karakter megadása szükséges.",
  maxlength:      "Legfeljebb %s karakter megadása engedélyezett.",
  length:         "Nem megfelelő karakterszám. Minimum %s, maximum %s karakter adható meg.",
  mincheck:       "Legalább %s értéket kell kiválasztani.",
  maxcheck:       "Maximum %s értéket lehet kiválasztani.",
  check:          "Legalább %s, legfeljebb %s értéket kell kiválasztani.",
  equalto:        "A mező értéke nem egyező."
});

Parsley.setLocale('hu');
<|endoftext|>


<commit_before>/**
 * --------------------------------------------------------------------------
 * Inflect (v1.0.2): inflect.js
 * Cleanup, modify, and save messy HTML
 * by Evan Yamanishi
 * Licensed under GPL-3.0
 * --------------------------------------------------------------------------
 */

'use strict'

// CONSTANTS

const NAME = 'inflect'
const VERSION = '1.0.2'

const Default = {
    includeInDesignTasks: true,
    removeWhitespace: true,
    vocab: 'epub'
}

// tasks for common InDesign HTML export issues
// these are run first if included via the includeInDesignTasks option
const InDesignTasks = [{
    'action': 'removeElement',
    'selector': '[id^=_id],[class^=_id]'
},
{
    'action': 'removeAttribute',
    'selector': '[lang]:not(html)',
    'attribute': 'lang'
}]

const ItemKeys = {
    selector: 'selector',
    tagReplacement: 'tag',
    attributeRemoval: 'attribute'
}

const VocabAttrName = {
    dpub: 'role',
    epub: 'epub:type'
}

// CLASS DEFINITION

class Inflect {

    // accepts a document, array of items (items.json), and optional config
    constructor(doc, items, config) {
        this.doc = doc
        this.config = this._getConfig(config)

        if (items) {
            this.items = this._getItems(items)

            for (let item of this.items) {
                this.inflectItem(item)
            }
        }
    }

    // PUBLIC

    // delete an element, but leave the non-empty children
    removeElement(el) {
        while (el.firstChild) {
            el.parentNode.insertBefore(el.firstChild, el)
        }
        el.parentNode.removeChild(el)
    }

    // delete an attribute from an element
    removeAttr(el, item) {
        if (item[ItemKeys.attributeRemoval] === 'all') {
            for (let attr of el.attributes) {
                el.removeAttribute(attr.name)
            }
        } else if (typeof item[ItemKeys.attributeRemoval] === 'object') {
            for (let attr of item[ItemKeys.attributeRemoval]) {
                el.removeAttribute(attr)
            }
        } else {
            el.removeAttribute(item[ItemKeys.attributeRemoval])
        }
    }

    // fix element based on data in item object
    fixElement(el, item) {
        let currentTag = el.tagName.toLowerCase()
        let newTag = (item[ItemKeys.tagReplacement]) ? item[ItemKeys.tagReplacement].toLowerCase() : null

        // change tag by regexp replacing the opening and closing strings
        if (newTag && currentTag !== newTag) {
            let openTag = new RegExp(`<${currentTag} `, 'g')
            let closeTag = new RegExp(`/${currentTag}>`, 'g')
            el.outerHTML = el.outerHTML.replace(openTag, `<${newTag} `).replace(closeTag, `/${newTag}>`)
        }
        this.setAttributes(el, item)
    }

    // set attributes on the element based on data in item object
    setAttributes(el, item) {
        if (item[this.config.vocab]) {
            el.setAttribute(VocabAttrName[this.config.vocab], item[this.config.vocab])
        }
    }

    // the starting-point function for semantic inflection
    inflectItem(item) {
        let elements = this.doc.querySelectorAll(item[ItemKeys.selector])

        for (let el of elements) {
            if (this.config.removeWhitespace) this._removePrecedingWhitespace(el)

            switch (item.action) {
                case 'removeElement':
                    this.removeElement(el)
                    break;
                case 'removeAttribute':
                    this.removeAttr(el, item)
                    break;
                default:
                    this.fixElement(el, item)
            }
        }
    }

    // PRIVATE

    // overwrite default options with supplied options
    _getConfig(config) {
        return Object.assign({}, Default, config)
    }

    // add items to the end of default tasks
    _getItems(items) {
        return (this.config.includeInDesignTasks) ? InDesignTasks.concat(items) : items
    }

    // returns true if the node is an empty text string
    _nodeIsEmpty(node) {
        // node exists, is a text node, and is empty after trim
        return node && node.nodeType === 3 && node.nodeValue.trim().length === 0
    }

    // remove the previous node if it's empty
    _removePrecedingWhitespace(el) {
        let prev = el.previousSibling
        if (this._nodeIsEmpty(prev)) prev.remove()
    }

    // copy all non-empty children from one element (el) to another (newEl)
    _getChildren(el, newEl) {
        for (let child of el.childNodes) {
            if (!this._nodeIsEmpty(child)) newEl.appendChild(child)
        }
        return newEl
    }
}

export default Inflect
<commit_msg>sometimes there isn't a space in opening tag<commit_after>/**
 * --------------------------------------------------------------------------
 * Inflect (v1.0.2): inflect.js
 * Cleanup, modify, and save messy HTML
 * by Evan Yamanishi
 * Licensed under GPL-3.0
 * --------------------------------------------------------------------------
 */

'use strict'

// CONSTANTS

const NAME = 'inflect'
const VERSION = '1.0.2'

const Default = {
    includeInDesignTasks: true,
    removeWhitespace: true,
    vocab: 'epub'
}

// tasks for common InDesign HTML export issues
// these are run first if included via the includeInDesignTasks option
const InDesignTasks = [{
    'action': 'removeElement',
    'selector': '[id^=_id],[class^=_id]'
},
{
    'action': 'removeAttribute',
    'selector': '[lang]:not(html)',
    'attribute': 'lang'
}]

const ItemKeys = {
    selector: 'selector',
    tagReplacement: 'tag',
    attributeRemoval: 'attribute'
}

const VocabAttrName = {
    dpub: 'role',
    epub: 'epub:type'
}

// CLASS DEFINITION

class Inflect {

    // accepts a document, array of items (items.json), and optional config
    constructor(doc, items, config) {
        this.doc = doc
        this.config = this._getConfig(config)

        if (items) {
            this.items = this._getItems(items)

            for (let item of this.items) {
                this.inflectItem(item)
            }
        }
    }

    // PUBLIC

    // delete an element, but leave the non-empty children
    removeElement(el) {
        while (el.firstChild) {
            el.parentNode.insertBefore(el.firstChild, el)
        }
        el.parentNode.removeChild(el)
    }

    // delete an attribute from an element
    removeAttr(el, item) {
        if (item[ItemKeys.attributeRemoval] === 'all') {
            for (let attr of el.attributes) {
                el.removeAttribute(attr.name)
            }
        } else if (typeof item[ItemKeys.attributeRemoval] === 'object') {
            for (let attr of item[ItemKeys.attributeRemoval]) {
                el.removeAttribute(attr)
            }
        } else {
            el.removeAttribute(item[ItemKeys.attributeRemoval])
        }
    }

    // fix element based on data in item object
    fixElement(el, item) {
        let currentTag = el.tagName.toLowerCase()
        let newTag = (item[ItemKeys.tagReplacement]) ? item[ItemKeys.tagReplacement].toLowerCase() : null

        // change tag by regexp replacing the opening and closing strings
        if (newTag && currentTag !== newTag) {
            let openTag = new RegExp(`<${currentTag}\s*`, 'g')
            let closeTag = new RegExp(`/${currentTag}>`, 'g')
            el.outerHTML = el.outerHTML.replace(openTag, `<${newTag} `).replace(closeTag, `/${newTag}>`)
        }
        this.setAttributes(el, item)
    }

    // set attributes on the element based on data in item object
    setAttributes(el, item) {
        if (item[this.config.vocab]) {
            el.setAttribute(VocabAttrName[this.config.vocab], item[this.config.vocab])
        }
    }

    // the starting-point function for semantic inflection
    inflectItem(item) {
        let elements = this.doc.querySelectorAll(item[ItemKeys.selector])

        for (let el of elements) {
            if (this.config.removeWhitespace) this._removePrecedingWhitespace(el)

            switch (item.action) {
                case 'removeElement':
                    this.removeElement(el)
                    break;
                case 'removeAttribute':
                    this.removeAttr(el, item)
                    break;
                default:
                    this.fixElement(el, item)
            }
        }
    }

    // PRIVATE

    // overwrite default options with supplied options
    _getConfig(config) {
        return Object.assign({}, Default, config)
    }

    // add items to the end of default tasks
    _getItems(items) {
        return (this.config.includeInDesignTasks) ? InDesignTasks.concat(items) : items
    }

    // returns true if the node is an empty text string
    _nodeIsEmpty(node) {
        // node exists, is a text node, and is empty after trim
        return node && node.nodeType === 3 && node.nodeValue.trim().length === 0
    }

    // remove the previous node if it's empty
    _removePrecedingWhitespace(el) {
        let prev = el.previousSibling
        if (this._nodeIsEmpty(prev)) prev.remove()
    }

    // copy all non-empty children from one element (el) to another (newEl)
    _getChildren(el, newEl) {
        for (let child of el.childNodes) {
            if (!this._nodeIsEmpty(child)) newEl.appendChild(child)
        }
        return newEl
    }
}

export default Inflect
<|endoftext|>


<commit_before>import isInteger from 'lodash/isInteger';
import isNil from 'lodash/isNil';

var SUFFIXES = ['million', 'billion', 'trillion', 'quadrillion', 'quintillion', 'sextillion', 'septillion', 'octillion', 'nonillion', 'decillion'];

/**
 * Returns the number of digits found in a number. Accounts for exponents, too.
 *
 * @private
 * @param  {Number} n
 * @return {Number}
 */
function getLengthOfNumber (n) {
  return Math.ceil(Math.log(n + 1) / Math.LN10);
}

/**
 * Converts a large integer into a string representation. Only makes sense for
 * numbers at least 1 million or more.
 *
 * @param  {Number} val
 * @return {String}
 * @example
 *
 * var journalize = require('journalize');
 *
 * journalize.intword(1000000);
 * // returns '1 million'
 *
 * journalize.intword(6500000000000);
 * // returns '6.5 trillion'
 */
export default function intword (val) {
  // if `val` is undefined or null, return an empty string
  if (isNil(val)) return '';

  var convertedVal = +val;

  // if `convertedVal` is not an integer, return `val`
  if (!isInteger(convertedVal)) return val;

  // if `convertedVal` is less than 1 million, no conversion is needed
  if (convertedVal < 1000000) return convertedVal;

  // get the number of digits in the number, and substract remainder to get
  // exponent value
  var numDigits = getLengthOfNumber(convertedVal) - 1;
  var exponent = numDigits - (numDigits % 3);

  // calculate the rounded version of `convertedVal`
  var new_val = convertedVal / Math.pow(10, exponent);
  new_val = Math.round(new_val * 10) / 10;

  return new_val + ' ' + SUFFIXES[Math.floor(exponent / 3) - 2];
}
<commit_msg>Add missing documentation<commit_after>import isInteger from 'lodash/isInteger';
import isNil from 'lodash/isNil';

/**
 * Array of suffixes to be used by intword.
 * @private
 * @type {Array}
 */
var SUFFIXES = ['million', 'billion', 'trillion', 'quadrillion', 'quintillion', 'sextillion', 'septillion', 'octillion', 'nonillion', 'decillion'];

/**
 * Returns the number of digits found in a number. Accounts for exponents, too.
 *
 * @private
 * @param  {Number} n
 * @return {Number}
 */
function getLengthOfNumber (n) {
  return Math.ceil(Math.log(n + 1) / Math.LN10);
}

/**
 * Converts a large integer into a string representation. Only makes sense for
 * numbers at least 1 million or more.
 *
 * @param  {Number} val
 * @return {String}
 * @example
 *
 * var journalize = require('journalize');
 *
 * journalize.intword(1000000);
 * // returns '1 million'
 *
 * journalize.intword(6500000000000);
 * // returns '6.5 trillion'
 */
export default function intword (val) {
  // if `val` is undefined or null, return an empty string
  if (isNil(val)) return '';

  var convertedVal = +val;

  // if `convertedVal` is not an integer, return `val`
  if (!isInteger(convertedVal)) return val;

  // if `convertedVal` is less than 1 million, no conversion is needed
  if (convertedVal < 1000000) return convertedVal;

  // get the number of digits in the number, and substract remainder to get
  // exponent value
  var numDigits = getLengthOfNumber(convertedVal) - 1;
  var exponent = numDigits - (numDigits % 3);

  // calculate the rounded version of `convertedVal`
  var new_val = convertedVal / Math.pow(10, exponent);
  new_val = Math.round(new_val * 10) / 10;

  return new_val + ' ' + SUFFIXES[Math.floor(exponent / 3) - 2];
}
<|endoftext|>


<commit_before>//
// HLF Extensions Core
// ===================
// [Tests](../../tests/js/core.html)
//
(function(root, namespace) {
  //
  // § __UMD__
  // - When AMD, register the attacher as an anonymous module.
  // - When Node or Browserify, set module exports to the attach result.
  // - When browser globals (root is window), Just run the attach function.
  //
  if (typeof define === 'function' && define.amd) {
    define(namespace);
  } else if (typeof exports === 'object') {
    module.exports = namespace();
  } else {
    window.hlf = namespace();
  }
})(this, function() {
  'use strict';
  //
  // Namespace
  // ---------
  // It takes some more boilerplate and helpers to write DOM extensions. That
  // code and set of conventions is here in the root namespace __hlf__. Child
  // namespaces follow suit convention.
  //
  // - The __debug__ flag here toggles debug logging for everything in the library
  //   that doesn't have a custom debug flag in its namespace.
  //
  // - __toString__ is mainly for extension namespacing. For now, its base form
  //   is very simple.
  //
  // - __debugLog__ in its base form just wraps around `console.log` and links to
  //   the `debug` flag. However, `debugLog` conventionally becomes a no-op if
  //   the `debug` flag is off.
  //
  let hlf = {
    debug: true,
    toString() { return 'hlf'; },
  };
  hlf.debugLog = (hlf.debug === false) ? function(){} :
    (console.log.bind ? console.log.bind(console) : console.log);
  //
  // createExtension
  // ---------------
  // Further binding state and functionality to DOM elements is a common task
  // that should be abstracted away, with common patterns and conventions around
  // logging, namespacing, instance access, and sending actions. Also, instead
  // of API classes and instances inheriting from a base layer, that base layer
  // should be integrated on instantiation.
  //
  // __createExtension__ will return an appropriate, multi-purpose function for
  // the given `createOptions`, comprised of:
  //
  // - The __name__ of the method is required.
  //
  // - __namespace__ is required and must correctly implement `debug`,
  //   `toString`, and `defaults`.
  //
  // - An __apiClass__ definition. It will get modified with base API additions.
  //   Also note that `apiClass` will get published into the namespace, so more
  //   flexibility is possible.
  //
  function createExtension(args) {
    const { name, namespace } = args;

    const { apiClass, autoListen, autoSelect } = args;
    let groups = args.baseMethodGroups || [];
    groups.push('action', 'naming');
    if (autoListen) {
      groups.push('event');
    }
    if (autoSelect) {
      groups.push('selection');
    }
    let baseMethods = createExtensionBaseMethods(namespace, groups);
    if (apiClass) {
      namespace.apiClass = apiClass;
      Object.assign(apiClass.prototype, baseMethods);
      if (apiClass.init) {
        apiClass.init();
      }
    }
    const { attrName } = baseMethods;

    const { asSharedInstance, compactOptions } = args;
    let idCounter = 0;
    let instances = {};
    //
    // The __extension__ function handles two variations of input. An action
    // `name` and `payload` can be passed in to trigger the action route. The
    // latter is typically additional, action-specific parameters. Otherwise,
    // if the first argument is an options collection, the normal route is
    // triggered.
    //
    // With the action route, if there is a extension instance and it can
    // __perform__ (`action` mixin), call the method. With the normal route,
    // if there is a extension instance and no arguments are provided we assume
    // the call is to access the instance, not reset it.
    //
    // Otherwise if the instance exists, it is returned. __asSharedInstance__
    // will decide what the extension instance's main element will be. The idea
    // is several elements all share the same extension instance.
    //
    // Otherwise, continue creating the instance by preparing the options and
    // deciding the main element before passing over to `_buildInstance`.
    //
    function extension(subject, ...args) {
      let { action, options, contextElement } = extension._parseArguments(args);
      contextElement = contextElement || document.body;

      if (action) {
        let target = asSharedInstance ? contextElement : subject;
        extension._dispatchAction(action, target);
        return;

      } else if (!options) {
        let source = asSharedInstance ? contextElement : subject;
        let result = extension._getInstanceOrInstances(source);
        if (result) {
          return result;
        }

      } else if (Object.keys(instances).length) {
        instances = {};
      }

      options = Object.assign({}, namespace.defaults, options);
      if (subject instanceof HTMLElement) {
        extension._buildInstance(subject, options, contextElement);
      } else {
        subject.forEach((element) => {
          extension._buildInstance(element, options, contextElement);
        });
      }

      return extension.bind(null, subject);
    }

    Object.assign(extension, {
      baseMethods,
      //
      // ___buildInstance__ is a subroutine that's part of `createExtension`,
      // which has more details on its required input.
      //
      // 1. Check if element has options set in its root data attribute. If
      //    so, merge those options into our own `finalOptions`.
      //
      // 2. Also decide the `rootElement` based on the situation. It's where the
      //    extension instance id gets stored and the root class gets added. A
      //    shared instance, for example, gets stored on the `contextElement`.
      //
      // 3. If we're provided with a class for the API, instantiate it. Decorate
      //    the instance with additional mixins if fitting.
      //
      // 4. If the `compactOptions` flag is toggled, `finalOptions` will be merged
      //    into the instance. This makes accessing options more convenient, but
      //    can cause conflicts with larger existing APIs that don't account for
      //    such naming conflicts, since _we don't handle conflicts here_. Else,
      //    just alias the conventional `selectors` and `classNames` option groups.
      //
      // 5. If the `autoListen` flag is toggled, add and call the `addEventListeners`
      //    method (ie. via `selection` mixin), to set up element event listening
      //    before initialization. The `eventListeners` property must be set.
      //
      // 6. If the `autoSelect` flag is toggled, add and call the `select` method
      //    (ie. via `selection` mixin), to set up element references before
      //    initialization.
      //
      // 7. If the `className` API addition exists and provides the root class,
      //    add the root class to the decided `rootElement` before initialization.
      //
      // 8. If an `init` method is provided, call it. Convention is to always
      //    provide it.
      //
      // 9. Lastly, store the instance id on `rootElement`.
      //
      _buildInstance(element, options, contextElement) {
        let attrOptions;
        if (element.hasAttribute(attrName())) {
          try {
            attrOptions = JSON.parse(element.getAttribute(attrName()));
          } catch (error) {}
        }
        let finalOptions = Object.assign({}, options, attrOptions);
        let rootElement = asSharedInstance ? contextElement : element;
        let instance = new apiClass(element, finalOptions, contextElement);
        instance.element = element;
        if (contextElement) {
          instance.contextElement = contextElement;
        }
        if (compactOptions) {
          Object.assign(instance, finalOptions);
          delete instance.options;
        } else {
          if (finalOptions.selectors) {
            instance.selectors = finalOptions.selectors;
          }
          if (finalOptions.classNames) {
            instance.classNames = finalOptions.classNames;
          }
        }
        if (autoListen && instance.addEventListeners && instance.eventListeners) {
          instance.addEventListeners(instance.eventListeners);
        }
        if (autoSelect && instance.selectToProperties) {
          instance.selectToProperties();
        }
        if (instance.className) {
          rootElement.classList.add(instance.className());
        }
        if (instance.init) {
          instance.init();
        }
        extension._setInstance(rootElement, instance);
        return instance;
      },
      _deleteInstance(element) {
        const id = element.getAttribute(attrName('instance-id'));
        delete instances[id];
      },
      _dispatchAction(action, target) {
        if (target instanceof HTMLElement) {
          extension._getInstance(target).perform(action);
        } else {
          Array.from(target).map(extension._getInstance)
            .forEach((instance) => instance.perform(action));
        }
      },
      _getInstance(element) {
        const id = element.getAttribute(attrName('instance-id'));
        return instances[id];
      },
      _getInstanceOrInstances(source) {
        let instance, instances;
        if (source instanceof HTMLElement &&
          (instance = extension._getInstance(source))
        ) {
          return instance;
        } else if ((instances = Array.from(source).map(extension._getInstance)) &&
          instances.length
        ) {
          return instances;
        }
      },
      _parseArguments(args) {
        let action, options, contextElement;
        const [first, second] = args;
        if (typeof first === 'string') {
          action = { name: first, payload: second };
        } else {
          options = first;
          if (second) {
            contextElement = second;
          }
        }
        return { action, options, contextElement };
      },
      _setInstance(element, instance) {
        const id = idCounter;
        idCounter += 1;
        instance.id = id;
        instances[id] = instance;
        element.setAttribute(attrName('instance-id'), id);
      },
    });

    namespace.extension = extension;

    return extension;
  }
  //
  // __createExtensionBaseMethods__ is an internal subroutine that selectively
  // applies a general mixin collection for writing DOM extensions. It's part of
  // `createExtension`, which has more details on its required input.
  //
  // - Add the __debugLog__ method and attach functionality instead of a no-op
  //   only if namespace `debug` is on.
  //
  // - __action__, allows performing actions by calling action methods.
  //
  // - __naming__, allows namespacing an `attrName`, `className`, or `eventName`.
  //
  // - __event__, sugar around mass-listening to `element` events and
  //   dispatching custom `element` events.
  //
  // - __selection__, sugar around selecting `element` descendants and selecting
  //   to properties based on `selectors`.
  //
  function createExtensionBaseMethods(namespace, groups) {
    let methods = {};
    methods.debugLog = (!namespace.debug ? function(){} :
      hlf.debugLog.bind(null, namespace.toString('log'))
    );
    if (groups.indexOf('action') !== -1) {
      Object.assign(methods, {
        perform(action) {
          const { name, payload } = action;
          let methodName = `perform${name[0].toUpperCase()}${name.substr(1)}`;
          if (!this[methodName]) { return; }
          this[methodName](payload);
        },
        performRemove() {
          namespace.extension._deleteInstance(this.element);
          this.deinit();
        },
      });
    }
    if (groups.indexOf('naming') !== -1) {
      Object.assign(methods, {
        attrName(name = '') {
          if (name.length) {
            name = `-${name}`;
          }
          return `data-${namespace.toString('data')}${name}`;
        },
        className(name = '') {
          if (name.length) {
            name = `-${name}`;
          }
          return `js-${namespace.toString('class')}${name}`;
        },
        eventName(name) {
          return `${namespace.toString('event')}${name}`;
        },
      });
      if (groups.indexOf('css') !== -1) {
        Object.assign(methods, {
          cssVariable(name) {
            return getComputedStyle(this.element)
              .getPropertyValue(`--${namespace.toString('class')}-${name}`);
          }
        });
      }
      if (groups.indexOf('event') !== -1) {
        let normalizeInfos = function(infos) {
          for (const type in infos) {
            if (!infos.hasOwnProperty(type)) { continue; }
            if (typeof infos[type] !== 'function') { continue; }
            infos[type] = [infos[type]];
          }
        };
        Object.assign(methods, {
          addEventListeners(infos, target) {
            target = target || this.element;
            normalizeInfos(infos);
            for (const type in infos) {
              if (!infos.hasOwnProperty(type)) { continue; }
              const [handler, options] = infos[type];
              target.addEventListener(type, handler, options);
            }
          },
          removeEventListeners(infos, target) {
            target = target || this.element;
            normalizeInfos(infos);
            for (const type in infos) {
              if (!infos.hasOwnProperty(type)) { continue; }
              const [handler, options] = infos[type];
              target.removeEventListener(type, handler, options);
            }
          },
          createCustomEvent(type, detail) {
            let initArgs = { detail };
            initArgs.bubbles = true;
            return new CustomEvent(this.eventName(type), initArgs);
          },
          dispatchCustomEvent(type, detail = {}) {
            return this.element.dispatchEvent(this.createCustomEvent(type, detail));
          },
        });
      }
      if (groups.indexOf('selection') !== -1) {
        Object.assign(methods, {
          selectByClass(name) {
            let selector = `.${this.className(name)}`;
            return this.element.querySelector(selector);
          },
          selectAllByClass(name) {
            let selector = `.${this.className(name)}`;
            return this.element.querySelectorAll(selector);
          },
          selectToProperties() {
            if (!this.element || !this.selectors) {
              throw 'Missing requirements.';
            }
            for (const name in this.selectors) {
              if (!this.selectors.hasOwnProperty(name)) { continue; }
              const selector = this.selectors[name];
              if (name.substr(-1) === 's') {
                this[name] = this.element.querySelectorAll(selector);
              } else {
                this[name] = this.element.querySelector(selector);
              }
            }
          },
        });
      }
    }
    return methods;
  }

  Object.assign(hlf, { createExtension });

  return hlf;

});
<commit_msg>ES6 rewrite: minor core refactor.<commit_after>//
// HLF Extensions Core
// ===================
// [Tests](../../tests/js/core.html)
//
(function(root, namespace) {
  //
  // § __UMD__
  // - When AMD, register the attacher as an anonymous module.
  // - When Node or Browserify, set module exports to the attach result.
  // - When browser globals (root is window), Just run the attach function.
  //
  if (typeof define === 'function' && define.amd) {
    define(namespace);
  } else if (typeof exports === 'object') {
    module.exports = namespace();
  } else {
    window.hlf = namespace();
  }
})(this, function() {
  'use strict';
  //
  // Namespace
  // ---------
  // It takes some more boilerplate and helpers to write DOM extensions. That
  // code and set of conventions is here in the root namespace __hlf__. Child
  // namespaces follow suit convention.
  //
  // - The __debug__ flag here toggles debug logging for everything in the library
  //   that doesn't have a custom debug flag in its namespace.
  //
  // - __toString__ is mainly for extension namespacing. For now, its base form
  //   is very simple.
  //
  // - __debugLog__ in its base form just wraps around `console.log` and links to
  //   the `debug` flag. However, `debugLog` conventionally becomes a no-op if
  //   the `debug` flag is off.
  //
  let hlf = {
    debug: true,
    toString() { return 'hlf'; },
  };
  hlf.debugLog = (hlf.debug === false) ? function(){} :
    (console.log.bind ? console.log.bind(console) : console.log);
  //
  // createExtension
  // ---------------
  // Further binding state and functionality to DOM elements is a common task
  // that should be abstracted away, with common patterns and conventions around
  // logging, namespacing, instance access, and sending actions. Also, instead
  // of API classes and instances inheriting from a base layer, that base layer
  // should be integrated on instantiation.
  //
  // __createExtension__ will return an appropriate, multi-purpose function for
  // the given `createOptions`, comprised of:
  //
  // - The __name__ of the method is required.
  //
  // - __namespace__ is required and must correctly implement `debug`,
  //   `toString`, and `defaults`.
  //
  // - An __apiClass__ definition. It will get modified with base API additions.
  //   Also note that `apiClass` will get published into the namespace, so more
  //   flexibility is possible.
  //
  function createExtension(args) {
    const { name, namespace } = args;

    const { apiClass, autoListen, autoSelect } = args;
    let groups = args.baseMethodGroups || [];
    groups.push('action', 'naming');
    if (autoListen) {
      groups.push('event');
    }
    if (autoSelect) {
      groups.push('selection');
    }
    let baseMethods = createExtensionBaseMethods(namespace, groups);
    if (apiClass) {
      namespace.apiClass = apiClass;
      Object.assign(apiClass.prototype, baseMethods);
      if (apiClass.init) {
        apiClass.init();
      }
    }
    const { attrName } = baseMethods;

    const { asSharedInstance, compactOptions } = args;
    let idCounter = 0;
    let instances = {};
    //
    // The __extension__ function handles two variations of input. An action
    // `name` and `payload` can be passed in to trigger the action route. The
    // latter is typically additional, action-specific parameters. Otherwise,
    // if the first argument is an options collection, the normal route is
    // triggered.
    //
    // With the action route, if there is a extension instance and it can
    // __perform__ (`action` mixin), call the method. With the normal route,
    // if there is a extension instance and no arguments are provided we assume
    // the call is to access the instance, not reset it.
    //
    // Otherwise if the instance exists, it is returned. __asSharedInstance__
    // will decide what the extension instance's main element will be. The idea
    // is several elements all share the same extension instance.
    //
    // Otherwise, continue creating the instance by preparing the options and
    // deciding the main element before passing over to `_buildInstance`.
    //
    function extension(subject, ...args) {
      let { action, options, contextElement } = extension._parseArguments(args);
      contextElement = contextElement || document.body;

      if (action) {
        let target = asSharedInstance ? contextElement : subject;
        extension._dispatchAction(action, target);
        return;

      } else if (!options) {
        let source = asSharedInstance ? contextElement : subject;
        let result = extension._getInstanceOrInstances(source);
        if (result) {
          return result;
        }

      } else if (Object.keys(instances).length) {
        instances = {};
      }

      options = Object.assign({}, namespace.defaults, options);
      if (subject instanceof HTMLElement) {
        extension._buildInstance(subject, options, contextElement);
      } else {
        subject.forEach((element) => {
          extension._buildInstance(element, options, contextElement);
        });
      }

      return extension.bind(null, subject);
    }

    Object.assign(extension, {
      baseMethods,
      //
      // ___buildInstance__ is a subroutine that's part of `createExtension`,
      // which has more details on its required input.
      //
      // 1. Check if element has options set in its root data attribute. If
      //    so, merge those options into our own `finalOptions`.
      //
      // 2. Also decide the `rootElement` based on the situation. It's where the
      //    extension instance id gets stored and the root class gets added. A
      //    shared instance, for example, gets stored on the `contextElement`.
      //
      // 3. If we're provided with a class for the API, instantiate it. Decorate
      //    the instance with additional mixins if fitting.
      //
      // 4. If the `compactOptions` flag is toggled, `finalOptions` will be merged
      //    into the instance. This makes accessing options more convenient, but
      //    can cause conflicts with larger existing APIs that don't account for
      //    such naming conflicts, since _we don't handle conflicts here_. Else,
      //    just alias the conventional `selectors` and `classNames` option groups.
      //
      // 5. If the `autoListen` flag is toggled, add and call the `addEventListeners`
      //    method (ie. via `selection` mixin), to set up element event listening
      //    before initialization. The `eventListeners` property must be set.
      //
      // 6. If the `autoSelect` flag is toggled, add and call the `select` method
      //    (ie. via `selection` mixin), to set up element references before
      //    initialization.
      //
      // 7. If the `className` API addition exists and provides the root class,
      //    add the root class to the decided `rootElement` before initialization.
      //
      // 8. If an `init` method is provided, call it. Convention is to always
      //    provide it.
      //
      // 9. Lastly, store the instance id on `rootElement`.
      //
      _buildInstance(element, options, contextElement) {
        let attrOptions;
        if (element.hasAttribute(attrName())) {
          try {
            attrOptions = JSON.parse(element.getAttribute(attrName()));
          } catch (error) {}
        }
        let finalOptions = Object.assign({}, options, attrOptions);
        let rootElement = asSharedInstance ? contextElement : element;
        let instance = new apiClass(element, finalOptions, contextElement);
        instance.element = element;
        if (contextElement) {
          instance.contextElement = contextElement;
        }
        if (compactOptions) {
          Object.assign(instance, finalOptions);
          delete instance.options;
        } else {
          if (finalOptions.selectors) {
            instance.selectors = finalOptions.selectors;
          }
          if (finalOptions.classNames) {
            instance.classNames = finalOptions.classNames;
          }
        }
        if (autoListen && instance.addEventListeners && instance.eventListeners) {
          instance.addEventListeners(instance.eventListeners);
        }
        if (autoSelect && instance.selectToProperties) {
          instance.selectToProperties();
        }
        if (instance.className) {
          rootElement.classList.add(instance.className());
        }
        if (instance.init) {
          instance.init();
        }
        extension._setInstance(rootElement, instance);
        return instance;
      },
      _deleteInstance(element) {
        const id = element.getAttribute(attrName('instance-id'));
        delete instances[id];
      },
      _dispatchAction(action, target) {
        if (target instanceof HTMLElement) {
          extension._getInstance(target).perform(action);
        } else {
          Array.from(target).map(extension._getInstance)
            .forEach((instance) => instance.perform(action));
        }
      },
      _getInstance(element) {
        const id = element.getAttribute(attrName('instance-id'));
        return instances[id];
      },
      _getInstanceOrInstances(source) {
        let instance, instances;
        if (source instanceof HTMLElement &&
          (instance = extension._getInstance(source))
        ) {
          return instance;
        } else if ((instances = Array.from(source).map(extension._getInstance)) &&
          instances.length
        ) {
          return instances;
        }
      },
      _parseArguments(args) {
        let action, options, contextElement;
        const [first, second] = args;
        if (typeof first === 'string') {
          action = { name: first, payload: second };
        } else {
          options = first;
          if (second) {
            contextElement = second;
          }
        }
        return { action, options, contextElement };
      },
      _setInstance(element, instance) {
        const id = idCounter;
        idCounter += 1;
        instance.id = id;
        instances[id] = instance;
        element.setAttribute(attrName('instance-id'), id);
      },
    });

    namespace.extension = extension;

    return extension;
  }
  //
  // __createExtensionBaseMethods__ is an internal subroutine that selectively
  // applies a general mixin collection for writing DOM extensions. It's part of
  // `createExtension`, which has more details on its required input.
  //
  // - Add the __debugLog__ method and attach functionality instead of a no-op
  //   only if namespace `debug` is on.
  //
  // - __action__, allows performing actions by calling action methods.
  //
  // - __naming__, allows namespacing an `attrName`, `className`, or `eventName`.
  //
  // - __event__, sugar around mass-listening to `element` events and
  //   dispatching custom `element` events.
  //
  // - __selection__, sugar around selecting `element` descendants and selecting
  //   to properties based on `selectors`.
  //
  function createExtensionBaseMethods(namespace, groups) {
    let methods = {};
    methods.debugLog = (!namespace.debug ? function(){} :
      hlf.debugLog.bind(null, namespace.toString('log'))
    );
    if (groups.indexOf('action') !== -1) {
      Object.assign(methods, {
        perform(action) {
          const { name, payload } = action;
          let methodName = `perform${name[0].toUpperCase()}${name.substr(1)}`;
          if (!this[methodName]) { return; }
          this[methodName](payload);
        },
        performRemove() {
          namespace.extension._deleteInstance(this.element);
          this.deinit();
        },
      });
    }
    if (groups.indexOf('naming') !== -1) {
      Object.assign(methods, {
        attrName(name = '') {
          if (name.length) {
            name = `-${name}`;
          }
          return `data-${namespace.toString('data')}${name}`;
        },
        className(name = '') {
          if (name.length) {
            name = `-${name}`;
          }
          return `js-${namespace.toString('class')}${name}`;
        },
        eventName(name) {
          return `${namespace.toString('event')}${name}`;
        },
      });
      if (groups.indexOf('css') !== -1) {
        Object.assign(methods, {
          cssVariable(name) {
            return getComputedStyle(this.element)
              .getPropertyValue(`--${namespace.toString('class')}-${name}`);
          }
        });
      }
      if (groups.indexOf('event') !== -1) {
        let normalizeInfos = function(infos) {
          for (const type in infos) {
            if (!infos.hasOwnProperty(type)) { continue; }
            if (typeof infos[type] !== 'function') { continue; }
            infos[type] = [infos[type]];
          }
        };
        Object.assign(methods, {
          addEventListeners(infos, target) {
            target = target || this.element;
            normalizeInfos(infos);
            for (const type in infos) {
              if (!infos.hasOwnProperty(type)) { continue; }
              const [handler, options] = infos[type];
              target.addEventListener(type, handler, options);
            }
          },
          removeEventListeners(infos, target) {
            target = target || this.element;
            normalizeInfos(infos);
            for (const type in infos) {
              if (!infos.hasOwnProperty(type)) { continue; }
              const [handler, options] = infos[type];
              target.removeEventListener(type, handler, options);
            }
          },
          createCustomEvent(type, detail) {
            let initArgs = { detail };
            initArgs.bubbles = true;
            return new CustomEvent(this.eventName(type), initArgs);
          },
          dispatchCustomEvent(type, detail = {}) {
            return this.element.dispatchEvent(this.createCustomEvent(type, detail));
          },
        });
      }
      if (groups.indexOf('selection') !== -1) {
        Object.assign(methods, {
          selectByClass(name) {
            return this.element.querySelector(`.${this.className(name)}`);
          },
          selectAllByClass(name) {
            return this.element.querySelectorAll(`.${this.className(name)}`);
          },
          selectToProperties() {
            if (!this.element || !this.selectors) {
              throw 'Missing requirements.';
            }
            for (const name in this.selectors) {
              if (!this.selectors.hasOwnProperty(name)) { continue; }
              const selector = this.selectors[name];
              if (name.substr(-1) === 's') {
                this[name] = this.element.querySelectorAll(selector);
              } else {
                this[name] = this.element.querySelector(selector);
              }
            }
          },
        });
      }
    }
    return methods;
  }

  Object.assign(hlf, { createExtension });

  return hlf;

});
<|endoftext|>


<commit_before>$(function () {
    var $container = $('#container'),
        content,
        i;

    $(window).on('resize orientationchange', function () {
        if ($container.data('scrollbox') !== undefined) {
            $container.scrollbox('update');
        }
    });

    content = '
';

    for (i = 1; i <= 500; ++ i) {
        content += '
Line ' + i + '
';
    }

    content += '
';

    $container.append(content);

    $container.scrollbox();
});<commit_msg>Removed trash<commit_after><|endoftext|>


<commit_before>function _get(q) {
	if (q[0] === '*') return document.querySelectorAll(q.substr(1));
	else return document.querySelector(q);
}

Object.defineProperties(Number.prototype, {
	'between': {
		value: function(a, b) {
			if (this > a && this < b) return true;
			return false;
		}
	},

	'outside': {
		value: function(a, b) {
			if (this < a || this > b) return true;
			return false;
		}
	}
});

function Game() {
	var CANVAS		= _get('#game-canvas'),
		gameW		= _get('#container').getBoundingClientRect().width,
		gameH		= _get('#container').getBoundingClientRect().height,
		bricks		= new Array,
		pi			= Math.PI,
		colors = {
			red			: ['hsl(0, 100%, 15%)',			'hsl(0, 100%, 30%)',		'hsl(0, 100%, 50%)'		],
			yellow		: [/*'hsl(51, 100%, 15%)',*/	'hsl(51, 100%, 30%)',		'hsl(51, 100%, 50%)'	],
			green		: [/*'hsl(120, 100%, 10%)',		'hsl(120, 100%, 15%)',*/	'hsl(120, 100%, 25%)'	],
			dark_red	: ['hsl(0, 100%, 10%)',			'hsl(0, 100%, 20%)',		'hsl(0, 100%, 35%)'		],
			dark_yellow : [/*'hsl(47, 100%, 10%)',*/	'hsl(47, 100%, 20%)',		'hsl(47, 100%, 35%)'	],
			dark_green	: [/*'hsl(120, 100%, 5%)',		'hsl(120, 100%, 10%)',*/	'hsl(120, 100%, 15%)'	],
		},
		animationID, pad, c;

	function fastLine(x1, y1, x2, y2, color, width) {
		c.beginPath();
		c.strokeStyle = color;
		c.lineWidth = width;
		c.moveTo(x1, y1);
		c.lineTo(x2, y2);
		c.closePath();
		c.stroke();
	}

	function Brick(x, y, w, h, color, health) {
		var borderW = w/15,
			x2 = x+w,
			y2 = y+h;

		this.dead = false;
		this.newTeta = 0;

		this.draw = function() {
			c.fillStyle = colors[color][health-1];
			c.lineWidth = borderW;
			c.strokeStyle = colors['dark_' + color][health-1];

			c.fillRect(x, y, w, h);
			c.strokeRect(x+borderW/2, y+borderW/2, w-borderW, h-borderW);
		}

		this.collision = function(ballX, ballY, ballR, ballTeta) {
			// returns true if the brick gets hit by the ball
			var distX = Math.abs(ballX - x - w/2),
				distY = Math.abs(ballY - y - h/2),
				dX = distX - w/2,
				dY = distY - h/2,
				collided = false;

			if (distX > w/2+ballR || distY > h/2+ballR) return collided;
			else if (distX <= w/2 || distY <= h/2 /*|| dX*dX + dY*dY <= ballR*ballR*/) collided = true;

			if (collided) {

				/* vertexes
				if (dX*dX + dY*dY <= ballR*ballR)
					this.newTeta = ballTeta;
				*/

				// vertical borders
				if (ballX.between(x-ballR, x2+ballR) && ballY.between(y, y2))
					this.newTeta = ballTeta <= pi ? pi - ballTeta : 3*pi - ballTeta;
				// horizontal borders
				else if (ballY.between(y-ballR, y2+ballR) && ballX.between(x, x2))
					this.newTeta =  2*pi - ballTeta;
			}

			if (collided && --health === 0) this.dead = true;
			return collided;
		}
	}

	function Pad() {
		var r = 7/100*gameW,
			h = 1/100*gameH,
			x = gameW/2,
			y = gameH-h,
			hitbox = false; // hitbox prevents the ball from hitting the pad more than once

		function draw() {
			c.fillStyle = 'white';
			c.fillRect(x-r, y, 2*r, h);

			// DEBUG
			fastLine(x, y, x, 0, 'white', 2);
		}

		this.direction = false;
		this.speed = 15;
		this.newTeta = 0;

		this.collision = function(ballX, ballY, ballR, ballTeta) {
			var dX = ballX - x;

			if (!(Math.abs(dX) <= r || ballY+ballR >= y)) hitbox = false;

			if (!hitbox && Math.abs(dX) <= r && ballY+ballR >= y) {
				hitbox = true;
				this.newTeta = 2*pi - ballTeta;

				// deviation of the ball
				if (dX > r/5) this.newTeta -= (this.newTeta-pi/36)*dX/r;
				else if (dX < r/5) this.newTeta -= (pi-this.newTeta-pi/36)*dX/r

				return true;
			}
			return false;
		}

		this.update = function() {
			if (this.direction === 'left') {
				x -= this.speed;

				if (x-r < 0) {
					this.direction = false;
					x = r;
				}
			}

			if (this.direction === 'right') {
				x += this.speed;

				if (x+r > gameW) {
					this.direction = false;
					x = gameW-r;
				}
			}

			draw();
		}

		draw();
	}

	function Ball() {
		var r = 1.5/100*gameW,
			x = gameW/2,
			y = gameH - gameH/100*5,
			teta = Math.random()*4*pi/6 + pi/6,
			speed = 10;

		function draw() {
			c.fillStyle = 'lightgrey';
			c.beginPath();
			c.arc(x, y, r, 0, pi*2);
			c.closePath();
			c.fill();

			// DEBUG
			fastLine(x, 0, x, gameH, 'lightgrey', 2);
			fastLine(0, y, gameW, y, 'lightgrey', 2);
			c.fillText('ballTeta = ' + teta/pi*180, 50, gameH - 200);
			fastLine(x, y, x + 1000*Math.cos(-teta), y + 1000*Math.sin(-teta), 'pink', 2);
		}

		this.update = function() {
			// Walls
			if (x+r >= gameW || x-r <= 0) teta = teta <= pi ? pi - teta : 3*pi - teta;	// right-left
			if (y-r <= 0) teta = 2*pi - teta;											// top
			if (pad.collision(x, y, r, teta)) teta = pad.newTeta;						// pad

			// Bricks
			for (var i=0, b; b = bricks[i]; i++) if (b.collision(x, y, r, teta)) {
				teta = b.newTeta;
				if (b.dead) bricks.splice(i--, 1);
			}

			x += speed*Math.cos(teta);
			y -= speed*Math.sin(teta);

			draw();
		}

		draw();
	}

	function spawnBricks(rows, columns, height) {
		var width = gameW/columns,
			height = height/100*gameH,
			color = 'red',
			health = 3,
			b;

		for (var i=0; i < rows; i++) {
			for (var j=0; j < columns; j++) {
				if (i > 1) { color = 'yellow'; health = 2; }
				if (i > 4) { color = 'green'; health = 1; }
				b = new Brick(j*width, i*height, width, height, color, health);
				b.draw();
				bricks.push(b);
			}
		}
	}

	function update() {
		c.clearRect(0, 0, gameW, gameH);

		for (var i=0, b; b = bricks[i]; i++) b.draw();
		pad.update();
		ball.update();

		animationID = requestAnimationFrame(update);
	}

	this.start = function() {
		CANVAS.width = CANVAS.height = gameW > gameH ? gameW = gameH : gameH = gameW;
		c = CANVAS.getContext('2d');

		spawnBricks(10, 10, 5);
		pad = new Pad();
		ball = new Ball();

		document.addEventListener('keydown', function(e) {
			if (e.keyCode === 37) pad.direction = 'left';
			if (e.keyCode === 39) pad.direction = 'right';
		});

		document.addEventListener('keyup', function(e) {
			if ((e.keyCode === 37 && pad.direction === 'left') || (e.keyCode === 39 && pad.direction === 'right')) pad.direction = false;
		});

		animationID = requestAnimationFrame(update);
	}
}

var game = new Game();
game.start();<commit_msg>Fixing ball bounce and pad deviation<commit_after>function _get(q) {
	if (q[0] === '*') return document.querySelectorAll(q.substr(1));
	else return document.querySelector(q);
}

Object.defineProperties(Number.prototype, {
	'between': {
		value: function(a, b) {
			if (this >= a && this <= b) return true;
			return false;
		}
	},

	'outside': {
		value: function(a, b) {
			if (this <= a || this >= b) return true;
			return false;
		}
	}
});

function Game() {
	var CANVAS		= _get('#game-canvas'),
		gameW		= _get('#container').getBoundingClientRect().width,
		gameH		= _get('#container').getBoundingClientRect().height,
		bricks		= new Array,
		pi			= Math.PI,
		colors = {
			red			: ['hsl(0, 100%, 15%)',			'hsl(0, 100%, 30%)',		'hsl(0, 100%, 50%)'		],
			yellow		: [/*'hsl(51, 100%, 15%)',*/	'hsl(51, 100%, 30%)',		'hsl(51, 100%, 50%)'	],
			green		: [/*'hsl(120, 100%, 10%)',		'hsl(120, 100%, 15%)',*/	'hsl(120, 100%, 25%)'	],
			dark_red	: ['hsl(0, 100%, 10%)',			'hsl(0, 100%, 20%)',		'hsl(0, 100%, 35%)'		],
			dark_yellow : [/*'hsl(47, 100%, 10%)',*/	'hsl(47, 100%, 20%)',		'hsl(47, 100%, 35%)'	],
			dark_green	: [/*'hsl(120, 100%, 5%)',		'hsl(120, 100%, 10%)',*/	'hsl(120, 100%, 15%)'	],
		},
		animationID, pad, c;

	function fastLine(x1, y1, x2, y2, color, width) {
		c.beginPath();
		c.strokeStyle = color;
		c.lineWidth = width;
		c.moveTo(x1, y1);
		c.lineTo(x2, y2);
		c.closePath();
		c.stroke();
	}

	function Brick(x, y, w, h, color, health) {
		var borderW = w/15,
			x2 = x+w,
			y2 = y+h;

		this.dead = false;
		this.newTeta = 0;

		this.draw = function() {
			c.fillStyle = colors[color][health-1];
			c.lineWidth = borderW;
			c.strokeStyle = colors['dark_' + color][health-1];

			c.fillRect(x, y, w, h);
			c.strokeRect(x+borderW/2, y+borderW/2, w-borderW, h-borderW);
		}

		this.collision = function(ballX, ballY, ballR, ballTeta) {
			// returns true if the brick gets hit by the ball
			var distX = Math.abs(ballX - x - w/2),
				distY = Math.abs(ballY - y - h/2),
				dX2 = Math.pow(distX - w/2, 2),
				dY2 = Math.pow(distY - h/2, 2);

			if (distX <= w/2+ballR && distY <= h/2+ballR) {
				void(0);

				if (ballX.between(x-ballR, x2+ballR) && ballY.between(y, y2))		// vertical borders
					this.newTeta = ballTeta <= pi ? pi - ballTeta : 3*pi - ballTeta;
				else if (ballY.between(y-ballR, y2+ballR) && ballX.between(x, x2))	// horizontal borders
					this.newTeta =  2*pi - ballTeta;
				else if (dX2 + dY2 <= ballR*ballR)									// vertexes
					this.newTeta = -ballTeta - pi + 2*Math.atan((y-y2)/(x-x2));
				else this.newTeta = ballTeta;

				if (--health === 0) this.dead = true;
				return true;
			} else return false;
		}
	}

	function Pad() {
		var r = 7/100*gameW,
			h = 1/100*gameH,
			x = gameW/2,
			y = gameH-h; // hitbox prevents the ball from hitting the pad more than once

		function draw() {
			c.fillStyle = 'white';
			c.fillRect(x-r, y, 2*r, h);

			// DEBUG
			fastLine(x, y, x, 0, 'white', 2);
		}

		this.direction = false;
		this.speed = 15;
		this.newTeta = 0;

		this.collision = function(ballX, ballY, ballR, ballTeta) {
			var dX = ballX - x;

			if (Math.abs(dX) <= r && ballY+ballR >= y && ballTeta.between(pi, 2*pi)) {
				this.newTeta = pi/2 - dX*(pi/3)/r;
				return true;
			}
			return false;
		}

		this.update = function() {
			if (this.direction === 'left') {
				x -= this.speed;

				if (x-r < 0) {
					this.direction = false;
					x = r;
				}
			}

			if (this.direction === 'right') {
				x += this.speed;

				if (x+r > gameW) {
					this.direction = false;
					x = gameW-r;
				}
			}

			draw();
		}

		draw();
	}

	function Ball() {
		var r = 1.5/100*gameW,
			x = gameW/2,
			y = gameH - gameH/100*5,
			teta = Math.random()*4*pi/6 + pi/6,
			speed = 10;

		function draw() {
			c.fillStyle = 'lightgrey';
			c.beginPath();
			c.arc(x, y, r, 0, pi*2);
			c.closePath();
			c.fill();

			// DEBUG
			fastLine(x, 0, x, gameH, 'lightgrey', 2);
			fastLine(0, y, gameW, y, 'lightgrey', 2);
			c.fillText('ballTeta = ' + teta/pi*180, 50, gameH - 200);
			fastLine(x, y, x + 1000*Math.cos(-teta), y + 1000*Math.sin(-teta), 'pink', 2);
		}

		this.update = function() {
			// Walls
			if (x+r >= gameW || x-r <= 0) teta = teta <= pi ? pi - teta : 3*pi - teta;	// right-left
			if (y-r <= 0) teta = 2*pi - teta;											// top
			if (pad.collision(x, y, r, teta)) teta = pad.newTeta;						// pad

			// Bricks
			for (var i=0, b; b = bricks[i]; i++) if (b.collision(x, y, r, teta)) {
				teta = b.newTeta;
				if (b.dead) bricks.splice(i--, 1);
			}

			x += speed*Math.cos(teta);
			y -= speed*Math.sin(teta);

			draw();
		}

		draw();
	}

	function spawnBricks(rows, columns, height) {
		var width = gameW/columns,
			height = height/100*gameH,
			color = 'red',
			health = 3,
			b;

		for (var i=0; i < rows; i++) {
			for (var j=0; j < columns; j++) {
				if (i > 1) { color = 'yellow'; health = 2; }
				if (i > 4) { color = 'green'; health = 1; }
				b = new Brick(j*width, i*height, width, height, color, health);
				b.draw();
				bricks.push(b);
			}
		}
	}

	function update() {
		c.clearRect(0, 0, gameW, gameH);

		for (var i=0, b; b = bricks[i]; i++) b.draw();
		pad.update();
		ball.update();

		animationID = requestAnimationFrame(update);
	}

	this.start = function() {
		CANVAS.width = CANVAS.height = gameW > gameH ? gameW = gameH : gameH = gameW;
		c = CANVAS.getContext('2d');

		spawnBricks(10, 10, 5);
		pad = new Pad();
		ball = new Ball();

		document.addEventListener('keydown', function(e) {
			if (e.keyCode === 37) pad.direction = 'left';
			if (e.keyCode === 39) pad.direction = 'right';
		});

		document.addEventListener('keyup', function(e) {
			if ((e.keyCode === 37 && pad.direction === 'left') || (e.keyCode === 39 && pad.direction === 'right')) pad.direction = false;
		});

		animationID = requestAnimationFrame(update);
	}
}

var game = new Game();
game.start();<|endoftext|>


<commit_before>/*
  Kashev Dalmia
  kashev.dalmia@gmail.com

  Everyone Needs to Wake Up
  A Project for ARTD 313 @ UIUC, Sp 2014
  proj1b - dalmia3

  main.js
*/<commit_msg>Added js to make slides 'work'<commit_after>/*
  Kashev Dalmia
  kashev.dalmia@gmail.com

  Everyone Needs to Wake Up
  A Project for ARTD 313 @ UIUC, Sp 2014
  proj1b - dalmia3

  main.js
*/

// Add to remove JSHint Error about Bespoke

/* global bespoke:false */
var deck = bespoke.from('#presentation', {
  // Plugins:
  keys: true,
  touch: true,
  bullets: 'li'
});
<|endoftext|>


<commit_before>define(['./watcher'], function($watcher) {
  return $watcher;
});
<commit_msg>Delete main.js<commit_after><|endoftext|>


<commit_before>import '../styles/main.scss'
import * as hbs from '../templates'
import 'bootstrap';
import db from 'baqend';

const data = {};
let co_url;
let bq_url = 'https://makefast-staging.app.baqend.com';
let co_start = 0;
let bq_start = 0;
let co_time = 0;
let bq_time = 0;
let timer = 0;
let co_time_display;
let bq_time_display;

db.connect('makefast', true);

document.addEventListener("DOMContentLoaded", () => {
    $("#main").html(hbs.main(data));
    co_time_display = $('.co_time');
    bq_time_display = $('.bq_time');

    $('#iframe-baqend').hover(() =>{
            $('.openButton').animate({opacity:1},100)
        },function(){
            $('.openButton').animate({opacity:0},100)
        }
    )
});

window.openBaqendFrame = () => {
    let win = window.open(getBaqendUrl(), '_blank');
    win.focus();
};

window.reload = () => {
    let urlInput = $('#currentVendorUrl').val();
    co_url = urlInput.indexOf('http://') !== -1 || urlInput.indexOf('https://') !== -1 ? urlInput : 'http://' + urlInput;

    if(co_url) {
        $('.center-vertical').animate({ 'marginTop': '0px'}, 500);
        db.ready().then(() => {
            db.modules.get('checkCors', {url: co_url}).then((check) => {
                if (check.isDenied) {
                    $('#modalButton').click();
                } else {
                    resetComparison();
                    $('#compareContent').addClass('invisible');
                    $('#info').addClass('hidden');
                    $('#preWarming').removeClass('hidden');

                    $('.carousel').carousel({
                        interval: 1200,
                        wrap: false
                    });
                    $('.carousel').carousel(0);
                    $('.carousel').carousel('cycle');

                    startPreWarming();
                }
            });
        });
    }
};

window.contactUs = (e) => {
    e.preventDefault();

    let data = {
        name: $('#c_name').val(),
        email: $('#c_email').val(),
        url: co_url,
        subject: 'from page speed comparison'
    };

    $.post('https://bbq-bq.global.ssl.fastly.net/v1/code/mailUs', data, (data, status, xhr) => {
         let form = $('#contact_form');
         form.find('.modal-body').html("
Thanks. We will get in touch shortly. " +
             "Check out our benchmark in the meantime
");
         form.find('.c_submit').remove();
     });
};

window.frameLoaded = (iframe) => {
    let stop = new Date().getTime();
    clearInterval(timer);
    if(iframe !== 'competitor') {
        if(bq_start > 0) {
            bq_time = (stop - bq_start) / 1000;

            if(co_time / bq_time >= 1) {
                $('#resultInfo').html('Baqend makes your site ' + (co_time / bq_time).toFixed(2) + 'x faster.');
            }
        }
    } else {
        if(co_start > 0) {
            co_time = (stop - co_start) / 1000;
            setTimeout(() => {
                let frame = createFrame('baqend', 'baqendFrame', 'myframe loading', getBaqendUrl());
                frame.onload = () => {
                    frameLoaded();
                };

                $('#iframe-baqend').append(frame);
                $('#iframe-baqend').removeClass('hide');
                $('#wListConfig').removeClass('hide');

                bq_start = new Date().getTime();
                timer = setInterval(updateTime, 1, bq_time_display, bq_start);
            }, 1000);
        }
    }
};

window.startComparison = () => {
    $('#competitorFrame').remove();
    let frame = createFrame('competitor', 'competitorFrame', 'myframe loading', co_url);

    frame.onload = () => {
        frameLoaded('competitor');
    };

    $('#iframe-competitor').append(frame);

    co_start = new Date().getTime();
    timer = setInterval(updateTime, 1, co_time_display, co_start);
};

function startPreWarming() {
    $('#baqendFrame').remove();
    let frame = createFrame('baqend', 'baqendFrame', 'myframe', getBaqendUrl());

    frame.onload = () => {
        setTimeout(() => {
            $('#compareContent').removeClass('invisible');
            $('#info').removeClass('hidden');
            $('#preWarming').addClass('hidden');
            $('#baqendFrame').remove();
            startComparison();
        }, 5000);
    };
    $('#iframe-baqend').append(frame);
}

function resetComparison() {
    clearInterval(timer);
    co_start = 0;
    bq_start = 0;
    co_time = 0;
    bq_time = 0;
    $('.co_time').html('...');
    $('.bq_time').html('...');
    $('#resultInfo').html('Can Baqend speed up your site?');
    $('#iframe_competitor').prop('src', '');
    $('#iframe_baqend').prop('src', '');
    $('.myframe').removeClass('loading');
}

function createFrame(name, id, classString, source) {
    let frame = document.createElement('iframe');
    frame.setAttribute('name', name);
    frame.setAttribute('id', id);
    frame.setAttribute('class', classString);
    frame.setAttribute('src', source);
    return frame;
}

function getBaqendUrl() {
    return bq_url + '?url=' + encodeURIComponent(co_url) + '&wlist=' +  generateWhiteList();
}

function generateWhiteList() {
    let wListString = new URL(co_url).host;
    if(wListString.indexOf('www') !== -1) {
        wListString = wListString.substr(wListString.indexOf('.') + 1);
    }
    wListString = '"^(https?:\\/\\/)?([\\w-]*\.){0,3}' + wListString.substr(wListString, wListString.indexOf('.') + 1) + '.*$"';

    let wListInputArray = document.getElementById('wListInput').value.split(',');
    if(wListInputArray[0] !== '') {
        for(let i = 0; i < wListInputArray.length; i++)
        {
            wListString += ',';
            wListString += '"^(https?:\\/\\/)?([\\w-]*\.){0,3}' + wListInputArray[i] + '.*$"';
        }
    }

    return encodeURIComponent(wListString);
}

function updateTime(time_display, start_time) {
    let now = new Date().getTime();
    let current = (now - start_time) / 1000;
    time_display.html(current.toFixed(3) + 's');
}<commit_msg>code cosmetics<commit_after>import '../styles/main.scss'
import * as hbs from '../templates'
import 'bootstrap';
import db from 'baqend';

const data = {};
let co_url;
let bq_url = 'https://makefast-staging.app.baqend.com';
let co_start = 0;
let bq_start = 0;
let co_time = 0;
let bq_time = 0;
let timer = 0;
let timeout = 0;
let co_time_display;
let bq_time_display;
let bq_frame;

db.connect('makefast', true);

document.addEventListener("DOMContentLoaded", () => {
    $("#main").html(hbs.main(data));
    co_time_display = $('.co_time');
    bq_time_display = $('.bq_time');
    bq_frame = $('#iframe-baqend');

    if(getUrlParam('url') !== '') {
        $('#currentVendorUrl').val(getUrlParam('url'));
    }

    if(getUrlParam('wlist') !== '') {
        $('#wListInput').val(getUrlParam('wlist'));
        $('#wListConfig').removeClass('hide');
    }

    bq_frame.hover(() =>{
            $('.openButton').animate({opacity:1},100)
        },function(){
            $('.openButton').animate({opacity:0},100)
        }
    );
});

window.addEventListener('message', (event) => {
    if(event.data === 'reload') {
        clearTimeout(timeout);
    }
});

window.openBaqendFrame = () => {
    let win = window.open(getBaqendUrl(false), '_blank');
    win.focus();
};

window.reload = () => {
    let urlInput = $('#currentVendorUrl').val();
    co_url = urlInput.indexOf('http://') !== -1 || urlInput.indexOf('https://') !== -1 ? urlInput : 'http://' + urlInput;

    if(co_url) {
        $('.center-vertical').animate({ 'marginTop': '0px'}, 500);
        db.ready().then(() => {
            db.modules.get('checkCors', {url: co_url}).then((check) => {
                if (check.isDenied) {
                    $('#modalButton').click();
                } else {
                    resetComparison();
                    $('#compareContent').addClass('invisible');
                    $('#info').addClass('hidden');
                    $('#preWarming').removeClass('hidden');

                    const carousel = $('.carousel').carousel({
                        interval: 1200,
                        wrap: false
                    });

                    carousel.carousel(0);
                    carousel.carousel('cycle');

                    startPreWarming();
                }
            });
        });
    }
};

window.contactUs = (e) => {
    e.preventDefault();

    let data = {
        name: $('#c_name').val(),
        email: $('#c_email').val(),
        url: co_url,
        subject: 'from page speed comparison'
    };

    $.post('https://bbq-bq.global.ssl.fastly.net/v1/code/mailUs', data, (data, status, xhr) => {
         let form = $('#contact_form');
         form.find('.modal-body').html("
Thanks. We will get in touch shortly. " +
             "Check out our benchmark in the meantime
");
         form.find('.c_submit').remove();
     });
};

window.frameLoaded = (iframe) => {
    let stop = new Date().getTime();
    clearInterval(timer);
    if(iframe !== 'competitor') {
        if(bq_start > 0) {
            bq_time = (stop - bq_start) / 1000;
            bq_time_display.html(bq_time.toFixed(3) + 's');

            if(co_time / bq_time >= 1) {
                $('#resultInfo').html('Baqend makes your site ' + (co_time / bq_time).toFixed(2) + 'x faster.');
            }
        }
    } else {
        if(co_start > 0) {
            co_time = (stop - co_start) / 1000;
            co_time_display.html(co_time.toFixed(3) + 's');

            setTimeout(() => {
                let frame = createFrame('baqend', 'baqendFrame', 'myframe loading', getBaqendUrl(false));
                frame.onload = () => {
                    frameLoaded();
                };

                bq_frame.append(frame);
                bq_frame.removeClass('hide');
                $('#wListConfig').removeClass('hide');

                bq_start = new Date().getTime();
                timer = setInterval(updateTime, 1, bq_time_display, bq_start);
            }, 1000);
        }
    }
};

window.startComparison = () => {
    $('#competitorFrame').remove();

    let frame = createFrame('competitor', 'competitorFrame', 'myframe loading', co_url);

    frame.onload = () => {
        frameLoaded('competitor');
    };

    $('#iframe-competitor').append(frame);

    co_start = new Date().getTime();

    timer = setInterval(updateTime, 1, co_time_display, co_start);
};

function getBaqendUrl(noCaching) {
    let url = bq_url + '?url=' + encodeURIComponent(co_url) + '&wlist=' +  generateWhiteList();
    if(noCaching) {
        url += '&noCaching=' + noCaching;
    }
    return url;
}

function getUrlParam(name) {
    return (location.search.split(name + '=')[1] || '').split('&')[0];
}

function startPreWarming() {
    $('#baqendFrame').remove();
    let frame = createFrame('baqend', 'baqendFrame', 'myframe', getBaqendUrl(true));

    frame.onload = () => {
        timeout = setTimeout(() => {
            $('#compareContent').removeClass('invisible');
            $('#info').removeClass('hidden');
            $('#preWarming').addClass('hidden');
            $('#baqendFrame').remove();
            startComparison();
        }, 5000);
    };
    bq_frame.append(frame);
}

function resetComparison() {
    clearInterval(timer);
    timer = 0;
    co_start = 0;
    bq_start = 0;
    co_time = 0;
    bq_time = 0;
    $('.co_time').html('...');
    $('.bq_time').html('...');
    $('#resultInfo').html('Can Baqend speed up your site?');
    $('#iframe_competitor').prop('src', '');
    $('#iframe_baqend').prop('src', '');
    $('.myframe').removeClass('loading');
}

function createFrame(name, id, classString, source) {
    let frame = document.createElement('iframe');
    frame.setAttribute('name', name);
    frame.setAttribute('id', id);
    frame.setAttribute('class', classString);
    frame.setAttribute('src', source);
    return frame;
}

function generateWhiteList() {
    let wListString = new URL(co_url).host;
    if(wListString.indexOf('www') !== -1) {
        wListString = wListString.substr(wListString.indexOf('.') + 1);
    }
    wListString = '"^(https?:\\/\\/)?([\\w-]*\.){0,3}' + wListString.substr(0, wListString.indexOf('.') + 1) + '.*$"';

    let wListInputArray = document.getElementById('wListInput').value.split(',');
    if(wListInputArray[0] !== '') {
        for(let i = 0; i < wListInputArray.length; i++)
        {
            wListString += ',';
            wListString += '"^(https?:\\/\\/)?([\\w-]*\.){0,3}' + wListInputArray[i] + '.*$"';
        }
    }

    return encodeURIComponent(wListString);
}

function updateTime(time_display, start_time) {
    let now = new Date().getTime();
    let current = (now - start_time) / 1000;
    time_display.html(current.toFixed(3) + 's');
}<|endoftext|>


<commit_before>/* jshint browser: true */
/* global console, Pebble */

var SGV_FETCH_COUNT = 72;
var SGV_FOR_PEBBLE_COUNT = 36;
var INTERVAL_SIZE_SECONDS = 5 * 60;
var IOB_RECENCY_THRESHOLD_SECONDS = 10 * 60;
var REQUEST_TIMEOUT = 5000;
var NO_DELTA_VALUE = 65536;

var CONFIG_URL = 'https://mddub.github.io/nightscout-graph-pebble/config/';
var LOCAL_STORAGE_KEY_CONFIG = 'config';

var MSG_TYPE_ERROR = 0;
var MSG_TYPE_DATA = 1;
var MSG_TYPE_PREFERENCES = 2;

var config = {
  nightscout_url: '',
  mmol: false,
};

function handleError(e) {
  console.log(e);
  sendMessage({msgType: MSG_TYPE_ERROR});
}

// In PebbleKit JS, specifying a timeout works only for synchronous XHR,
// except on Android, where synchronous XHR doesn't work at all.
// https://forums.getpebble.com/discussion/13224/problem-with-xmlhttprequest-timeout
function getURL(url, callback) {
  var received = false;
  var timedOut = false;

  var xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);
  xhr.onreadystatechange = function () {
    if (timedOut) {
      return;
    }
    if (xhr.readyState === 4) {
      received = true;
      if (xhr.status === 200) {
        callback(xhr.responseText);
      } else {
        handleError(new Error('Request failed, status ' + xhr.status + ': ' + url));
      }
    }
  };
  xhr.send(null);

  setTimeout(function() {
    if (received) {
      return;
    }
    timedOut = true;
    handleError(new Error('Request timed out: ' + url));
  }, REQUEST_TIMEOUT);
}

function getJSON(url, callback) {
  getURL(url, function(result) {
    try {
      callback(JSON.parse(result));
    } catch (e) {
      handleError(e);
    }
  });
}

function getIOB(callback) {
  getJSON(config.nightscout_url + '/api/v1/entries.json?find[activeInsulin][$exists]=true&count=1', function(iobs) {
    if(iobs.length && Date.now() - iobs[0]['date'] <= IOB_RECENCY_THRESHOLD_SECONDS * 1000) {
      var recency = Math.floor((Date.now() - iobs[0]['date']) / (60 * 1000));
      var iob = iobs[0]['activeInsulin'].toFixed(1).toString() + ' u (' + recency + ')';
      callback(iob);
    } else {
      callback('-');
    }
  });
}

function getSGVsDateDescending(callback) {
  getJSON(config.nightscout_url + '/api/v1/entries/sgv.json?count=' + SGV_FETCH_COUNT, function(entries) {
    callback(entries.map(function(e) {
      e['date'] = e['date'] / 1000;
      return e;
    }));
  });
}

function graphArray(sgvs) {
  var endTime = sgvs[0]['date'];
  var noEntry = {
    'date': Infinity,
    'sgv': 0
  };
  var i;

  var graphed = [];
  var xs = [];
  for(i = SGV_FOR_PEBBLE_COUNT - 1; i >= 0; i--) {
    graphed.push(noEntry);
    xs.push(endTime - i * INTERVAL_SIZE_SECONDS);
  }

  // This n^2 algorithm sacrifices efficiency for clarity
  for(i = 0; i < sgvs.length; i++) {
    var min = Infinity;
    var xi;
    // Find the x value closest to this sgv's date
    for(var j = 0; j < xs.length; j++) {
      if(Math.abs(sgvs[i]['date'] - xs[j]) < min) {
        min = Math.abs(sgvs[i]['date'] - xs[j]);
        xi = j;
      }
    }
    // Assign it if it's the closest sgv to that x
    if(min < INTERVAL_SIZE_SECONDS && Math.abs(sgvs[i]['date'] - xs[xi]) < Math.abs(graphed[xi]['date'] - xs[xi])) {
      graphed[xi] = sgvs[i];
    }
  }

  var ys = graphed.map(function(entry) { return entry['sgv']; });

  return ys;
}

function lastSgv(sgvs) {
  return parseInt(sgvs[0]['sgv'], 10);
}

function directionToTrend(direction) {
  return {
    'NONE': 0,
    'DoubleUp': 1,
    'SingleUp': 2,
    'FortyFiveUp': 3,
    'Flat': 4,
    'FortyFiveDown': 5,
    'SingleDown': 6,
    'DoubleDown': 7,
    'NOT COMPUTABLE': 8,
    'RATE OUT OF RANGE': 9,
  }[direction];
}

function lastTrendNumber(sgvs) {
  var trend = sgvs[0]['trend'];
  if (trend !== undefined && trend >= 0 && trend <= 9) {
    return trend;
  } else if (sgvs[0]['direction'] !== undefined) {
    return directionToTrend(sgvs[0]['direction']);
  } else {
    return 0;
  }
}

function lastDelta(ys) {
  if (ys[ys.length - 2] === 0) {
    return NO_DELTA_VALUE;
  } else {
    return ys[ys.length - 1] - ys[ys.length - 2];
  }
}

function recency(sgvs) {
  var seconds = Date.now() / 1000 - sgvs[0]['date'];
  return Math.floor(seconds);
}

function sendMessage(data) {
  console.log('sending ' + JSON.stringify(data));
  Pebble.sendAppMessage(data);
}

function requestAndSendBGs() {
  function onData(sgvs, iobText) {
    try {
      var ys = graphArray(sgvs);
      sendMessage({
        msgType: MSG_TYPE_DATA,
        recency: recency(sgvs),
        // XXX: divide BG by 2 to fit into 1 byte
        sgvs: ys.map(function(y) { return Math.min(255, Math.floor(y / 2)); }),
        lastSgv: lastSgv(sgvs),
        trend: lastTrendNumber(sgvs),
        delta: lastDelta(ys),
        statusText: iobText,
      });
    } catch (e) {
      handleError(e);
    }
  }

  getSGVsDateDescending(function(sgvs) {
    getIOB(function(iobText) {
      onData(sgvs, iobText);
    });
  });
}

function sendPreferences() {
  sendMessage({
    msgType: MSG_TYPE_PREFERENCES,
    mmol: config.mmol,
  });
}

Pebble.addEventListener('ready', function() {
  var configStr = localStorage.getItem(LOCAL_STORAGE_KEY_CONFIG);
  if (configStr !== null) {
    try {
      config = JSON.parse(configStr);
    } catch (e) {
      console.log('Bad config: ' + configStr);
    }
  }

  Pebble.addEventListener('showConfiguration', function() {
    Pebble.openURL(CONFIG_URL + '?current=' + encodeURIComponent(JSON.stringify(config)));
  });

  Pebble.addEventListener('webviewclosed', function(e) {
    var configStr = decodeURIComponent(e.response);
    config = JSON.parse(configStr);
    localStorage.setItem(LOCAL_STORAGE_KEY_CONFIG, configStr);
    sendPreferences();
    requestAndSendBGs();
  });

  Pebble.addEventListener('appmessage', function() {
    requestAndSendBGs();
  });

  // Send data immediately after the watchface is launched
  requestAndSendBGs();
});
<commit_msg>Don't fail if SGVs can be fetched but status bar text can't<commit_after>/* jshint browser: true */
/* global console, Pebble */

var SGV_FETCH_COUNT = 72;
var SGV_FOR_PEBBLE_COUNT = 36;
var INTERVAL_SIZE_SECONDS = 5 * 60;
var IOB_RECENCY_THRESHOLD_SECONDS = 10 * 60;
var REQUEST_TIMEOUT = 5000;
var NO_DELTA_VALUE = 65536;

var CONFIG_URL = 'https://mddub.github.io/nightscout-graph-pebble/config/';
var LOCAL_STORAGE_KEY_CONFIG = 'config';

var MSG_TYPE_ERROR = 0;
var MSG_TYPE_DATA = 1;
var MSG_TYPE_PREFERENCES = 2;

var config = {
  nightscout_url: '',
  mmol: false,
};

function sgvDataError(e) {
  console.log(e);
  sendMessage({msgType: MSG_TYPE_ERROR});
}

// In PebbleKit JS, specifying a timeout works only for synchronous XHR,
// except on Android, where synchronous XHR doesn't work at all.
// https://forums.getpebble.com/discussion/13224/problem-with-xmlhttprequest-timeout
function getURL(url, callback) {
  var received = false;
  var timedOut = false;

  var xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);
  xhr.onreadystatechange = function () {
    if (timedOut) {
      return;
    }
    if (xhr.readyState === 4) {
      received = true;
      if (xhr.status === 200) {
        callback(null, xhr.responseText);
      } else {
        callback(new Error('Request failed, status ' + xhr.status + ': ' + url));
      }
    }
  };
  xhr.send(null);

  setTimeout(function() {
    if (received) {
      return;
    }
    timedOut = true;
    xhr.abort();
    callback(new Error('Request timed out: ' + url));
  }, REQUEST_TIMEOUT);
}

function getJSON(url, callback) {
  getURL(url, function(err, result) {
    if (err) {
      return callback(err);
    }
    try {
      callback(null, JSON.parse(result));
    } catch (e) {
      callback(e);
    }
  });
}

function getIOB(callback) {
  getJSON(config.nightscout_url + '/api/v1/entries.json?find[activeInsulin][$exists]=true&count=1', function(err, iobs) {
    if (err) {
      return callback(err);
    }
    if(iobs.length && Date.now() - iobs[0]['date'] <= IOB_RECENCY_THRESHOLD_SECONDS * 1000) {
      var recency = Math.floor((Date.now() - iobs[0]['date']) / (60 * 1000));
      var iob = iobs[0]['activeInsulin'].toFixed(1).toString() + ' u (' + recency + ')';
      callback(null, iob);
    } else {
      callback(null, '-');
    }
  });
}

function getSGVsDateDescending(callback) {
  getJSON(config.nightscout_url + '/api/v1/entries/sgv.json?count=' + SGV_FETCH_COUNT, function(err, entries) {
    if (err) {
      return callback(err);
    }
    callback(null, entries.map(function(e) {
      e['date'] = e['date'] / 1000;
      return e;
    }));
  });
}

function graphArray(sgvs) {
  var endTime = sgvs[0]['date'];
  var noEntry = {
    'date': Infinity,
    'sgv': 0
  };
  var i;

  var graphed = [];
  var xs = [];
  for(i = SGV_FOR_PEBBLE_COUNT - 1; i >= 0; i--) {
    graphed.push(noEntry);
    xs.push(endTime - i * INTERVAL_SIZE_SECONDS);
  }

  // This n^2 algorithm sacrifices efficiency for clarity
  for(i = 0; i < sgvs.length; i++) {
    var min = Infinity;
    var xi;
    // Find the x value closest to this sgv's date
    for(var j = 0; j < xs.length; j++) {
      if(Math.abs(sgvs[i]['date'] - xs[j]) < min) {
        min = Math.abs(sgvs[i]['date'] - xs[j]);
        xi = j;
      }
    }
    // Assign it if it's the closest sgv to that x
    if(min < INTERVAL_SIZE_SECONDS && Math.abs(sgvs[i]['date'] - xs[xi]) < Math.abs(graphed[xi]['date'] - xs[xi])) {
      graphed[xi] = sgvs[i];
    }
  }

  var ys = graphed.map(function(entry) { return entry['sgv']; });

  return ys;
}

function lastSgv(sgvs) {
  return parseInt(sgvs[0]['sgv'], 10);
}

function directionToTrend(direction) {
  return {
    'NONE': 0,
    'DoubleUp': 1,
    'SingleUp': 2,
    'FortyFiveUp': 3,
    'Flat': 4,
    'FortyFiveDown': 5,
    'SingleDown': 6,
    'DoubleDown': 7,
    'NOT COMPUTABLE': 8,
    'RATE OUT OF RANGE': 9,
  }[direction];
}

function lastTrendNumber(sgvs) {
  var trend = sgvs[0]['trend'];
  if (trend !== undefined && trend >= 0 && trend <= 9) {
    return trend;
  } else if (sgvs[0]['direction'] !== undefined) {
    return directionToTrend(sgvs[0]['direction']);
  } else {
    return 0;
  }
}

function lastDelta(ys) {
  if (ys[ys.length - 2] === 0) {
    return NO_DELTA_VALUE;
  } else {
    return ys[ys.length - 1] - ys[ys.length - 2];
  }
}

function recency(sgvs) {
  var seconds = Date.now() / 1000 - sgvs[0]['date'];
  return Math.floor(seconds);
}

function sendMessage(data) {
  console.log('sending ' + JSON.stringify(data));
  Pebble.sendAppMessage(data);
}

function requestAndSendBGs() {
  function onData(sgvs, iobText) {
    try {
      var ys = graphArray(sgvs);
      sendMessage({
        msgType: MSG_TYPE_DATA,
        recency: recency(sgvs),
        // XXX: divide BG by 2 to fit into 1 byte
        sgvs: ys.map(function(y) { return Math.min(255, Math.floor(y / 2)); }),
        lastSgv: lastSgv(sgvs),
        trend: lastTrendNumber(sgvs),
        delta: lastDelta(ys),
        statusText: iobText,
      });
    } catch (e) {
      sgvDataError(e);
    }
  }

  getSGVsDateDescending(function(err, sgvs) {
    if (err) {
      // error fetching sgvs is unrecoverable
      sgvDataError(err);
    } else {
      getIOB(function(err, iobText) {
        if (err) {
          // error fetching status bar text is okay
          console.log(err);
          iobText = '-';
        }
        onData(sgvs, iobText);
      });
    }
  });
}

function sendPreferences() {
  sendMessage({
    msgType: MSG_TYPE_PREFERENCES,
    mmol: config.mmol,
  });
}

Pebble.addEventListener('ready', function() {
  var configStr = localStorage.getItem(LOCAL_STORAGE_KEY_CONFIG);
  if (configStr !== null) {
    try {
      config = JSON.parse(configStr);
    } catch (e) {
      console.log('Bad config: ' + configStr);
    }
  }

  Pebble.addEventListener('showConfiguration', function() {
    Pebble.openURL(CONFIG_URL + '?current=' + encodeURIComponent(JSON.stringify(config)));
  });

  Pebble.addEventListener('webviewclosed', function(e) {
    var configStr = decodeURIComponent(e.response);
    config = JSON.parse(configStr);
    localStorage.setItem(LOCAL_STORAGE_KEY_CONFIG, configStr);
    sendPreferences();
    requestAndSendBGs();
  });

  Pebble.addEventListener('appmessage', function() {
    requestAndSendBGs();
  });

  // Send data immediately after the watchface is launched
  requestAndSendBGs();
});
<|endoftext|>