<commit_before>/**
 * rowcol - a library for row-column data manipulation
 * @module rowcol
 * @author Samuel Rouse <samuel.rouse@gmail.com>
 * @license MIT http://opensource.org/licenses/MIT
 */

/*--------------------------------------------------------------------------*/
/*
 * Constants and basic settings
 * Structure and code from Lo-Dash 2.4.1 <http://lodash.com/>
 */

const version = '3.0.0';

/*--------------------------------------------------------------------------*/

/* Functions */
const { has } = require('./util');

/**
 * Indicates if the passed object is an array
 * @param {*} obj
 * @returns {boolean}
 */
function isArray(obj) {
  return Object.prototype.toString.call(obj) === '[object Array]';
}

function getIndexesWithFunction(array, filter) {
  const indexes = [];
  const len = array.length;
  let i;

  for (i = 0; i < len; i += 1) {
    if (filter(array[i], i)) {
      indexes.push(i);
    }
  }

  return indexes;
}

function getIndexesWithValue(array, filter) {
  const indexes = [];
  const len = array.length;
  let i;

  for (i = 0; i < len; i += 1) {
    if (array[i] === filter) {
      indexes.push(i);
    }
  }

  return indexes;
}

/**
 * Returns an array of indexes that match a filter string or function.
 * @param {Array} array Array of values to match
 * @param {Function|String} filter Function or String to match array values.
 * @returns {Array} Array of indexes that match the filter.
 */
function getIndexes(array, filter) {
  if (typeof filter === 'function') {
    return getIndexesWithFunction(array, filter);
  }
  return getIndexesWithValue(array, filter);
}

/**
 * Returns the elements of an array using a list of selected indexes.
 * @param {Array} array
 * @param {Array} indexes
 * @returns {Array}
 */
function getByIndexes(array, indexes) {
  let i;
  const len = indexes.length;
  const data = [];

  for (i = 0; i < len; i += 1) {
    data.push(array[indexes[i]]);
  }
  return data;
}

/**
 * Performs the rotation for an unlimited (regular) rotation
 * @param {Array} arr
 * @param {Object} result
 * @returns {Object}
 */
function arrayRotateUnlimited(arr, result) {
  return arr.reduce((res, obj, i) => Object.entries(obj).reduce((acc, [key, val]) => {
    if (acc[key] === undefined) {
      acc[key] = [];
    }
    acc[key][i] = val;
    return acc;
  }, res), result);
}

/**
 * Performs the rotation for a limited (partial) rotation
 * @param {Array} arr
 * @param {Object} result
 * @param {Array|boolean} limited
 * @returns {Object}
 */
function arrayRotateLimited(arr, result, limited) {
  // If this is limited to the list of keys, get the keys for limited rotate
  // One pass to eliminate any unusable keys and create missing arrays
  const objKeys = (isArray(limited) ? limited : Object.keys(result)).filter((key) => {
    // Create arrays for missing keys
    if (undefined === result[key]) {
      result[key] = [];
      return true;
    }

    // Check if existing keys are arrays
    return isArray(result[key]);
  });

  arr.forEach((obj, i) => objKeys.reduce((acc, att) => {
    acc[att][i] = obj[att];
    return acc;
  }, result));

  return result;
}

/**
 * Rotate an array of row-data into a column-data object
 * @param {Array} arr
 * @param {Object} [result] Result object to use
 * @param {boolean} [limited] Only update keys on the result object; a limited rotation
 * @returns {Object}
 */
function arrayRotate(arr, result, limited = false) {
  const data = result || {};

  // Not an array? Send it back.
  if (!isArray(arr)) {
    throw new TypeError('RC: Argument is not an array');
  }

  if (limited && (typeof result !== 'object' || result === undefined)) {
    throw new TypeError("RC: Must pass a result object when 'limited' is true");
  }

  // Explicit check: you could pass [0], limited could be falsy.
  if (limited) {
    return arrayRotateLimited(arr, data, limited);
  }

  return arrayRotateUnlimited(arr, data);
}

/**
 *
 * @param obj
 * @param field
 * @param filter
 * @returns {Array}
 */
function filterIndexes(obj, field, filter) {
  let indexes = [];

  if (has(obj, field)) {
    indexes = getIndexes(obj[field], filter);
  }

  return indexes;
}

/**
 * Filters all properties in a column-data object using an array of indexes.
 * @param {Object} obj
 * @param {Array} indexes
 * @returns {Object}
 */
function filterMerge(obj, indexes) {
  // Don't waste time if there are no indexes to merge.
  if (indexes === undefined || !indexes.length) {
    return {};
  }

  return Object.entries(obj).reduce((acc, [key, val]) => {
    acc[key] = getByIndexes(val, indexes);
    return acc;
  }, {});
}

/**
 * Filter a column-data object for a particular field.
 * @param {Object} obj
 * @param {String} field
 * @param {Function|String} filter
 * @returns {*}
 */
function objectFilter(obj, field, filter) {
  return filterMerge(obj, filterIndexes(obj, field, filter));
}

/**
 * Finds the longest length of any property in a column-data object.
 * @param {Object} obj
 * @returns {number}
 */
function objectLength(obj) {
  return Math.max(0, ...Object.values(obj).map(arr => arr.length));
}

/**
 * Error throwing for object rotate
 * @param {Object} obj
 * @param result
 */
function objectRotateErrors(obj, result) {
  // Not an array? Send it back.
  if (typeof obj !== 'object') {
    throw new TypeError('RC: Argument is not an object');
  }

  // If a result is passed and isn't an array, send it back.
  if (undefined !== result && !isArray(result)) {
    throw new TypeError('RC: Result argument is not an array');
  }
}

/**
 * Rotates column-data to row-data and optionally adds it to an existing array.
 * @param {Object} obj
 * @param {Array} [result] Optional array init which we should place rotated data.
 * @param {Boolean} [clearUndef]
 * @returns {Array}
 */
function objectRotate(obj, result, clearUndef) {
  // Call out for errors
  objectRotateErrors(obj, result);

  // Don't replace parameters to avoid optimization issues.
  const output = result || [];

  // Get the existing result array length
  const resultOffset = output.length;

  const len = objectLength(obj);

  for (let i = 0; i < len; i += 1) {
    output[i + resultOffset] = Object.entries(obj).reduce((acc, [key, val]) => {
      if (!clearUndef || val[i] !== undefined) {
        acc[key] = val[i];
      }
      return acc;
    }, {});
  }

  return output;
}

/**
 * Create a
 * @param {Object} obj
 * @param {number} index
 * @param {Boolean} [clearUndef]
 * @param {Object} [result]
 * @returns {*}
 */
function objFromIndex(obj, index, clearUndef, result = {}) {
  return Object.entries(obj).reduce((acc, [key, val]) => {
    if (!clearUndef || val[index] !== undefined) {
      acc[key] = val[index];
    }
    return acc;
  }, result);
}

/**
 * A generic rotate function that accepts row or column data to rotate.
 * @param {Object|Array} obj
 * @param {...*} [args]
 * @returns {Array|Object}
 */
function rotate(obj, ...args) {
  // Generic, which directs to the appropriate array/object rotate
  if (typeof obj !== 'object') throw new TypeError('RC: rotate requires an object or an array');

  if (isArray(obj)) {
    return arrayRotate(obj, ...args);
  }
  return objectRotate(obj, ...args);
}

/**
 * Increment over column-data like it was array data, making a "read-only" object for each index.
 * Does not prevent modification of values with complex data types (objects, arrays).
 * @param {Object} obj
 * @param {Function} fn
 */
function readEach(obj, fn) {
  const len = objectLength(obj);

  for (let i = 0; i < len; i += 1) {
    fn(objFromIndex(obj, i));
  }
}

/**
 * Create an object and add a .commit() prototype to place the values back into the original.
 * Useful for moving simple data types around. Objects and arrays will be automatically referenced.
 * @constructor
 * @param {Object} obj - A columnar object
 * @param {number} index - The index to convert into a row-based object
 * @param {Boolean} [clearUndef] - Clear undefined attributes when copying the object.
 * @example
 * var proxyRow = new RowcolProxy(colData, index);
 */
const RCProxy = (function () {
  // TODO - swap out for ES6 proxy object
  const proxyObj = [];
  const proxyIdx = [];
  const proxyClearFlag = [];
  const proxyThis = [];
  let guid = 0;

  /**
   * Uses a private array to locate the same object,
   * so the proxy doesn't expose itself to modification.
   * We compare the passed object against an array of existing RowcolProxy objects;
   * basically pointer comparison.
   * @param {RowcolProxy} proxy
   * @returns {number} The proxy ID to allow commit and destroy to locate the correct element
   * @private
   */
  function proxyGetId(proxy) {
    let pid;

    // Most likely to be at the end, so start there
    for (let i = proxyThis.length; i;) {
      i -= 1;
      if (proxyThis[i] === proxy) {
        pid = i;
        break;
      }
    }

    if (pid === undefined) {
      throw new ReferenceError('Proxy is finalized and cannot be used again.');
    }
    return pid;
  }

  /**
   * The actual RowcolProxy constructor.
   * @param {Object} obj
   * @param {number} index
   * @param {Boolean} [clearUndef]
   * @constructor
   */
  function RowcolProxy(obj, index, clearUndef) {
    // Increment the guid
    guid += 1;

    // Set the private data.
    proxyObj[guid] = obj;
    proxyIdx[guid] = index;
    proxyClearFlag[guid] = clearUndef;
    proxyThis[guid] = this;

    // Call reusable code for objFromIndex
    objFromIndex(obj, index, clearUndef, this);
  }

  // Defined inside the constructor to give it access to the originating object and parameters

  /**
   * Commits the changes from the proxy to the original.
   */
  RowcolProxy.prototype.commit = function () {
    const pid = proxyGetId(this);
    const obj = proxyObj[pid];
    const index = proxyIdx[pid];
    const clearUndef = proxyClearFlag[pid];

    Object.entries(this).reduce((acc, [key, val]) => {
      if (key === '__rcProxyId') {
        return acc;
      }
      if (!clearUndef || val !== undefined) {
        acc[key][index] = val;
      }
      return acc;
    }, obj);
  };

  /**
   * Removes the proxy to prevent memory leaks
   */
  RowcolProxy.prototype.destroy = function () {
    const pid = proxyGetId(this);
    delete proxyThis[pid];
    delete proxyObj[pid];
    delete proxyIdx[pid];
    delete proxyClearFlag[pid];
  };

  /**
   * Commit and destroy the proxy, as a single step
   */
  RowcolProxy.prototype.finalize = function () {
    this.commit();
    this.destroy();
  };

  return RowcolProxy;
}());

/**
 * Create a proxy
 * @param obj
 * @param index
 * @param clearUndef
 */
function proxyFromIndex(obj, index, clearUndef) {
  return new RCProxy(obj, index, clearUndef);
}

/**
 * Increment over column-data like it was array data, making a proxy object for each index.
 * @param {Object} obj
 * @param {Function} fn
 */
function objEach(obj, fn) {
  const len = objectLength(obj);
  let i = 0;
  let prox;

  for (; i < len; i += 1) {
    prox = new RCProxy(obj, i);

    fn(prox, i);

    prox.finalize();
  }
}

/*--------------------------------------------------------------------------*/

const rowcol = {
  rotate,
  proxy: proxyFromIndex,
  array: {
    getIndexes,
    getByIndexes,
    rotate: arrayRotate,
  },
  object: {
    filter: objectFilter,
    filterIndexes,
    filterMerge,
    rotate: objectRotate,
    objFromIndex,
    proxy: proxyFromIndex,
    readEach,
    each: objEach,
    objLength: objectLength,
  },
  VERSION: version,
  test: {
    isArray,
  },
};

/*--------------------------------------------------------------------------*/

module.exports = rowcol;
<commit_msg>CodeClimate cleanup<commit_after>/**
 * rowcol - a library for row-column data manipulation
 * @module rowcol
 * @author Samuel Rouse <samuel.rouse@gmail.com>
 * @license MIT http://opensource.org/licenses/MIT
 */

/*--------------------------------------------------------------------------*/
/*
 * Constants and basic settings
 * Structure and code from Lo-Dash 2.4.1 <http://lodash.com/>
 */

const version = '3.0.0';

/*--------------------------------------------------------------------------*/

/* Functions */
const { has } = require('./util');

/**
 * Indicates if the passed object is an array
 * @param {*} obj
 * @returns {boolean}
 */
function isArray(obj) {
  return Object.prototype.toString.call(obj) === '[object Array]';
}

function getIndexesWithFunction(array, filter) {
  const indexes = [];
  const len = array.length;
  let i;

  for (i = 0; i < len; i += 1) {
    if (filter(array[i], i)) {
      indexes.push(i);
    }
  }

  return indexes;
}

function getIndexesWithValue(array, filter) {
  const indexes = [];
  const len = array.length;
  let i;

  for (i = 0; i < len; i += 1) {
    if (array[i] === filter) {
      indexes.push(i);
    }
  }

  return indexes;
}

/**
 * Returns an array of indexes that match a filter string or function.
 * @param {Array} array Array of values to match
 * @param {Function|String} filter Function or String to match array values.
 * @returns {Array} Array of indexes that match the filter.
 */
function getIndexes(array, filter) {
  if (typeof filter === 'function') {
    return getIndexesWithFunction(array, filter);
  }
  return getIndexesWithValue(array, filter);
}

/**
 * Returns the elements of an array using a list of selected indexes.
 * @param {Array} array
 * @param {Array} indexes
 * @returns {Array}
 */
function getByIndexes(array, indexes) {
  let i;
  const len = indexes.length;
  const data = [];

  for (i = 0; i < len; i += 1) {
    data.push(array[indexes[i]]);
  }
  return data;
}

/**
 * Performs the rotation for an unlimited (regular) rotation
 * @param {Array} arr
 * @param {Object} result
 * @returns {Object}
 */
function arrayRotateUnlimited(arr, result) {
  return arr.reduce((res, obj, i) => Object.entries(obj).reduce((acc, [key, val]) => {
    if (acc[key] === undefined) {
      acc[key] = [];
    }
    acc[key][i] = val;
    return acc;
  }, res), result);
}

/**
 * Performs the rotation for a limited (partial) rotation
 * @param {Array} arr
 * @param {Object} result
 * @param {Array|boolean} limited
 * @returns {Object}
 */
function arrayRotateLimited(arr, result, limited) {
  // If this is limited to the list of keys, get the keys for limited rotate
  // One pass to eliminate any unusable keys and create missing arrays
  const objKeys = (isArray(limited) ? limited : Object.keys(result)).filter((key) => {
    // Create arrays for missing keys
    if (undefined === result[key]) {
      result[key] = [];
      return true;
    }

    // Check if existing keys are arrays
    return isArray(result[key]);
  });

  arr.forEach((obj, i) => objKeys.reduce((acc, att) => {
    acc[att][i] = obj[att];
    return acc;
  }, result));

  return result;
}

/**
 * Rotate an array of row-data into a column-data object
 * @param {Array} arr
 * @param {Object} [result] Result object to use
 * @param {boolean} [limited] Only update keys on the result object; a limited rotation
 * @returns {Object}
 */
function arrayRotate(arr, result, limited = false) {
  const data = result || {};

  // Not an array? Send it back.
  if (!isArray(arr)) {
    throw new TypeError('RC: Argument is not an array');
  }

  if (limited && (typeof result !== 'object' || result === undefined)) {
    throw new TypeError("RC: Must pass a result object when 'limited' is true");
  }

  // Explicit check: you could pass [0], limited could be falsy.
  if (limited) {
    return arrayRotateLimited(arr, data, limited);
  }

  return arrayRotateUnlimited(arr, data);
}

/**
 *
 * @param obj
 * @param field
 * @param filter
 * @returns {Array}
 */
function filterIndexes(obj, field, filter) {
  let indexes = [];

  if (has(obj, field)) {
    indexes = getIndexes(obj[field], filter);
  }

  return indexes;
}

/**
 * Filters all properties in a column-data object using an array of indexes.
 * @param {Object} obj
 * @param {Array} indexes
 * @returns {Object}
 */
function filterMerge(obj, indexes) {
  // Don't waste time if there are no indexes to merge.
  if (indexes === undefined || !indexes.length) {
    return {};
  }

  return Object.entries(obj).reduce((acc, [key, val]) => {
    acc[key] = getByIndexes(val, indexes);
    return acc;
  }, {});
}

/**
 * Filter a column-data object for a particular field.
 * @param {Object} obj
 * @param {String} field
 * @param {Function|String} filter
 * @returns {*}
 */
function objectFilter(obj, field, filter) {
  return filterMerge(obj, filterIndexes(obj, field, filter));
}

/**
 * Finds the longest length of any property in a column-data object.
 * @param {Object} obj
 * @returns {number}
 */
function objectLength(obj) {
  return Math.max(0, ...Object.values(obj).map(arr => arr.length));
}

/**
 * Error throwing for object rotate
 * @param {Object} obj
 * @param result
 */
function objectRotateErrors(obj, result) {
  // Not an array? Send it back.
  if (typeof obj !== 'object') {
    throw new TypeError('RC: Argument is not an object');
  }

  // If a result is passed and isn't an array, send it back.
  if (undefined !== result && !isArray(result)) {
    throw new TypeError('RC: Result argument is not an array');
  }
}

/**
 * Create an object from the specified column index
 * @param {Object} obj
 * @param {number} index
 * @param {Boolean} [clearUndef]
 * @param {Object} [result]
 * @returns {*}
 */
function objFromIndex(obj, index, clearUndef, result = {}) {
  return Object.entries(obj).reduce((acc, [key, val]) => {
    if (!clearUndef || val[index] !== undefined) {
      acc[key] = val[index];
    }
    return acc;
  }, result);
}

/**
 * Rotates column-data to row-data and optionally adds it to an existing array.
 * @param {Object} obj
 * @param {Array} [result] Optional array init which we should place rotated data.
 * @param {Boolean} [clearUndef]
 * @returns {Array}
 */
function objectRotate(obj, result, clearUndef) {
  // Call out for errors
  objectRotateErrors(obj, result);

  // Don't replace parameters to avoid optimization issues.
  const output = result || [];

  // Get the existing result array length
  const resultOffset = output.length;

  const len = objectLength(obj);

  for (let i = 0; i < len; i += 1) {
    output[i + resultOffset] = objFromIndex(obj, i, clearUndef);
  }

  return output;
}

/**
 * A generic rotate function that accepts row or column data to rotate.
 * @param {Object|Array} obj
 * @param {...*} [args]
 * @returns {Array|Object}
 */
function rotate(obj, ...args) {
  // Generic, which directs to the appropriate array/object rotate
  if (typeof obj !== 'object') throw new TypeError('RC: rotate requires an object or an array');

  if (isArray(obj)) {
    return arrayRotate(obj, ...args);
  }
  return objectRotate(obj, ...args);
}

/**
 * Increment over column-data like it was array data, making a "read-only" object for each index.
 * Does not prevent modification of values with complex data types (objects, arrays).
 * @param {Object} obj
 * @param {Function} fn
 */
function readEach(obj, fn) {
  const len = objectLength(obj);

  for (let i = 0; i < len; i += 1) {
    fn(objFromIndex(obj, i));
  }
}

/**
 * Create an object and add a .commit() prototype to place the values back into the original.
 * Useful for moving simple data types around. Objects and arrays will be automatically referenced.
 * @constructor
 * @param {Object} obj - A columnar object
 * @param {number} index - The index to convert into a row-based object
 * @param {Boolean} [clearUndef] - Clear undefined attributes when copying the object.
 * @example
 * var proxyRow = new RowcolProxy(colData, index);
 */
const RCProxy = (function () {
  // TODO - swap out for ES6 proxy object
  const proxyObj = [];
  const proxyIdx = [];
  const proxyClearFlag = [];
  const proxyThis = [];
  let guid = 0;

  /**
   * Uses a private array to locate the same object,
   * so the proxy doesn't expose itself to modification.
   * We compare the passed object against an array of existing RowcolProxy objects;
   * basically pointer comparison.
   * @param {RowcolProxy} proxy
   * @returns {number} The proxy ID to allow commit and destroy to locate the correct element
   * @private
   */
  function proxyGetId(proxy) {
    let pid;

    // Most likely to be at the end, so start there
    for (let i = proxyThis.length; i;) {
      i -= 1;
      if (proxyThis[i] === proxy) {
        pid = i;
        break;
      }
    }

    if (pid === undefined) {
      throw new ReferenceError('Proxy is finalized and cannot be used again.');
    }
    return pid;
  }

  /**
   * The actual RowcolProxy constructor.
   * @param {Object} obj
   * @param {number} index
   * @param {Boolean} [clearUndef]
   * @constructor
   */
  function RowcolProxy(obj, index, clearUndef) {
    // Increment the guid
    guid += 1;

    // Set the private data.
    proxyObj[guid] = obj;
    proxyIdx[guid] = index;
    proxyClearFlag[guid] = clearUndef;
    proxyThis[guid] = this;

    // Call reusable code for objFromIndex
    objFromIndex(obj, index, clearUndef, this);
  }

  // Defined inside the constructor to give it access to the originating object and parameters

  /**
   * Commits the changes from the proxy to the original.
   */
  RowcolProxy.prototype.commit = function () {
    const pid = proxyGetId(this);
    const obj = proxyObj[pid];
    const index = proxyIdx[pid];
    const clearUndef = proxyClearFlag[pid];

    Object.entries(this).reduce((acc, [key, val]) => {
      if (key === '__rcProxyId') {
        return acc;
      }
      if (!clearUndef || val !== undefined) {
        acc[key][index] = val;
      }
      return acc;
    }, obj);
  };

  /**
   * Removes the proxy to prevent memory leaks
   */
  RowcolProxy.prototype.destroy = function () {
    const pid = proxyGetId(this);
    delete proxyThis[pid];
    delete proxyObj[pid];
    delete proxyIdx[pid];
    delete proxyClearFlag[pid];
  };

  /**
   * Commit and destroy the proxy, as a single step
   */
  RowcolProxy.prototype.finalize = function () {
    this.commit();
    this.destroy();
  };

  return RowcolProxy;
}());

/**
 * Create a proxy
 * @param obj
 * @param index
 * @param clearUndef
 */
function proxyFromIndex(obj, index, clearUndef) {
  return new RCProxy(obj, index, clearUndef);
}

/**
 * Increment over column-data like it was array data, making a proxy object for each index.
 * @param {Object} obj
 * @param {Function} fn
 */
function objEach(obj, fn) {
  const len = objectLength(obj);
  let i = 0;
  let prox;

  for (; i < len; i += 1) {
    prox = new RCProxy(obj, i);

    fn(prox, i);

    prox.finalize();
  }
}

/*--------------------------------------------------------------------------*/

const rowcol = {
  rotate,
  proxy: proxyFromIndex,
  array: {
    getIndexes,
    getByIndexes,
    rotate: arrayRotate,
  },
  object: {
    filter: objectFilter,
    filterIndexes,
    filterMerge,
    rotate: objectRotate,
    objFromIndex,
    proxy: proxyFromIndex,
    readEach,
    each: objEach,
    objLength: objectLength,
  },
  VERSION: version,
  test: {
    isArray,
  },
};

/*--------------------------------------------------------------------------*/

module.exports = rowcol;
<|endoftext|>


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

import '@/assets/css/base.scss';
import moment from 'moment';
import axios from '@/utils/axios';
import 'moment/locale/de';
import Vue from 'vue';
import VueRouter from 'vue-router';
import components from './components';
import Notifications from './notifications';
import sbaConfig from './sba-config'
import sbaShell from './shell';
import Store from './store';
import ViewRegistry from './viewRegistry';
import views from './views';
import i18n from './i18n';

moment.locale(navigator.language.split('-')[0]);
Vue.use(VueRouter);
Vue.use(components);

const applicationStore = new Store();
const viewRegistry = new ViewRegistry();

const installables = [
  Notifications,
  ...views,
  ...sbaConfig.extensions
];

installables.forEach(view => view.install({
  viewRegistry,
  applicationStore,
  vue: Vue,
  axios
}));

const routesKnownToBackend = sbaConfig.uiSettings.routes.map(r => new RegExp(`^${r.replace('/**', '(/.*)?')}$`));
const unknownRoutes = viewRegistry.routes.filter(vr => vr.path !== '/' && !routesKnownToBackend.some(br => br.test(vr.path)));
if (unknownRoutes.length > 0) {
  console.warn(`The routes ${JSON.stringify(unknownRoutes.map(r => r.path))} aren't known to the backend and may be not properly routed!`)
}

new Vue({
  i18n,
  router: new VueRouter({
    mode: 'history',
    linkActiveClass: 'is-active',
    routes: viewRegistry.routes
  }),
  el: '#app',
  render(h) {
    return h(sbaShell, {
      props: {
        views: this.views,
        applications: this.applications,
        applicationsInitialized: this.applicationsInitialized,
        error: this.error
      }
    });
  },
  data: {
    views: viewRegistry.views,
    applications: applicationStore.applications,
    applicationsInitialized: false,
    error: null
  },
  methods: {
    onError(error) {
      console.warn('Connection to server failed:', error);
      this.applicationsInitialized = true;
      this.error = error;
    },
    onConnected() {
      this.applicationsInitialized = true;
      this.error = null;
    }
  },
  created() {
    applicationStore.addEventListener('connected', this.onConnected);
    applicationStore.addEventListener('error', this.onError);
    applicationStore.start();
  },
  beforeDestroy() {
    applicationStore.stop();
    applicationStore.removeEventListener('connected', this.onConnected);
    applicationStore.removeEventListener('error', this.onError)
  }
});
<commit_msg>Make the VueI18n instance available for custom views<commit_after>/*
 * Copyright 2014-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import '@/assets/css/base.scss';
import axios from '@/utils/axios';
import moment from 'moment';
import 'moment/locale/de';
import Vue from 'vue';
import VueRouter from 'vue-router';
import components from './components';
import i18n from './i18n';
import Notifications from './notifications';
import sbaConfig from './sba-config'
import sbaShell from './shell';
import Store from './store';
import ViewRegistry from './viewRegistry';
import views from './views';

moment.locale(navigator.language.split('-')[0]);
Vue.use(VueRouter);
Vue.use(components);

const applicationStore = new Store();
const viewRegistry = new ViewRegistry();

const installables = [
  Notifications,
  ...views,
  ...sbaConfig.extensions
];

installables.forEach(view => view.install({
  viewRegistry,
  applicationStore,
  vue: Vue,
  vueI18n: i18n,
  axios
}));

const routesKnownToBackend = sbaConfig.uiSettings.routes.map(r => new RegExp(`^${r.replace('/**', '(/.*)?')}$`));
const unknownRoutes = viewRegistry.routes.filter(vr => vr.path !== '/' && !routesKnownToBackend.some(br => br.test(vr.path)));
if (unknownRoutes.length > 0) {
  console.warn(`The routes ${JSON.stringify(unknownRoutes.map(r => r.path))} aren't known to the backend and may be not properly routed!`)
}

new Vue({
  i18n,
  router: new VueRouter({
    mode: 'history',
    linkActiveClass: 'is-active',
    routes: viewRegistry.routes
  }),
  el: '#app',
  render(h) {
    return h(sbaShell, {
      props: {
        views: this.views,
        applications: this.applications,
        applicationsInitialized: this.applicationsInitialized,
        error: this.error
      }
    });
  },
  data: {
    views: viewRegistry.views,
    applications: applicationStore.applications,
    applicationsInitialized: false,
    error: null
  },
  methods: {
    onError(error) {
      console.warn('Connection to server failed:', error);
      this.applicationsInitialized = true;
      this.error = error;
    },
    onConnected() {
      this.applicationsInitialized = true;
      this.error = null;
    }
  },
  created() {
    applicationStore.addEventListener('connected', this.onConnected);
    applicationStore.addEventListener('error', this.onError);
    applicationStore.start();
  },
  beforeDestroy() {
    applicationStore.stop();
    applicationStore.removeEventListener('connected', this.onConnected);
    applicationStore.removeEventListener('error', this.onError)
  }
});
<|endoftext|>


<commit_before>#!/usr/bin/env node
var q = require('q'),
    _ = require('lodash'),
    util = require('util'),
    utils = require('./utils'),
    driver = utils.getDriver(),
    C = driver.constants;

function runUser(userId, onlyInRoom) {

    driver.config.emit('runnerLoopStage','runUser', userId, onlyInRoom);

    //driver.influxAccumulator.resetTime();

    return driver.makeRuntime(userId, onlyInRoom)
        .then(saveResult, saveResult);

    function saveResult(runResult) {

        driver.config.emit('runnerLoopStage','saveResultStart', runResult);

        //driver.influxAccumulator.mark('endMakeRuntime');
        if(runResult.console) {
            driver.sendConsoleMessages(userId, runResult.console);
        }
        if(runResult.error) {
            driver.sendConsoleError(userId, runResult.error);
        }

        //driver.resetUserRoomVisibility(userId);

        var promises = [];
        if(runResult.memory) {
            promises.push(driver.saveUserMemory(userId, runResult.memory, onlyInRoom));
        }
        if(runResult.memorySegments) {
            promises.push(driver.saveUserMemorySegments(userId, runResult.memorySegments));
        }
        if(runResult.interShardSegment) {
            promises.push(driver.saveUserMemoryInterShardSegment(userId, runResult.interShardSegment));
        }
        if(runResult.intents) {
            promises.push(driver.saveUserIntents(userId, runResult.intents));
        }
        return q.all(promises)
        .then(() => {
            driver.config.emit('runnerLoopStage','saveResultFinish', runResult);
            //driver.influxAccumulator.mark('saveUser');
        })
    }
}

driver.connect('runner')
.then(() => driver.queue.create('users', 'read'))
.then(_usersQueue => {

    var usersQueue = _usersQueue;

    driver.startLoop('runner', function() {
        var userId, fetchedUserId;

        driver.config.emit('runnerLoopStage','start');

        return usersQueue.fetch()
            .then((_userId) => {
                userId = fetchedUserId = _userId;
                var onlyInRoom;
                var m = userId.match(/^Invader:(.*)$/);
                if(m) {
                    userId = '2';
                    onlyInRoom = m[1];
                }

                return runUser(userId, onlyInRoom);
            })
            .catch((error) => console.error('Error in runner loop:', _.isObject(error) && error.stack || error))
            .then(() => usersQueue.markDone(fetchedUserId))
            .finally(() => driver.config.emit('runnerLoopStage','finish', userId));
    });

}).catch((error) => {
    console.log('Error connecting to driver:', error);
});

if(typeof self == 'undefined') {
    setInterval(() => {
        var rejections = q.getUnhandledReasons();
        rejections.forEach((i) => console.error('Unhandled rejection:', i));
        q.resetUnhandledRejections();
    }, 1000);
}

<commit_msg>refact(runner): remove `onlyInRoom` selector since we don't have "invader" runtime users anymore<commit_after>#!/usr/bin/env node
var q = require('q'),
    _ = require('lodash'),
    util = require('util'),
    utils = require('./utils'),
    driver = utils.getDriver(),
    C = driver.constants;

function runUser(userId) {

    driver.config.emit('runnerLoopStage','runUser', userId);

    //driver.influxAccumulator.resetTime();

    return driver.makeRuntime(userId)
        .then(saveResult, saveResult);

    function saveResult(runResult) {

        driver.config.emit('runnerLoopStage','saveResultStart', runResult);

        //driver.influxAccumulator.mark('endMakeRuntime');
        if(runResult.console) {
            driver.sendConsoleMessages(userId, runResult.console);
        }
        if(runResult.error) {
            driver.sendConsoleError(userId, runResult.error);
        }

        //driver.resetUserRoomVisibility(userId);

        var promises = [];
        if(runResult.memory) {
            promises.push(driver.saveUserMemory(userId, runResult.memory));
        }
        if(runResult.memorySegments) {
            promises.push(driver.saveUserMemorySegments(userId, runResult.memorySegments));
        }
        if(runResult.interShardSegment) {
            promises.push(driver.saveUserMemoryInterShardSegment(userId, runResult.interShardSegment));
        }
        if(runResult.intents) {
            promises.push(driver.saveUserIntents(userId, runResult.intents));
        }
        return q.all(promises)
        .then(() => {
            driver.config.emit('runnerLoopStage','saveResultFinish', runResult);
            //driver.influxAccumulator.mark('saveUser');
        })
    }
}

driver.connect('runner')
.then(() => driver.queue.create('users', 'read'))
.then(_usersQueue => {

    var usersQueue = _usersQueue;

    driver.startLoop('runner', function() {
        var userId, fetchedUserId;

        driver.config.emit('runnerLoopStage','start');

        return usersQueue.fetch()
            .then((_userId) => {
                userId = fetchedUserId = _userId;
                return runUser(userId);
            })
            .catch((error) => console.error('Error in runner loop:', _.isObject(error) && error.stack || error))
            .then(() => usersQueue.markDone(fetchedUserId))
            .finally(() => driver.config.emit('runnerLoopStage','finish', userId));
    });

}).catch((error) => {
    console.log('Error connecting to driver:', error);
});

if(typeof self == 'undefined') {
    setInterval(() => {
        var rejections = q.getUnhandledReasons();
        rejections.forEach((i) => console.error('Unhandled rejection:', i));
        q.resetUnhandledRejections();
    }, 1000);
}

<|endoftext|>


<commit_before>// ==UserScript==
// @name        ShoutBox
// @namespace   Elitepvpers
// @description SB
// @include     *//www.elitepvpers.com/forum/*
// @author      Syc
// @downloadURL https://github.com/epvpsyc/SycBox/raw/master/SycBox.user.js
// @grant       none
// ==/UserScript==
(function ($)
{
    var chat_history = [];

    initSB(updateChatHistory());

    function updateChatHistory()
    {
        var content_table = fetch_tags(refreshAjax.handler.responseXML, 'chatbox_content');
        chatbox_content = refreshAjax.fetch_data(content_table[0]);

        $(chatbox_content).find('tr.alt2').each(function (i, tr)
        {
            var id = $(tr).find('td:first').attr('id').replace('chat_', '');
            var id_exists = false;

            $.each(chat_history, function (j, elem)
            {
                if (id in elem)
                {
                    id_exists = true;
                }
            });

            if (!id_exists)
            {
                var message = {
                    'id': id,
                    'time': $(tr).find('.mgc_cb_evo_date').text().trim(),
                    'user': {
                        'url': $(tr).find('td:nth-last-child(2) > span > a').attr('href'),
                        'name': $(tr).find('td:nth-last-child(2) > span > a > span').text(),
                        'color': $(tr).find('td:nth-last-child(2) > span > a > span').css('color'),
                    },
                    'text': $(tr).find('td').last().html().trim(),
                    'appended': false,
                };
                chat_history.push(message);
            }
        });

        return chat_history;
    }

    function initSB()
    {
        var input = $('#mgc_cb_evo_input');
        var sbWidth = $('tbody#mgc_cb_evo_opened').width();
        var sbHeight = $('tbody#mgc_cb_evo_opened').sbHeight();

        $('tbody#mgc_cb_evo_opened').parent().html('

');
        $('#shoutBoxTbody').parent().attr("id", "shoutBoxTable");

        for (var chat in chat_history.reverse())
        {
            chat_history[chat]['appended'] = true;
            chat = chat_history[chat];
            var line = '
' + chat['time'] + '	' + chat['user']['name'] + '	' + chat['text'] + '
';
            $('#shoutBoxTbody').append(line);
        };

        // $('#shoutBoxTbody').append('
<input type="text" id="mgc_cb_evo_input" name="mgc_cb_evo_input" tabindex="1">
');
        $('#shoutBoxTable').width(sbWidth + 'px');
        $('#shoutBoxTable').width(sbHeight + 'px');
    }

    function appendSB()
    {
        $.each(chat_history, function (j, chat)
        {
            if (!chat['appended'])
            {
                var line = '
' + chat['time'] + '	' + chat['user']['name'] + '	' + chat['text'] + '
';

                $('#shoutBoxTbody').append(line);
            }
        });
    }

    window.setInterval(function ()
    {
        window.clearTimeout(idleTimeout);
    }, 30000);

    window.setInterval(function ()
    {
        updateChatHistory();
    }, 5000);

    // apply css
    $("head").append($("<link rel='stylesheet' href='https://github.com/epvpsyc/SycBox/raw/master/SycBox.css' type='text/css' media='screen' />"));
})(jQuery);<commit_msg>typo fix<commit_after>// ==UserScript==
// @name        ShoutBox
// @namespace   Elitepvpers
// @description SB
// @include     *//www.elitepvpers.com/forum/*
// @author      Syc
// @downloadURL https://github.com/epvpsyc/SycBox/raw/master/SycBox.user.js
// @grant       none
// ==/UserScript==
(function ($)
{
    var chat_history = [];

    initSB(updateChatHistory());

    function updateChatHistory()
    {
        var content_table = fetch_tags(refreshAjax.handler.responseXML, 'chatbox_content');
        chatbox_content = refreshAjax.fetch_data(content_table[0]);

        $(chatbox_content).find('tr.alt2').each(function (i, tr)
        {
            var id = $(tr).find('td:first').attr('id').replace('chat_', '');
            var id_exists = false;

            $.each(chat_history, function (j, elem)
            {
                if (id in elem)
                {
                    id_exists = true;
                }
            });

            if (!id_exists)
            {
                var message = {
                    'id': id,
                    'time': $(tr).find('.mgc_cb_evo_date').text().trim(),
                    'user': {
                        'url': $(tr).find('td:nth-last-child(2) > span > a').attr('href'),
                        'name': $(tr).find('td:nth-last-child(2) > span > a > span').text(),
                        'color': $(tr).find('td:nth-last-child(2) > span > a > span').css('color'),
                    },
                    'text': $(tr).find('td').last().html().trim(),
                    'appended': false,
                };
                chat_history.push(message);
            }
        });

        return chat_history;
    }

    function initSB()
    {
        var input = $('#mgc_cb_evo_input');
        var sbWidth = $('tbody#mgc_cb_evo_opened').width();
        var sbHeight = $('tbody#mgc_cb_evo_opened').height();

        $('tbody#mgc_cb_evo_opened').parent().html('

');
        $('#shoutBoxTbody').parent().attr("id", "shoutBoxTable");

        for (var chat in chat_history.reverse())
        {
            chat_history[chat]['appended'] = true;
            chat = chat_history[chat];
            var line = '
' + chat['time'] + '	' + chat['user']['name'] + '	' + chat['text'] + '
';
            $('#shoutBoxTbody').append(line);
        };

        // $('#shoutBoxTbody').append('
<input type="text" id="mgc_cb_evo_input" name="mgc_cb_evo_input" tabindex="1">
');
        $('#shoutBoxTable').width(sbWidth + 'px');
        $('#shoutBoxTable').width(sbHeight + 'px');
    }

    function appendSB()
    {
        $.each(chat_history, function (j, chat)
        {
            if (!chat['appended'])
            {
                var line = '
' + chat['time'] + '	' + chat['user']['name'] + '	' + chat['text'] + '
';

                $('#shoutBoxTbody').append(line);
            }
        });
    }

    window.setInterval(function ()
    {
        window.clearTimeout(idleTimeout);
    }, 30000);

    window.setInterval(function ()
    {
        updateChatHistory();
    }, 5000);

    // apply css
    $("head").append($("<link rel='stylesheet' href='https://github.com/epvpsyc/SycBox/raw/master/SycBox.css' type='text/css' media='screen' />"));
})(jQuery);
<|endoftext|>


<commit_before>// Looking at a single unit...

//// Constants /////////////////////////////////////////////////////////////////

const INIT_GUESS = 0.3
const INIT_SLIP = 0.1
const INIT_LEARNED = 0.4
const MAX_LEARNED = 0.99
const INIT_TRANSIT = 0 // TODO update to estimate, 0.05?

//// Formulas //////////////////////////////////////////////////////////////////

function calcCorrect(guess, slip, learned) {
  return learned * (1 - slip) + (1 - learned) * guess
}

function calcIncorrect(guess, slip, learned) {
  return learned * slip + (1 - learned) * (1 - guess)
}

function updateLearned({ score, learned, guess, slip, transit }) {
  const posterior =
    score
      * calcCorrect(0, slip, learned)
      / calcCorrect(guess, slip, learned)
    + (1 - score)
      * calcIncorrect(0, slip, learned)
      / calcIncorrect(guess, slip, learned)
  return posterior + (1 - posterior) * transit
}

function sum (arr) {
  return arr.reduce((sum, val) => sum + val, 0)
}

function mean (arr) {
  return sum(arr) / arr.length
}

function error (cards, param, realParam) {
  return mean(cards.map(card => (card[param] - card[realParam]) ** 2))
}

function control (cards, realParam, init) {
  return mean(cards.map(card => (init - card[realParam]) ** 2))
}

function around(value) {
  return value + Math.random() * value - 0.5 * value
}

function choose(arr) {
  return arr[Math.floor(Math.random() * arr.length)]
}

//// Mock //////////////////////////////////////////////////////////////////////

function createCards(numCards = 20) {
  return [...Array(numCards).keys()]
    .map(i => ({
      name: i,
      realGuess: around(INIT_GUESS),
      guess: INIT_GUESS,
      realSlip: around(INIT_SLIP),
      slip: INIT_SLIP,
      realTransit: INIT_TRANSIT, // TODO around(INIT_TRANSIT)
      transit: INIT_TRANSIT,
      responses: [],
    }))
}

function createLearners(numLearners = 1000) {
  return [...Array(numLearners).keys()]
    .map(i => ({ name: i, learned: INIT_LEARNED }))
}

//// Simluate //////////////////////////////////////////////////////////////////

function getScore(learner, card) {
  const correct = calcCorrect(
    card.realGuess,
    card.realSlip,
    learner.learned
  )
  return +(correct > Math.random())
}

function updateLearner(learner, params) {
  learner.learned = updateLearned(params)
}

function updateCard(card, params) {
  // THIS IS WHERE THE EXPERIMENT OCCURS!!!
  // card.guess = ???
  // card.slip = ???
  // card.transit = ???

  function calcGuess({ score, learned }) {
    return (score * 0.5 + 0.5) * (1 - learned)
  }

  function calcSlip({ score, learned }) {
    return (1 - (score * 0.5 + 0.5)) * learned
  }

  function smoothed (init, sum, count, C = 30) {
    return (C * init + sum) / (C + params.count)
  }

  card.guess = smoothed(INIT_GUESS, sum(card.responses.map(calcGuess)), params.count)
  card.slip = smoothed(INIT_SLIP, sum(card.responses.map(calcSlip)), params.count)
}

function simulate(numCards, numLearners, rounds = 5000) {
  const cards = createCards(numCards)
  const learners = createLearners(numLearners)

  for (let i = 0; i < rounds; i++) {
    const card = choose(cards)
    const learner = choose(learners)

    if (learner.learned > MAX_LEARNED) continue

    const score = getScore(learner, card)
    const params = {
      score,
      learned: learner.learned,
      guess: card.guess,
      slip: card.slip,
      transit: card.transit,
      count: card.responses.length,
    }

    card.responses.push(params)

    // Update learner
    updateLearner(learner, params)

    // Update card
    updateCard(card, params)

    // console.log(i, learner, card)
  }

  // console.log('mean responses per card', mean(cards.map(({responses}) => responses.length)))

  return { cards, learners }
}

//// Result ////////////////////////////////////////////////////////////////////

if (require.main === module) {
  // The goal is to beat `1`.

  const { cards, learners } = simulate(160, 8000, 40000)

  const guessPerf =
    error(cards, 'guess', 'realGuess')
    / control(cards, 'realGuess', INIT_GUESS)

  const slipPerf =
    error(cards, 'slip', 'realSlip')
    / control(cards, 'realSlip', INIT_SLIP)

  console.log(
    'mean responses per card',
    mean(cards.map(({responses}) => responses.length))
  )

  console.log(
    (guessPerf + slipPerf) / 2,
    mean(cards.map(({guess}) => guess)),
    mean(cards.map(({slip}) => slip)),
  )
}

/*

  () => INIT_GUESS,
  () => INIT_SLIP,
  () => INIT_TRANSIT,
  () => 0,
  () => 1,
  ({ learned }) => learned,
  ({ learned }) => 1 - learned,
  ({ learned }) => 1 + learned,
  ({ learned }) => 1 / learned,
  ({ learned }) => 1 / (1 - learned),
  ({ learned }) => 1 / (1 + learned),
  ({ learned }) => learned / (1 - learned),
  ({ learned }) => learned / (1 + learned),
  ({ learned }) => (1 - learned) / learned,
  ({ learned }) => (1 - learned) / (1 + learned),
  ({ learned }) => (1 + learned) / learned,
  ({ learned }) => (1 + learned) / (1 - learned),
  ({ learned, guess, slip }) => calcCorrect(guess, slip, learned),
  ({ learned, guess, slip }) => calcIncorrect(guess, slip, learned),
  ({ learned, guess, slip }) => calcCorrect(0, slip, learned),
  ({ learned, guess, slip }) => calcIncorrect(0, slip, learned),
  ({ learned, guess, slip }) => calcCorrect(1, slip, learned),
  ({ learned, guess, slip }) => calcIncorrect(1, slip, learned),
  ({ learned, guess, slip }) => calcCorrect(guess, 0, learned),
  ({ learned, guess, slip }) => calcIncorrect(guess, 0, learned),
  ({ learned, guess, slip }) => calcCorrect(guess, 1, learned),
  ({ learned, guess, slip }) => calcIncorrect(guess, 1, learned),
  ({ learned, guess, slip }) => calcCorrect(guess, slip, 0),
  ({ learned, guess, slip }) => calcIncorrect(guess, slip, 0),
  ({ learned, guess, slip }) => calcCorrect(guess, slip, 1),
  ({ learned, guess, slip }) => calcIncorrect(guess, slip, 1),
  ({ learned, guess, slip }) => calcCorrect(0, 0, learned),
  ({ learned, guess, slip }) => calcIncorrect(0, 0, learned),
  ({ learned, guess, slip }) => calcCorrect(1, 1, learned),
  ({ learned, guess, slip }) => calcIncorrect(1, 1, learned),
  ({ learned, guess, slip }) => calcCorrect(0, 1, learned),
  ({ learned, guess, slip }) => calcIncorrect(0, 1, learned),
  ({ learned, guess, slip }) => calcCorrect(1, 0, learned),
  ({ learned, guess, slip }) => calcIncorrect(1, 0, learned),
  ({ learned, guess, slip }) => calcCorrect(0, slip, 0),
  ({ learned, guess, slip }) => calcIncorrect(0, slip, 0),
  ({ learned, guess, slip }) => calcCorrect(1, slip, 1),
  ({ learned, guess, slip }) => calcIncorrect(1, slip, 1),
  ({ learned, guess, slip }) => calcCorrect(0, slip, 1),
  ({ learned, guess, slip }) => calcIncorrect(0, slip, 1),
  ({ learned, guess, slip }) => calcCorrect(1, slip, 0),
  ({ learned, guess, slip }) => calcIncorrect(1, slip, 0),
  ({ learned, guess, slip }) => calcCorrect(guess, 0, 0),
  ({ learned, guess, slip }) => calcIncorrect(guess, 0, 0),
  ({ learned, guess, slip }) => calcCorrect(guess, 1, 1),
  ({ learned, guess, slip }) => calcIncorrect(guess, 1, 1),
  ({ learned, guess, slip }) => calcCorrect(guess, 1, 0),
  ({ learned, guess, slip }) => calcIncorrect(guess, 1, 0),
  ({ learned, guess, slip }) => calcCorrect(guess, 0, 1),
  ({ learned, guess, slip }) => calcIncorrect(guess, 0, 1),

  const totalOptions = values.length ** 6
  let option = 0

  const opt1 = []
  const opt2 = []
  const opt3 = []

  for (let a = 0; a < values.length; a++) {
    for (let b = 0; b < values.length; b++) {
      for (let c = 0; c < values.length; c++) {
        for (let d = 0; d < values.length; d++) {
          for (let e = 0; e < values.length; e++) {
            for (let f = 0; f < values.length; f++) {

  const path = [f, e, d, c, b, a]
  const { cards, learners } = simulate(20000, path)

  const foundCount = (guessPerf < 0.99) + (slipPerf < 0.99) + (transitPerf < 0.99)
  if (foundCount > 0) {
    const data = { path, guessPerf, slipPerf, transitPerf }
    if (foundCount === 1) opt1.push(data)
    if (foundCount === 2) opt2.push(data)
    if (foundCount === 3) opt3.push(data)
  }

  option++

  process.stdout.clearLine()
  process.stdout.cursorTo(0)
  process.stdout.write(`${option} of ${totalOptions}, found ${opt1.length} ${opt2.length} ${opt3.length} ... ${path.map(p => (''+p).padStart(2)).join(' ')}`)

            }
          }
        }
      }
    }
  }

*/
<commit_msg>Update simulation.js<commit_after>// Looking at a single unit...

//// Constants /////////////////////////////////////////////////////////////////

const INIT_GUESS = 0.3
const INIT_SLIP = 0.1
const INIT_LEARNED = 0.4
const MAX_LEARNED = 0.99
const INIT_TRANSIT = 0 // TODO update to estimate, 0.05?

//// Formulas //////////////////////////////////////////////////////////////////

function calcCorrect(guess, slip, learned) {
  return learned * (1 - slip) + (1 - learned) * guess
}

function calcIncorrect(guess, slip, learned) {
  return learned * slip + (1 - learned) * (1 - guess)
}

function updateLearned({ score, learned, guess, slip, transit }) {
  const posterior =
    (score * calcCorrect(0, slip, learned)) /
      calcCorrect(guess, slip, learned) +
    ((1 - score) * calcIncorrect(0, slip, learned)) /
      calcIncorrect(guess, slip, learned)
  return posterior + (1 - posterior) * transit
}

function sum(arr) {
  return arr.reduce((sum, val) => sum + val, 0)
}

function mean(arr) {
  return sum(arr) / arr.length
}

function error(arr1, arr2) {
  return mean(
    [...Array(arr1.length).keys()].map(i => (arr1[i] - arr2[i]) ** 2)
  )
}

function correlation(arr1, arr2) {
  const sum1 = sum(arr1)
  const sum2 = sum(arr2)
  return error(arr1.map(a => a / sum1), arr2.map(a => a / sum2))
}

function around(value) {
  return value + Math.random() * value - 0.5 * value
}

function choose(arr) {
  return arr[Math.floor(Math.random() * arr.length)]
}

//// Mock //////////////////////////////////////////////////////////////////////

function createCards(numCards = 20) {
  return [...Array(numCards).keys()].map(i => ({
    name: i,
    realGuess: around(INIT_GUESS),
    guess: INIT_GUESS,
    realSlip: around(INIT_SLIP),
    slip: INIT_SLIP,
    realTransit: INIT_TRANSIT, // TODO around(INIT_TRANSIT)
    transit: INIT_TRANSIT,
    responses: [],
  }))
}

function createLearners(numLearners = 1000) {
  return [...Array(numLearners).keys()].map(i => ({
    name: i,
    learned: INIT_LEARNED,
  }))
}

//// Simluate //////////////////////////////////////////////////////////////////

function getScore(learner, card) {
  const correct = calcCorrect(card.realGuess, card.realSlip, learner.learned)
  return +(correct > Math.random())
}

function updateLearner(learner, params) {
  learner.learned = updateLearned(params)
}

function updateCard(card, params) {
  // THIS IS WHERE THE EXPERIMENT OCCURS!!!
  // card.guess = ???
  // card.slip = ???
  // card.transit = ???

  function calcGuess({ score, guess, slip, learned }) {
    return (score * 0.5 + 0.5) * (1 - learned)
  }

  function calcSlip({ score, guess, slip, learned }) {
    return (1 - (score * 0.5 + 0.5)) * learned
  }

  function smoothed(init, sum, count, C = 30) {
    return (C * init + sum) / (C + params.count + 1)
  }

  card.guess = smoothed(
    INIT_GUESS,
    sum(card.responses.map(calcGuess)),
    params.count
  )
  card.slip = smoothed(
    INIT_SLIP,
    sum(card.responses.map(calcSlip)),
    params.count
  )
}

function simulate(numCards, numLearners, rounds = 5000) {
  const cards = createCards(numCards)
  const learners = createLearners(numLearners)

  for (let i = 0; i < rounds; i++) {
    const card = choose(cards)
    const learner = choose(learners)
    if (learner.learned > MAX_LEARNED) continue
    const score = getScore(learner, card)
    const params = {
      score,
      learned: learner.learned,
      guess: card.guess,
      slip: card.slip,
      transit: card.transit,
      count: card.responses.length,
    }
    card.responses.push(params)
    updateLearner(learner, params)
    updateCard(card, params)
  }

  return { cards, learners }
}

//// Result ////////////////////////////////////////////////////////////////////

function results(cards, learners) {
  const meanResponses = mean(cards.map(({ responses }) => responses.length))
  const meanGuess = mean(cards.map(({ guess }) => guess))
  const guessPerf =
    error(
      cards.map(({ guess }) => guess),
      cards.map(({ realGuess }) => realGuess)
    ) /
    error(cards.map(({ realGuess }) => realGuess), cards.map(() => INIT_GUESS))
  const guessCorr =
    correlation(
      cards.map(({ guess }) => guess),
      cards.map(({ realGuess }) => realGuess)
    ) /
    correlation(
      cards.map(({ realGuess }) => realGuess),
      cards.map(() => INIT_GUESS)
    )
  const meanSlip = mean(cards.map(({ slip }) => slip))
  const slipPerf =
    error(
      cards.map(({ slip }) => slip),
      cards.map(({ realSlip }) => realSlip)
    ) /
    error(cards.map(({ realSlip }) => realSlip), cards.map(() => INIT_SLIP))
  const slipCorr =
    correlation(
      cards.map(({ slip }) => slip),
      cards.map(({ realSlip }) => realSlip)
    ) /
    correlation(
      cards.map(({ realSlip }) => realSlip),
      cards.map(() => INIT_SLIP)
    )
  return {
    meanResponses,
    meanGuess,
    guessPerf,
    guessCorr,
    meanSlip,
    slipPerf,
    slipCorr,
  }
}

//// Run ///////////////////////////////////////////////////////////////////////

if (require.main === module) {
  // The goal is to beat `1`.
  const { cards, learners } = simulate(160, 8000, 40000)
  console.log(results(cards, learners))
}

/*
  () => INIT_GUESS,
  () => INIT_SLIP,
  () => INIT_TRANSIT,
  () => 0,
  () => 1,
  ({ learned }) => learned,
  ({ learned }) => 1 - learned,
  ({ learned }) => 1 + learned,
  ({ learned }) => 1 / learned,
  ({ learned }) => 1 / (1 - learned),
  ({ learned }) => 1 / (1 + learned),
  ({ learned }) => learned / (1 - learned),
  ({ learned }) => learned / (1 + learned),
  ({ learned }) => (1 - learned) / learned,
  ({ learned }) => (1 - learned) / (1 + learned),
  ({ learned }) => (1 + learned) / learned,
  ({ learned }) => (1 + learned) / (1 - learned),
  ({ learned, guess, slip }) => calcCorrect(guess, slip, learned),
  ({ learned, guess, slip }) => calcIncorrect(guess, slip, learned),
  ({ learned, guess, slip }) => calcCorrect(0, slip, learned),
  ({ learned, guess, slip }) => calcIncorrect(0, slip, learned),
  ({ learned, guess, slip }) => calcCorrect(1, slip, learned),
  ({ learned, guess, slip }) => calcIncorrect(1, slip, learned),
  ({ learned, guess, slip }) => calcCorrect(guess, 0, learned),
  ({ learned, guess, slip }) => calcIncorrect(guess, 0, learned),
  ({ learned, guess, slip }) => calcCorrect(guess, 1, learned),
  ({ learned, guess, slip }) => calcIncorrect(guess, 1, learned),
  ({ learned, guess, slip }) => calcCorrect(guess, slip, 0),
  ({ learned, guess, slip }) => calcIncorrect(guess, slip, 0),
  ({ learned, guess, slip }) => calcCorrect(guess, slip, 1),
  ({ learned, guess, slip }) => calcIncorrect(guess, slip, 1),
  ({ learned, guess, slip }) => calcCorrect(0, 0, learned),
  ({ learned, guess, slip }) => calcIncorrect(0, 0, learned),
  ({ learned, guess, slip }) => calcCorrect(1, 1, learned),
  ({ learned, guess, slip }) => calcIncorrect(1, 1, learned),
  ({ learned, guess, slip }) => calcCorrect(0, 1, learned),
  ({ learned, guess, slip }) => calcIncorrect(0, 1, learned),
  ({ learned, guess, slip }) => calcCorrect(1, 0, learned),
  ({ learned, guess, slip }) => calcIncorrect(1, 0, learned),
  ({ learned, guess, slip }) => calcCorrect(0, slip, 0),
  ({ learned, guess, slip }) => calcIncorrect(0, slip, 0),
  ({ learned, guess, slip }) => calcCorrect(1, slip, 1),
  ({ learned, guess, slip }) => calcIncorrect(1, slip, 1),
  ({ learned, guess, slip }) => calcCorrect(0, slip, 1),
  ({ learned, guess, slip }) => calcIncorrect(0, slip, 1),
  ({ learned, guess, slip }) => calcCorrect(1, slip, 0),
  ({ learned, guess, slip }) => calcIncorrect(1, slip, 0),
  ({ learned, guess, slip }) => calcCorrect(guess, 0, 0),
  ({ learned, guess, slip }) => calcIncorrect(guess, 0, 0),
  ({ learned, guess, slip }) => calcCorrect(guess, 1, 1),
  ({ learned, guess, slip }) => calcIncorrect(guess, 1, 1),
  ({ learned, guess, slip }) => calcCorrect(guess, 1, 0),
  ({ learned, guess, slip }) => calcIncorrect(guess, 1, 0),
  ({ learned, guess, slip }) => calcCorrect(guess, 0, 1),
  ({ learned, guess, slip }) => calcIncorrect(guess, 0, 1),

  const totalOptions = values.length ** 6
  let option = 0

  const opt1 = []
  const opt2 = []
  const opt3 = []

  for (let a = 0; a < values.length; a++) {
    for (let b = 0; b < values.length; b++) {
      for (let c = 0; c < values.length; c++) {
        for (let d = 0; d < values.length; d++) {
          for (let e = 0; e < values.length; e++) {
            for (let f = 0; f < values.length; f++) {

  const path = [f, e, d, c, b, a]
  const { cards, learners } = simulate(20000, path)

  const foundCount = (guessPerf < 0.99) + (slipPerf < 0.99) + (transitPerf < 0.99)
  if (foundCount > 0) {
    const data = { path, guessPerf, slipPerf, transitPerf }
    if (foundCount === 1) opt1.push(data)
    if (foundCount === 2) opt2.push(data)
    if (foundCount === 3) opt3.push(data)
  }

  option++

  process.stdout.clearLine()
  process.stdout.cursorTo(0)
  process.stdout.write(`${option} of ${totalOptions}, found ${opt1.length} ${opt2.length} ${opt3.length} ... ${path.map(p => (''+p).padStart(2)).join(' ')}`)

            }
          }
        }
      }
    }
  }

*/
<|endoftext|>


<commit_before>define(function () {
  return {
    name: "@font-face",
    description: "The @font-face rule lets you use any font as a web font. It is supported by the majority of browsers. While all browsers support the syntax, not every browser supports the same font format.",
    keywords: ['@font-face', 'fontface', 'font face', 'font', 'webfont'],
    browsers: [
      { name: "ie", range: "-", support: "yes", note: "Internet Explorer 6, 7, and 8 only support the Embedded OpenType (EOT) format. Internet Explorer 9 and above supports multiple formats." },
      { name: "chrome", range: "-", support: "yes" },
      { name: "firefox", range: "-", support: "yes" },
      { name: "safari", range: "-", support: "yes" },
      { name: "ios", range: "-", support: "yes", note: "Safari for iOS 3.2 to 4.1 only support SVG fonts." },
      { name: "opera", range: "-", support: "yes" },
      { name: "android", range: "-", support: "yes" }
    ],
    features: [
      {
        name: "font-family",
        keywords: ['font-family', 'family', 'font', 'typeface'],
        browsers: [
          { name: "ie", range: "-", support: "yes", note: "Internet Explorer limits the length of a font-family to 32 characters." },
          { name: "chrome", range: "-", support: "yes" },
          { name: "firefox", range: "-", support: "yes" },
          { name: "safari", range: "-", support: "yes" },
          { name: "ios", range: "-", support: "yes" },
          { name: "opera", range: "-", support: "yes" },
          { name: "android", range: "-", support: "yes" }
        ]
      },
      {
        name: "src",
        keywords: ['font', 'src'],
        browsers: [
          { name: "ie", range: "6-8", support: "partial", note: "Internet Explorer 6 to 8 only support a single url." },
          { name: "ie", range: "9-", support: "yes" },
          { name: "chrome", range: "-", support: "yes" },
          { name: "firefox", range: "-", support: "yes" },
          { name: "safari", range: "-", support: "yes" },
          { name: "ios", range: "-", support: "yes" },
          { name: "opera", range: "-", support: "yes" },
          { name: "android", range: "-", support: "yes" }
        ],
        features: [
          {
            name: "WOFF",
            keywords: ['woff', 'format', 'web font format', 'font format'],
            browsers: [
              { name: "ie", range: "-8", support: "no", note: "Internet Explorer 6 to 8 only support Embedded OpenType (EOT)." },
              { name: "ie", range: "9-", support: "yes" },
              { name: "chrome", range: "4", support: "no" },
              { name: "chrome", range: "5-", support: "yes" },
              { name: "firefox", range: "-", support: "yes" },
              { name: "safari", range: "-5", support: "no" },
              { name: "safari", range: "5.1-", support: "yes" },
              { name: "ios", range: "-4.3", support: "no" },
              { name: "ios", range: "5.1-", support: "yes" },
              { name: "opera", range: "-11", support: "no" },
              { name: "opera", range: "11.1", support: "yes" },
              { name: "android", range: "-4.3", support: "no" },
              { name: "android", range: "4.4-", support: "yes" }
            ]
          },
          {
            name: "WOFF2",
            keywords: ['woff', 'format', 'web font format', 'font format'],
            browsers: [
              { name: "ie", range: "-", support: "no" },
              { name: "chrome", range: "-35", support: "no" },
              { name: "chrome", range: "36-", support: "yes" },
              { name: "firefox", range: "-", support: "no" },
              { name: "safari", range: "-", support: "no" },
              { name: "ios", range: "-", support: "no" },
              { name: "opera", range: "-22", support: "no" },
              { name: "opera", range: "23-", support: "yes" },
              { name: "android", range: "-", support: "no" }
            ]
          },
          {
            name: "EOT",
            keywords: ['eot', 'format', 'web font format', 'font format', 'embedded opentype'],
            browsers: [
              { name: "ie", range: "-", support: "yes", note: "The EOT format only supports embedding TrueType fonts in Internet Explorer 8 and below." },
              { name: "chrome", range: "-", support: "no" },
              { name: "firefox", range: "-", support: "no" },
              { name: "safari", range: "-", support: "no" },
              { name: "ios", range: "-", support: "no" },
              { name: "opera", range: "-", support: "no" },
              { name: "android", range: "-", support: "no" }
            ]
          },
          {
            name: "TTF/OTF",
            keywords: ['ttf', 'truetype', 'opentype', 'otf', 'format', 'web font format', 'font format'],
            browsers: [
              { name: "ie", range: "-8", support: "no" },
              { name: "ie", range: "9-", support: "yes", note: "The fonts need their installable bit set for fonts to load." },
              { name: "chrome", range: "-", support: "yes" },
              { name: "firefox", range: "-", support: "yes" },
              { name: "safari", range: "-", support: "yes" },
              { name: "ios", range: "-4.1", support: "no" },
              { name: "ios", range: "4.3-", support: "yes" },
              { name: "opera", range: "-", support: "yes" },
              { name: "android", range: "-", support: "yes", note: "Due to a bug fonts need their installable bit set between versions 3.1 and 4.1." }
            ]
          },
          {
            name: "SVG fonts",
            keywords: ['svg', 'vector', 'scalable', 'graphics', 'format', 'web font format', 'font format'],
            browsers: [
              { name: "ie", range: "-", support: "no" },
              { name: "firefox", range: "-", support: "no" },
              { name: "chrome", range: "-37", support: "yes" },
              { name: "chrome", range: "38-", support: "partial", note: "Starting from Chrome 38 SVG fonts are disabled on all platforms except Windows XP and Windows Vista. On these platforms SVG fonts still work but are deprecated." },
              { name: "safari", range: "-", support: "yes" },
              { name: "opera", range: "-24", support: "yes" },
              { name: "opera", range: "25-", support: "yes", note: "Starting from Opera 25 SVG fonts are disabled on all platforms except Windows XP and Windows Vista. On these platforms SVG fonts still work but are deprecated." },
              { name: "android", range: "-2.3", support: "no" },
              { name: "android", range: "3-", support: "yes" }
            ]
          }
        ]
      },
      {
        name: "font-weight",
        keywords: ['font-weight', 'bold', 'weight'],
        browsers: [
          { name: "ie", range: "-", support: "yes" },
          { name: "chrome", range: "-", support: "yes" },
          { name: "firefox", range: "-", support: "yes" },
          { name: "safari", range: "-", support: "yes" },
          { name: "ios", range: "-", support: "yes" },
          { name: "opera", range: "-", support: "yes" },
          { name: "android", range: "-", support: "yes" }
        ]
      },
      {
        name: "font-style",
        keywords: ['font-style', 'style', 'italic', 'oblique'],
        browsers: [
          { name: "ie", range: "-", support: "yes" },
          { name: "chrome", range: "-", support: "yes" },
          { name: "firefox", range: "-", support: "yes" },
          { name: "safari", range: "-", support: "yes" },
          { name: "ios", range: "-", support: "yes" },
          { name: "opera", range: "-", support: "yes" },
          { name: "android", range: "-", support: "yes" }
        ]
      },
      {
        name: "font-stretch",
        keywords: ['font-stretch', 'stretch', 'condensed', 'expanded'],
        browsers: [
          { name: "ie", range: "-8", support: "no" },
          { name: "ie", range: "9-", support: "yes" },
          { name: "chrome", range: "-", support: "no" },
          { name: "firefox", range: "-8", support: "yes", note: "Firefox 3.6 to 8 on Windows do not support font-stretch. The font-stretch property is supported from version 3.6 on all other platforms." },
          { name: "firefox", range: "8-", support: "yes" },
          { name: "safari", range: "-", support: "no" },
          { name: "ios", range: "-", support: "no" },
          { name: "opera", range: "-", support: "no" },
          { name: "android", range: "-", support: "no" }
        ]
      },
      {
        name: "font-variant",
        keywords: ['font-variant', 'variant', 'small-caps'],
        browsers: [
          { name: "ie", range: "-", support: "no" },
          { name: "chrome", range: "-", support: "no", note: "Web fonts fail to render if font-variant is used within @font-face." },
          { name: "firefox", range: "-", support: "no" },
          { name: "safari", range: "-", support: "no", note: "Web fonts fail to render if font-variant is used within @font-face." },
          { name: "ios", range: "-", support: "no", note: "Web fonts fail to render if font-variant is used within @font-face." },
          { name: "opera", range: "-", support: "no", note: "Web fonts fail to render if font-variant is used within @font-face." },
          { name: "android", range: "-", support: "no", note: "Web fonts fail to render if font-variant is used within @font-face." }
        ]
      },
      {
        name: "font-feature-settings (font-face)",
        description: "The font-feature-settings property can be used to set default OpenType features within @font-face rules.",
        keywords: ['font-feature-settings', 'feature-settings', 'feature', 'features', 'ligatures', 'small-caps', 'opentype'],
        browsers: [
          { name: "ie", range: "-", support: "no" },
          { name: "chrome", range: "-", support: "no" },
          { name: "firefox", range: "-19", support: "no" },
          { name: "firefox", range: "20-", support: "yes" },
          { name: "safari", range: "-", support: "no" },
          { name: "ios", range: "-", support: "no" },
          { name: "opera", range: "-", support: "no" },
          { name: "android", range: "-", support: "no" }
        ]
      },
      {
        // This needs a bit more work. We also need to define what support means.
        // Several browsers can use this property to define which characters are
        // supported by a web font, but don't use this information to download
        // only the web fonts that are needed.
        name: "unicode-range",
        keywords: ['unicode-range', 'range', 'unicode', 'subset'],
        browsers: [
          { name: "ie", range: "-", support: "no" },
          { name: "chrome", range: "-", support: "yes" },
          { name: "firefox", range: "-", support: "no" },
          { name: "safari", range: "-", support: "yes" },
          { name: "ios", range: "-", support: "yes" },
          { name: "opera", range: "-12.16", support: "no" },
          { name: "opera", range: "15-", support: "yes" },
          { name: "android", range: "-3", support: "no" },
          { name: "android", range: "4-", support: "yes" }
        ]
      }
    ]
  };
});
<commit_msg>Update unicode-range data.<commit_after>define(function () {
  return {
    name: "@font-face",
    description: "The @font-face rule lets you use any font as a web font. It is supported by the majority of browsers. While all browsers support the syntax, not every browser supports the same font format.",
    keywords: ['@font-face', 'fontface', 'font face', 'font', 'webfont'],
    browsers: [
      { name: "ie", range: "-", support: "yes", note: "Internet Explorer 6, 7, and 8 only support the Embedded OpenType (EOT) format. Internet Explorer 9 and above supports multiple formats." },
      { name: "chrome", range: "-", support: "yes" },
      { name: "firefox", range: "-", support: "yes" },
      { name: "safari", range: "-", support: "yes" },
      { name: "ios", range: "-", support: "yes", note: "Safari for iOS 3.2 to 4.1 only support SVG fonts." },
      { name: "opera", range: "-", support: "yes" },
      { name: "android", range: "-", support: "yes" }
    ],
    features: [
      {
        name: "font-family",
        keywords: ['font-family', 'family', 'font', 'typeface'],
        browsers: [
          { name: "ie", range: "-", support: "yes", note: "Internet Explorer limits the length of a font-family to 32 characters." },
          { name: "chrome", range: "-", support: "yes" },
          { name: "firefox", range: "-", support: "yes" },
          { name: "safari", range: "-", support: "yes" },
          { name: "ios", range: "-", support: "yes" },
          { name: "opera", range: "-", support: "yes" },
          { name: "android", range: "-", support: "yes" }
        ]
      },
      {
        name: "src",
        keywords: ['font', 'src'],
        browsers: [
          { name: "ie", range: "6-8", support: "partial", note: "Internet Explorer 6 to 8 only support a single url." },
          { name: "ie", range: "9-", support: "yes" },
          { name: "chrome", range: "-", support: "yes" },
          { name: "firefox", range: "-", support: "yes" },
          { name: "safari", range: "-", support: "yes" },
          { name: "ios", range: "-", support: "yes" },
          { name: "opera", range: "-", support: "yes" },
          { name: "android", range: "-", support: "yes" }
        ],
        features: [
          {
            name: "WOFF",
            keywords: ['woff', 'format', 'web font format', 'font format'],
            browsers: [
              { name: "ie", range: "-8", support: "no", note: "Internet Explorer 6 to 8 only support Embedded OpenType (EOT)." },
              { name: "ie", range: "9-", support: "yes" },
              { name: "chrome", range: "4", support: "no" },
              { name: "chrome", range: "5-", support: "yes" },
              { name: "firefox", range: "-", support: "yes" },
              { name: "safari", range: "-5", support: "no" },
              { name: "safari", range: "5.1-", support: "yes" },
              { name: "ios", range: "-4.3", support: "no" },
              { name: "ios", range: "5.1-", support: "yes" },
              { name: "opera", range: "-11", support: "no" },
              { name: "opera", range: "11.1", support: "yes" },
              { name: "android", range: "-4.3", support: "no" },
              { name: "android", range: "4.4-", support: "yes" }
            ]
          },
          {
            name: "WOFF2",
            keywords: ['woff', 'format', 'web font format', 'font format'],
            browsers: [
              { name: "ie", range: "-", support: "no" },
              { name: "chrome", range: "-35", support: "no" },
              { name: "chrome", range: "36-", support: "yes" },
              { name: "firefox", range: "-", support: "no" },
              { name: "safari", range: "-", support: "no" },
              { name: "ios", range: "-", support: "no" },
              { name: "opera", range: "-22", support: "no" },
              { name: "opera", range: "23-", support: "yes" },
              { name: "android", range: "-", support: "no" }
            ]
          },
          {
            name: "EOT",
            keywords: ['eot', 'format', 'web font format', 'font format', 'embedded opentype'],
            browsers: [
              { name: "ie", range: "-", support: "yes", note: "The EOT format only supports embedding TrueType fonts in Internet Explorer 8 and below." },
              { name: "chrome", range: "-", support: "no" },
              { name: "firefox", range: "-", support: "no" },
              { name: "safari", range: "-", support: "no" },
              { name: "ios", range: "-", support: "no" },
              { name: "opera", range: "-", support: "no" },
              { name: "android", range: "-", support: "no" }
            ]
          },
          {
            name: "TTF/OTF",
            keywords: ['ttf', 'truetype', 'opentype', 'otf', 'format', 'web font format', 'font format'],
            browsers: [
              { name: "ie", range: "-8", support: "no" },
              { name: "ie", range: "9-", support: "yes", note: "The fonts need their installable bit set for fonts to load." },
              { name: "chrome", range: "-", support: "yes" },
              { name: "firefox", range: "-", support: "yes" },
              { name: "safari", range: "-", support: "yes" },
              { name: "ios", range: "-4.1", support: "no" },
              { name: "ios", range: "4.3-", support: "yes" },
              { name: "opera", range: "-", support: "yes" },
              { name: "android", range: "-", support: "yes", note: "Due to a bug fonts need their installable bit set between versions 3.1 and 4.1." }
            ]
          },
          {
            name: "SVG fonts",
            keywords: ['svg', 'vector', 'scalable', 'graphics', 'format', 'web font format', 'font format'],
            browsers: [
              { name: "ie", range: "-", support: "no" },
              { name: "firefox", range: "-", support: "no" },
              { name: "chrome", range: "-37", support: "yes" },
              { name: "chrome", range: "38-", support: "partial", note: "Starting from Chrome 38 SVG fonts are disabled on all platforms except Windows XP and Windows Vista. On these platforms SVG fonts still work but are deprecated." },
              { name: "safari", range: "-", support: "yes" },
              { name: "opera", range: "-24", support: "yes" },
              { name: "opera", range: "25-", support: "yes", note: "Starting from Opera 25 SVG fonts are disabled on all platforms except Windows XP and Windows Vista. On these platforms SVG fonts still work but are deprecated." },
              { name: "android", range: "-2.3", support: "no" },
              { name: "android", range: "3-", support: "yes" }
            ]
          }
        ]
      },
      {
        name: "font-weight",
        keywords: ['font-weight', 'bold', 'weight'],
        browsers: [
          { name: "ie", range: "-", support: "yes" },
          { name: "chrome", range: "-", support: "yes" },
          { name: "firefox", range: "-", support: "yes" },
          { name: "safari", range: "-", support: "yes" },
          { name: "ios", range: "-", support: "yes" },
          { name: "opera", range: "-", support: "yes" },
          { name: "android", range: "-", support: "yes" }
        ]
      },
      {
        name: "font-style",
        keywords: ['font-style', 'style', 'italic', 'oblique'],
        browsers: [
          { name: "ie", range: "-", support: "yes" },
          { name: "chrome", range: "-", support: "yes" },
          { name: "firefox", range: "-", support: "yes" },
          { name: "safari", range: "-", support: "yes" },
          { name: "ios", range: "-", support: "yes" },
          { name: "opera", range: "-", support: "yes" },
          { name: "android", range: "-", support: "yes" }
        ]
      },
      {
        name: "font-stretch",
        keywords: ['font-stretch', 'stretch', 'condensed', 'expanded'],
        browsers: [
          { name: "ie", range: "-8", support: "no" },
          { name: "ie", range: "9-", support: "yes" },
          { name: "chrome", range: "-", support: "no" },
          { name: "firefox", range: "-8", support: "yes", note: "Firefox 3.6 to 8 on Windows do not support font-stretch. The font-stretch property is supported from version 3.6 on all other platforms." },
          { name: "firefox", range: "8-", support: "yes" },
          { name: "safari", range: "-", support: "no" },
          { name: "ios", range: "-", support: "no" },
          { name: "opera", range: "-", support: "no" },
          { name: "android", range: "-", support: "no" }
        ]
      },
      {
        name: "font-variant",
        keywords: ['font-variant', 'variant', 'small-caps'],
        browsers: [
          { name: "ie", range: "-", support: "no" },
          { name: "chrome", range: "-", support: "no", note: "Web fonts fail to render if font-variant is used within @font-face." },
          { name: "firefox", range: "-", support: "no" },
          { name: "safari", range: "-", support: "no", note: "Web fonts fail to render if font-variant is used within @font-face." },
          { name: "ios", range: "-", support: "no", note: "Web fonts fail to render if font-variant is used within @font-face." },
          { name: "opera", range: "-", support: "no", note: "Web fonts fail to render if font-variant is used within @font-face." },
          { name: "android", range: "-", support: "no", note: "Web fonts fail to render if font-variant is used within @font-face." }
        ]
      },
      {
        name: "font-feature-settings (font-face)",
        description: "The font-feature-settings property can be used to set default OpenType features within @font-face rules.",
        keywords: ['font-feature-settings', 'feature-settings', 'feature', 'features', 'ligatures', 'small-caps', 'opentype'],
        browsers: [
          { name: "ie", range: "-", support: "no" },
          { name: "chrome", range: "-", support: "no" },
          { name: "firefox", range: "-19", support: "no" },
          { name: "firefox", range: "20-", support: "yes" },
          { name: "safari", range: "-", support: "no" },
          { name: "ios", range: "-", support: "no" },
          { name: "opera", range: "-", support: "no" },
          { name: "android", range: "-", support: "no" }
        ]
      },
      {
        name: "unicode-range",
        description: "The unicode-range property offers a way to tell the browser which unicode characters are included in a font. It can use this information to selectively download and display fonts. For a browser to have full support it must both download and display the font selectively. Partial support means that a browser only uses the given ranges to selectively display characters.",
        keywords: ['unicode-range', 'range', 'unicode', 'subset'],
        browsers: [
          { name: "ie", range: "-8", support: "no" },
          { name: "ie", range: "9-", support: "partial", note: "Internet Explorer only supports the range syntax with an uppercase U (e.g. U+65, U+66). Support for lowercase ranges (e.g. u+65, u+66) was added to the CSS specification after Internet Explorer shipped, so you should always use ranges with an uppercase U for maximum compatibility." },
          { name: "chrome", range: "-35", support: "partial" },
          { name: "chrome", range: "36-", support: "yes" },
          { name: "firefox", range: "-35", support: "no" },
          { name: "firefox", range: "36-", support: "yes" },
          { name: "safari", range: "-", support: "partial" },
          { name: "ios", range: "-", support: "partial" },
          { name: "opera", range: "-12.16", support: "no" },
          { name: "opera", range: "15-22", support: "partial" },
          { name: "opera", range: "23-", support: "yes" },
          { name: "android", range: "-3", support: "no" },
          { name: "android", range: "4-", support: "partial" }
        ]
      }
    ]
  };
});
<|endoftext|>


<commit_before>export default {
	"hat": [
		"fedora",
		"headgear",
		"helmet",
		"boater",
		"bonnet",
		"bowler",
		"bucket",
		"chapeau",
		"headpiece",
		"lid",
		"millinery",
		"Panama",
		"head-protector",
		"sailor",
		"skimmer",
		"sombrero",
		"Stetson",
		"straw",
		"tam",
		"topper",
		"stove-top"
	],
	"car": [
		"auto",
		"automobile",
		"bus",
		"convertible",
		"jeep",
		"limousine",
		"machine",
		"motor",
		"pickup",
		"ride",
		"station wagon",
		"truck",
		"van",
		"wagon",
		"bucket",
		"buggy",
		"compact",
		"conveyance",
		"coupe",
		"hardtop",
		"hatchback",
		"heap",
		"jalopy",
		"junker",
		"motorcar",
		"roadster",
		"sedan",
		"subcompact",
		"wheels",
		"wreck",
		"clunker",
		"gas guzzler",
		"touring car"
	],
	"autombile": [
		"auto",
		"automobile",
		"bus",
		"convertible",
		"jeep",
		"limousine",
		"machine",
		"motor",
		"pickup",
		"ride",
		"station wagon",
		"truck",
		"van",
		"wagon",
		"bucket",
		"buggy",
		"compact",
		"conveyance",
		"coupe",
		"hardtop",
		"hatchback",
		"heap",
		"jalopy",
		"junker",
		"motorcar",
		"roadster",
		"sedan",
		"subcompact",
		"wheels",
		"wreck",
		"clunker",
		"gas guzzler",
		"touring car"
	],
	"wagon": [
		"auto",
		"automobile",
		"bus",
		"convertible",
		"jeep",
		"limousine",
		"machine",
		"motor",
		"pickup",
		"ride",
		"station wagon",
		"truck",
		"van",
		"wagon",
		"bucket",
		"buggy",
		"compact",
		"conveyance",
		"coupe",
		"hardtop",
		"hatchback",
		"heap",
		"jalopy",
		"junker",
		"motorcar",
		"roadster",
		"sedan",
		"subcompact",
		"wheels",
		"wreck",
		"clunker",
		"gas guzzler",
		"touring car"
	],
};
<commit_msg>I bought a great new // unctuous millinery // peripatetic<commit_after>export default {
	"hat": [
		"fedora",
		"headgear",
		"helmet",
		"boater",
		"bonnet",
		"bowler",
		"bucket",
		"chapeau",
		"headpiece",
		"lid",
		"millinery",
		"Panama",
		"headprotector",
		"sailor",
		"skimmer",
		"sombrero",
		"Stetson",
		"straw",
		"tam",
		"topper",
		"stove-top"
	],
	"car": [
		"auto",
		"automobile",
		"bus",
		"convertible",
		"jeep",
		"limousine",
		"machine",
		"motor",
		"pickup",
		"ride",
		"station wagon",
		"truck",
		"van",
		"wagon",
		"bucket",
		"buggy",
		"compact",
		"conveyance",
		"coupe",
		"hardtop",
		"hatchback",
		"heap",
		"jalopy",
		"junker",
		"motorcar",
		"roadster",
		"sedan",
		"subcompact",
		"wheels",
		"wreck",
		"clunker",
		"gas guzzler",
		"touring car"
	],
	"autombile": [
		"auto",
		"automobile",
		"bus",
		"convertible",
		"jeep",
		"limousine",
		"machine",
		"motor",
		"pickup",
		"ride",
		"station wagon",
		"truck",
		"van",
		"wagon",
		"bucket",
		"buggy",
		"compact",
		"conveyance",
		"coupe",
		"hardtop",
		"hatchback",
		"heap",
		"jalopy",
		"junker",
		"motorcar",
		"roadster",
		"sedan",
		"subcompact",
		"wheels",
		"wreck",
		"clunker",
		"gas guzzler",
		"touring car"
	],
	"wagon": [
		"auto",
		"automobile",
		"bus",
		"convertible",
		"jeep",
		"limousine",
		"machine",
		"motor",
		"pickup",
		"ride",
		"station wagon",
		"truck",
		"van",
		"wagon",
		"bucket",
		"buggy",
		"compact",
		"conveyance",
		"coupe",
		"hardtop",
		"hatchback",
		"heap",
		"jalopy",
		"junker",
		"motorcar",
		"roadster",
		"sedan",
		"subcompact",
		"wheels",
		"wreck",
		"clunker",
		"gas guzzler",
		"touring car"
	],
};
<|endoftext|>


<commit_before>/*
 DataCamp Light
 Version {{version}}
 */

(function () {
  'use strict';

  var MIN_HEIGHT = 300;
  var DCL_URL = "https://cdn.datacamp.com/dcl/";

  //Logic for 'Powered By DataCamp'
  function checkPoweredBy() {
    function domainMatches(domain) {
      return location.hostname.match(domain) !== null
    }

    function changeLink(url) {
      for (var i = 0; i < elements.length; i++) {
        elements[i].getElementsByTagName('a')[0].href = url;
      }
    }

    function removePoweredBy() {
      while (elements[0]) {
        elements[0].parentNode.removeChild(elements[0]);
      }
    }

    var elements = document.getElementsByClassName('powered-by-datacamp');
    if (domainMatches("r-bloggers.com")) {
      changeLink("https://www.datacamp.com?tap_a=5644-dce66f&tap_s=10907-287229");
    } else if (domainMatches("datacamp.com")) {
      removePoweredBy();
    }
  }

  //Initialises the DIV for the DCL exercise: Load HTML, sets height, etc
  function createContainer(exercise_DOM) {
    exercise_DOM.className += ' datacamp-exercise';

    // Calculate height
    var height;
    if ("height" in exercise_DOM.dataset && exercise_DOM.dataset["height"] !== 'auto') {
      var user_height = Math.round(exercise_DOM.dataset["height"]);
      if (!isNaN(user_height)) {
        if (user_height >= MIN_HEIGHT) {
          exercise_DOM.style.height = user_height + "px";
          var style_attribute = "height:" + user_height + "px;";
          exercise_DOM.setAttribute("style", style_attribute);
        } else {
          console.log("The height attribute should be >= " + MIN_HEIGHT + ".");
        }
      } else {
        console.log("Invalid height attribute.");
      }
    }

    //Wrap encoded data for easier handling
    if ("encoded" in exercise_DOM.dataset) {
      exercise_DOM.innerHTML = '
' + exercise_DOM.innerHTML.trim() + '
';
    }

    //Load angular app HTML
    exercise_DOM.innerHTML += '{{mainView}}';

    //Powered By DataCamp
    var htmlString = '{{poweredBy}}';
    var div = document.createElement('div');
    div.innerHTML = htmlString;
    var element = div.firstChild;
    exercise_DOM.parentNode.insertBefore(element, exercise_DOM.nextSibling);
  }

  function loadScriptAsync(file) {
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = file;
    script.charset = "utf-8";

    insertTag('body', script);
  }

  function loadStyle(file) {
    var style = document.createElement("link");
    style.type = 'text/css';
    style.rel = 'stylesheet';
    style.href = file;

    insertTag('head', style);
  }

  function renderDCLightExercises() {
    var exercises = document.querySelectorAll("[data-datacamp-exercise]");

    if (exercises.length === 0) {
      console.log("No DataCamp Light exercises found. Make sure the exercise has the 'data-datacamp-exercise' attribute.");
    }

    for (var i = 0; i < exercises.length; i++) {
      (function (index) {
        var exercise_DOM = exercises[index];

        if ((' ' + exercise_DOM.className + ' ').indexOf(' datacamp-exercise ') > -1) {
          // We use this check to see if the exercise is already replaced.
          return;
        }

        // Create the DCL angular app div
        createContainer(exercise_DOM);
      })(i);
    }
    checkPoweredBy();
  }

  function initDCLightExercises() {
    renderDCLightExercises();
    loadScriptAsync(DCL_URL + '{{scriptLink}}');
  }

  function renderAddedDCLightExercises() {
    renderDCLightExercises();
    window.bootstrapDCLightExercises();
  }

  function insertAllStyles() {
    insertCSS();

    var links = [
      DCL_URL + "{{styleLink}}",
      "https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css"
    ];

    for (var i = 0; i < links.length; i++) {
      loadStyle(links[i]);
    }
  }

  function insertTag(parent, element) {
    document.getElementsByTagName(parent)[0].appendChild(element);
  }

  function insertCSS() {
    var style = document.createElement('style');
    style.type = 'text/css';
    insertTag('head', style);

    var css = '{{mainStyle}}';

    if (style.styleSheet)
      style.styleSheet.cssText = css;
    else
      style.innerHTML = css;
  }

  function isAlreadyExecuted() {
    return (typeof(window.renderAddedDataCampExercises) === "function");
  }

  if (!isAlreadyExecuted()) {
    window.renderAddedDCLightExercises = renderAddedDCLightExercises;
    insertAllStyles();
    if (document.readyState == "complete" || document.readyState == "loaded") {
      initDCLightExercises();
    } else {
      document.addEventListener('DOMContentLoaded', initDCLightExercises);
    }
  } else {
    console.log('Warning: tried to load DataCamp Light multiple times.')
  }
})();

<commit_msg>improve naming<commit_after>/*
 DataCamp Light
 Version {{version}}
 */

(function () {
  'use strict';

  var MIN_HEIGHT = 300;
  var DCL_URL = "https://cdn.datacamp.com/dcl/";

  //Logic for 'Powered By DataCamp'
  function checkPoweredBy() {
    function domainMatches(domain) {
      return location.hostname.match(domain) !== null
    }

    function changeLink(url) {
      for (var i = 0; i < elements.length; i++) {
        elements[i].getElementsByTagName('a')[0].href = url;
      }
    }

    function removePoweredBy() {
      while (elements[0]) {
        elements[0].parentNode.removeChild(elements[0]);
      }
    }

    var elements = document.getElementsByClassName('powered-by-datacamp');
    if (domainMatches("r-bloggers.com")) {
      changeLink("https://www.datacamp.com?tap_a=5644-dce66f&tap_s=10907-287229");
    } else if (domainMatches("datacamp.com")) {
      removePoweredBy();
    }
  }

  //Initialises the DIV for the DCL exercise: Load HTML, sets height, etc
  function createContainer(exercise_DOM) {
    exercise_DOM.className += ' datacamp-exercise';

    // Calculate height
    var height;
    if ("height" in exercise_DOM.dataset && exercise_DOM.dataset["height"] !== 'auto') {
      var user_height = Math.round(exercise_DOM.dataset["height"]);
      if (!isNaN(user_height)) {
        if (user_height >= MIN_HEIGHT) {
          exercise_DOM.style.height = user_height + "px";
          var style_attribute = "height:" + user_height + "px;";
          exercise_DOM.setAttribute("style", style_attribute);
        } else {
          console.log("The height attribute should be >= " + MIN_HEIGHT + ".");
        }
      } else {
        console.log("Invalid height attribute.");
      }
    }

    //Wrap encoded data for easier handling
    if ("encoded" in exercise_DOM.dataset) {
      exercise_DOM.innerHTML = '
' + exercise_DOM.innerHTML.trim() + '
';
    }

    //Load angular app HTML
    exercise_DOM.innerHTML += '{{mainView}}';

    //Powered By DataCamp
    var htmlString = '{{poweredBy}}';
    var div = document.createElement('div');
    div.innerHTML = htmlString;
    var element = div.firstChild;
    exercise_DOM.parentNode.insertBefore(element, exercise_DOM.nextSibling);
  }

  function loadScriptAsync(file) {
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = file;
    script.charset = "utf-8";

    insertTag('body', script);
  }

  function loadStyle(file) {
    var style = document.createElement("link");
    style.type = 'text/css';
    style.rel = 'stylesheet';
    style.href = file;

    insertTag('head', style);
  }

  function renderDCLightExercises() {
    var exercises = document.querySelectorAll("[data-datacamp-exercise]");

    if (exercises.length === 0) {
      console.log("No DataCamp Light exercises found. Make sure the exercise has the 'data-datacamp-exercise' attribute.");
    }

    for (var i = 0; i < exercises.length; i++) {
      (function (index) {
        var exercise_DOM = exercises[index];

        if ((' ' + exercise_DOM.className + ' ').indexOf(' datacamp-exercise ') > -1) {
          // We use this check to see if the exercise is already replaced.
          return;
        }

        // Create the DCL angular app div
        createContainer(exercise_DOM);
      })(i);
    }
    checkPoweredBy();
  }

  function initDCLightExercises() {
    renderDCLightExercises();
    loadScriptAsync(DCL_URL + '{{scriptLink}}');
  }

  function initAddedDCLightExercises() {
    renderDCLightExercises();
    window.bootstrapDCLightExercises();
  }

  function insertAllStyles() {
    insertCSS();

    var links = [
      DCL_URL + "{{styleLink}}",
      "https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css"
    ];

    for (var i = 0; i < links.length; i++) {
      loadStyle(links[i]);
    }
  }

  function insertTag(parent, element) {
    document.getElementsByTagName(parent)[0].appendChild(element);
  }

  function insertCSS() {
    var style = document.createElement('style');
    style.type = 'text/css';
    insertTag('head', style);

    var css = '{{mainStyle}}';

    if (style.styleSheet)
      style.styleSheet.cssText = css;
    else
      style.innerHTML = css;
  }

  function isAlreadyExecuted() {
    return (typeof(window.initAddedDCLightExercises) === "function");
  }

  if (!isAlreadyExecuted()) {
    window.initAddedDCLightExercises = initAddedDCLightExercises;
    insertAllStyles();
    if (document.readyState == "complete" || document.readyState == "loaded") {
      initDCLightExercises();
    } else {
      document.addEventListener('DOMContentLoaded', initDCLightExercises);
    }
  } else {
    console.log('Warning: tried to load DataCamp Light multiple times.')
  }
})();

<|endoftext|>