<commit_before>/*eslint no-cond-assign: 0*/
import i18next from 'i18next';
import {DOM} from 'aurelia-pal';

export class I18N {

  globalVars = {};
  params = {};
  i18nextDefered = {
    resolve: null,
    promise: null
  };

  constructor(ea, signaler) {
    this.i18next = i18next;
    this.ea = ea;
    this.Intl = window.Intl;
    this.signaler = signaler;
    this.i18nextDefered.promise = new Promise((resolve) => this.i18nextDefered.resolve = resolve);
  }

  setup(options?) {
    const defaultOptions = {
      compatibilityAPI: 'v1',
      compatibilityJSON: 'v1',
      lng: 'en',
      attributes: ['t', 'i18n'],
      fallbackLng: 'en',
      debug: false
    };

    i18next.init(options || defaultOptions, (err, t) => {
      //make sure attributes is an array in case a string was provided
      if (i18next.options.attributes instanceof String) {
        i18next.options.attributes = [i18next.options.attributes];
      }

      this.i18nextDefered.resolve(this.i18next);
    });

    return this.i18nextDefered.promise;
  }

  i18nextReady() {
    return this.i18nextDefered.promise;
  }

  setLocale(locale) {
    return new Promise( resolve => {
      let oldLocale = this.getLocale();
      this.i18next.changeLanguage(locale, (err, tr) => {
        this.ea.publish('i18n:locale:changed', { oldValue: oldLocale, newValue: locale });
        this.signaler.signal('aurelia-translation-signal');
        resolve(tr);
      });
    });
  }

  getLocale() {
    return this.i18next.language;
  }

  nf(options?, locales?) {
    return new this.Intl.NumberFormat(locales || this.getLocale(), options || {});
  }

  uf(number, locale?) {
    let nf = this.nf({}, locale || this.getLocale());
    let comparer = nf.format(10000 / 3);

    let thousandSeparator = comparer[1];
    let decimalSeparator  = comparer[5];

    // remove thousand seperator
    let result = number.replace(thousandSeparator, '')
      // remove non-numeric signs except -> , .
      .replace(/[^\d.,-]/g, '')
      // replace original decimalSeparator with english one
      .replace(decimalSeparator, '.');

    // return real number
    return Number(result);
  }

  df(options?, locales?) {
    return new this.Intl.DateTimeFormat(locales || this.getLocale(), options);
  }

  tr(key, options?) {
    let fullOptions = this.globalVars;

    if (options !== undefined) {
      fullOptions = Object.assign(Object.assign({}, this.globalVars), options);
    }

    return this.i18next.t(key, fullOptions);
  }

  registerGlobalVariable(key, value) {
    this.globalVars[key] = value;
  }

  unregisterGlobalVariable(key) {
    delete this.globalVars[key];
  }

  /**
   * Scans an element for children that have a translation attribute and
   * updates their innerHTML with the current translation values.
   *
   * If an image is encountered the translated value will be applied to the src attribute.
   *
   * @param el    HTMLElement to search within
   */
  updateTranslations(el) {
    if (!el || !el.querySelectorAll) {
      return;
    }

    let i;
    let l;

    //create a selector from the specified attributes to look for
    //var selector = [].concat(this.i18next.options.attributes);
    let selector = [].concat(this.i18next.options.attributes);
    for (i = 0, l = selector.length; i < l; i++) selector[i] = '[' + selector[i] + ']';
    selector = selector.join(',');

    //get the nodes
    let nodes = el.querySelectorAll(selector);
    for (i = 0, l = nodes.length; i < l; i++) {
      let node = nodes[i];
      let keys;
      //test every attribute and get the first one that has a value
      for (let i2 = 0, l2 = this.i18next.options.attributes.length; i2 < l2; i2++) {
        keys = node.getAttribute(this.i18next.options.attributes[i2]);
        if (keys) break;
      }
      //skip if nothing was found
      if (!keys) continue;

      //split the keys into multiple keys separated by a ;
      this.updateValue(node, keys);
    }
  }

  updateValue(node, value, params) {
    if (params) {
      this.params[value] = params;
    } else if (this.params[value]) {
      params = this.params[value];
    }

    return this.i18nextDefered.promise.then(() => this._updateValue(node, value, params));
  }

  _updateValue(node, value, params) {
    if (value === null || value === undefined) {
      return;
    }

    let keys = value.split(';');
    let i = keys.length;

    while (i--) {
      let key = keys[i];
      // remove the optional attribute
      let re = /\[([a-z\-]*)\]/g;

      let m;
      let attr = 'text';
      //set default attribute to src if this is an image node
      if (node.nodeName === 'IMG') attr = 'src';

      //check if a attribute was specified in the key
      while ((m = re.exec(key)) !== null) {
        if (m.index === re.lastIndex) {
          re.lastIndex++;
        }
        if (m) {
          key = key.replace(m[0], '');
          attr = m[1];
        }
      }

      if (!node._textContent) node._textContent = node.textContent;
      if (!node._innerHTML) node._innerHTML = node.innerHTML;

      //handle various attributes
      //anything other than text,prepend,append or html will be added as an attribute on the element.
      switch (attr) {
      case 'text':
        let newChild = DOM.createTextNode(this.tr(key, params));
        if (node._newChild) {
          node.removeChild(node._newChild);
        }

        node._newChild = newChild;
        while (node.firstChild) {
          node.removeChild(node.firstChild);
        }
        node.appendChild(node._newChild);
        break;
      case 'prepend':
        let prependParser = DOM.createElement('div');
        prependParser.innerHTML = this.tr(key, params);
        for (let ni = node.childNodes.length - 1; ni >= 0; ni--) {
          if (node.childNodes[ni]._prepended) {
            node.removeChild(node.childNodes[ni]);
          }
        }

        for (let pi = prependParser.childNodes.length - 1; pi >= 0; pi--) {
          prependParser.childNodes[pi]._prepended = true;
          if (node.firstChild) {
            node.insertBefore(prependParser.childNodes[pi], node.firstChild);
          } else {
            node.appendChild(prependParser.childNodes[pi]);
          }
        }
        break;
      case 'append':
        let appendParser = DOM.createElement('div');
        appendParser.innerHTML = this.tr(key, params);
        for (let ni = node.childNodes.length - 1; ni >= 0; ni--) {
          if (node.childNodes[ni]._appended) {
            node.removeChild(node.childNodes[ni]);
          }
        }

        while (appendParser.firstChild) {
          appendParser.firstChild._appended = true;
          node.appendChild(appendParser.firstChild);
        }
        break;
      case 'html':
        node.innerHTML = this.tr(key, params);
        break;
      default: //normal html attribute
        node.setAttribute(attr, this.tr(key, params));
        break;
      }
    }
  }
}
<commit_msg>feat(i18n): add dependency injection<commit_after>/*eslint no-cond-assign: 0*/
import i18next from 'i18next';
import {DOM} from 'aurelia-pal';
import {EventAggregator} from 'aurelia-event-aggregator';
import {BindingSignaler} from 'aurelia-templating-resources';

export class I18N {
  static inject = [EventAggregator, BindingSignaler];

  globalVars = {};
  params = {};
  i18nextDefered = {
    resolve: null,
    promise: null
  };

  constructor(ea, signaler) {
    this.i18next = i18next;
    this.ea = ea;
    this.Intl = window.Intl;
    this.signaler = signaler;
    this.i18nextDefered.promise = new Promise((resolve) => this.i18nextDefered.resolve = resolve);
  }

  setup(options?) {
    const defaultOptions = {
      compatibilityAPI: 'v1',
      compatibilityJSON: 'v1',
      lng: 'en',
      attributes: ['t', 'i18n'],
      fallbackLng: 'en',
      debug: false
    };

    i18next.init(options || defaultOptions, (err, t) => {
      //make sure attributes is an array in case a string was provided
      if (i18next.options.attributes instanceof String) {
        i18next.options.attributes = [i18next.options.attributes];
      }

      this.i18nextDefered.resolve(this.i18next);
    });

    return this.i18nextDefered.promise;
  }

  i18nextReady() {
    return this.i18nextDefered.promise;
  }

  setLocale(locale) {
    return new Promise( resolve => {
      let oldLocale = this.getLocale();
      this.i18next.changeLanguage(locale, (err, tr) => {
        this.ea.publish('i18n:locale:changed', { oldValue: oldLocale, newValue: locale });
        this.signaler.signal('aurelia-translation-signal');
        resolve(tr);
      });
    });
  }

  getLocale() {
    return this.i18next.language;
  }

  nf(options?, locales?) {
    return new this.Intl.NumberFormat(locales || this.getLocale(), options || {});
  }

  uf(number, locale?) {
    let nf = this.nf({}, locale || this.getLocale());
    let comparer = nf.format(10000 / 3);

    let thousandSeparator = comparer[1];
    let decimalSeparator  = comparer[5];

    // remove thousand seperator
    let result = number.replace(thousandSeparator, '')
      // remove non-numeric signs except -> , .
      .replace(/[^\d.,-]/g, '')
      // replace original decimalSeparator with english one
      .replace(decimalSeparator, '.');

    // return real number
    return Number(result);
  }

  df(options?, locales?) {
    return new this.Intl.DateTimeFormat(locales || this.getLocale(), options);
  }

  tr(key, options?) {
    let fullOptions = this.globalVars;

    if (options !== undefined) {
      fullOptions = Object.assign(Object.assign({}, this.globalVars), options);
    }

    return this.i18next.t(key, fullOptions);
  }

  registerGlobalVariable(key, value) {
    this.globalVars[key] = value;
  }

  unregisterGlobalVariable(key) {
    delete this.globalVars[key];
  }

  /**
   * Scans an element for children that have a translation attribute and
   * updates their innerHTML with the current translation values.
   *
   * If an image is encountered the translated value will be applied to the src attribute.
   *
   * @param el    HTMLElement to search within
   */
  updateTranslations(el) {
    if (!el || !el.querySelectorAll) {
      return;
    }

    let i;
    let l;

    //create a selector from the specified attributes to look for
    //var selector = [].concat(this.i18next.options.attributes);
    let selector = [].concat(this.i18next.options.attributes);
    for (i = 0, l = selector.length; i < l; i++) selector[i] = '[' + selector[i] + ']';
    selector = selector.join(',');

    //get the nodes
    let nodes = el.querySelectorAll(selector);
    for (i = 0, l = nodes.length; i < l; i++) {
      let node = nodes[i];
      let keys;
      //test every attribute and get the first one that has a value
      for (let i2 = 0, l2 = this.i18next.options.attributes.length; i2 < l2; i2++) {
        keys = node.getAttribute(this.i18next.options.attributes[i2]);
        if (keys) break;
      }
      //skip if nothing was found
      if (!keys) continue;

      //split the keys into multiple keys separated by a ;
      this.updateValue(node, keys);
    }
  }

  updateValue(node, value, params) {
    if (params) {
      this.params[value] = params;
    } else if (this.params[value]) {
      params = this.params[value];
    }

    return this.i18nextDefered.promise.then(() => this._updateValue(node, value, params));
  }

  _updateValue(node, value, params) {
    if (value === null || value === undefined) {
      return;
    }

    let keys = value.split(';');
    let i = keys.length;

    while (i--) {
      let key = keys[i];
      // remove the optional attribute
      let re = /\[([a-z\-]*)\]/g;

      let m;
      let attr = 'text';
      //set default attribute to src if this is an image node
      if (node.nodeName === 'IMG') attr = 'src';

      //check if a attribute was specified in the key
      while ((m = re.exec(key)) !== null) {
        if (m.index === re.lastIndex) {
          re.lastIndex++;
        }
        if (m) {
          key = key.replace(m[0], '');
          attr = m[1];
        }
      }

      if (!node._textContent) node._textContent = node.textContent;
      if (!node._innerHTML) node._innerHTML = node.innerHTML;

      //handle various attributes
      //anything other than text,prepend,append or html will be added as an attribute on the element.
      switch (attr) {
      case 'text':
        let newChild = DOM.createTextNode(this.tr(key, params));
        if (node._newChild) {
          node.removeChild(node._newChild);
        }

        node._newChild = newChild;
        while (node.firstChild) {
          node.removeChild(node.firstChild);
        }
        node.appendChild(node._newChild);
        break;
      case 'prepend':
        let prependParser = DOM.createElement('div');
        prependParser.innerHTML = this.tr(key, params);
        for (let ni = node.childNodes.length - 1; ni >= 0; ni--) {
          if (node.childNodes[ni]._prepended) {
            node.removeChild(node.childNodes[ni]);
          }
        }

        for (let pi = prependParser.childNodes.length - 1; pi >= 0; pi--) {
          prependParser.childNodes[pi]._prepended = true;
          if (node.firstChild) {
            node.insertBefore(prependParser.childNodes[pi], node.firstChild);
          } else {
            node.appendChild(prependParser.childNodes[pi]);
          }
        }
        break;
      case 'append':
        let appendParser = DOM.createElement('div');
        appendParser.innerHTML = this.tr(key, params);
        for (let ni = node.childNodes.length - 1; ni >= 0; ni--) {
          if (node.childNodes[ni]._appended) {
            node.removeChild(node.childNodes[ni]);
          }
        }

        while (appendParser.firstChild) {
          appendParser.firstChild._appended = true;
          node.appendChild(appendParser.firstChild);
        }
        break;
      case 'html':
        node.innerHTML = this.tr(key, params);
        break;
      default: //normal html attribute
        node.setAttribute(attr, this.tr(key, params));
        break;
      }
    }
  }
}
<|endoftext|>


<commit_before>var SourceMapGenerator = require("source-map").SourceMapGenerator;

module.exports = {
  surround,
};

let defaultOptions = {
  args: undefined,
  params: undefined,
  prependSemicolon: true,
  useStrict: true,
  trimCode: true,
  generateSourceMap: true,
};

function surround(code, userOptions, sourceMapOptions) {
  let options = {
    ...defaultOptions,
    ...userOptions,
  };

  let useStrictLines = options.useStrict ? ['"use strict";', ""] : [];
  const trimmedCode = options.trimCode ? code.trim() : code;
  const prependedSemicolon = options.prependSemicolon ? ";" : "";
  const bindThis = options.bindThis ? ".bind(this)" : "";

  const { args, params } = getArgsAndParams(options);

  let lines = [
    `${prependedSemicolon}(function(${params}) {`,
    ...useStrictLines,
    trimmedCode,
    `}${bindThis}(${args}));`,
    "",
  ];

  let result = {
    code: lines.join("\n"),
  };

  if (sourceMapOptions && options.generateSourceMap !== false) {
    result.sourceMap = generateSourceMap(code, options, sourceMapOptions);
  }

  return result;
}

function getArgsAndParams(options) {
  const params = options.params || options.args || [];
  const args = options.args || options.params || [];

  return {
    args: args.join(", "),
    params: params.join(", "),
  };
}

function generateSourceMap(originalCode, options, sourceMapOptions) {
  // We don't care about trailing lines for the mapping
  let code = originalCode.trimRight();

  let sourceMapGenerator = new SourceMapGenerator({
    file: sourceMapOptions.fileName,
  });

  // We have at least one line of positive offset because of the start of the IIFE
  let linesOffset = 1;

  // Then we have optionally two more lines because of the "use strict"
  // and the empty line after that
  linesOffset += options.useStrict ? 2 : 0;

  // Then we have negative lines for the leading empty lines that are trimmed
  let leadingEmptyLines = ((code.match(/^\s+/) || [""])[0].match(/\n/g) || [])
    .length;
  linesOffset -= options.trimCode ? leadingEmptyLines : 0;

  // We add sourcemaps only for the non-empty lines.
  // So, we start the loop in the first non-empty line.
  // (The trailing empty lines are already trimmed.)
  let codeLines = (code.trimLeft().match(/\n/g) || []).length + 1;

  for (let i = 1 + leadingEmptyLines; i <= codeLines + leadingEmptyLines; i++) {
    sourceMapGenerator.addMapping({
      source: sourceMapOptions.fileName,
      original: {
        line: i,
        column: 0,
      },
      generated: {
        line: i + linesOffset,
        column: 0,
      },
    });
  }

  return sourceMapGenerator.toString();
}
<commit_msg>Move module.exports to the end of the file<commit_after>var SourceMapGenerator = require("source-map").SourceMapGenerator;

let defaultOptions = {
  args: undefined,
  params: undefined,
  prependSemicolon: true,
  useStrict: true,
  trimCode: true,
  generateSourceMap: true,
};

function surround(code, userOptions, sourceMapOptions) {
  let options = {
    ...defaultOptions,
    ...userOptions,
  };

  let useStrictLines = options.useStrict ? ['"use strict";', ""] : [];
  const trimmedCode = options.trimCode ? code.trim() : code;
  const prependedSemicolon = options.prependSemicolon ? ";" : "";
  const bindThis = options.bindThis ? ".bind(this)" : "";

  const { args, params } = getArgsAndParams(options);

  let lines = [
    `${prependedSemicolon}(function(${params}) {`,
    ...useStrictLines,
    trimmedCode,
    `}${bindThis}(${args}));`,
    "",
  ];

  let result = {
    code: lines.join("\n"),
  };

  if (sourceMapOptions && options.generateSourceMap !== false) {
    result.sourceMap = generateSourceMap(code, options, sourceMapOptions);
  }

  return result;
}

function getArgsAndParams(options) {
  const params = options.params || options.args || [];
  const args = options.args || options.params || [];

  return {
    args: args.join(", "),
    params: params.join(", "),
  };
}

function generateSourceMap(originalCode, options, sourceMapOptions) {
  // We don't care about trailing lines for the mapping
  let code = originalCode.trimRight();

  let sourceMapGenerator = new SourceMapGenerator({
    file: sourceMapOptions.fileName,
  });

  // We have at least one line of positive offset because of the start of the IIFE
  let linesOffset = 1;

  // Then we have optionally two more lines because of the "use strict"
  // and the empty line after that
  linesOffset += options.useStrict ? 2 : 0;

  // Then we have negative lines for the leading empty lines that are trimmed
  let leadingEmptyLines = ((code.match(/^\s+/) || [""])[0].match(/\n/g) || [])
    .length;
  linesOffset -= options.trimCode ? leadingEmptyLines : 0;

  // We add sourcemaps only for the non-empty lines.
  // So, we start the loop in the first non-empty line.
  // (The trailing empty lines are already trimmed.)
  let codeLines = (code.trimLeft().match(/\n/g) || []).length + 1;

  for (let i = 1 + leadingEmptyLines; i <= codeLines + leadingEmptyLines; i++) {
    sourceMapGenerator.addMapping({
      source: sourceMapOptions.fileName,
      original: {
        line: i,
        column: 0,
      },
      generated: {
        line: i + linesOffset,
        column: 0,
      },
    });
  }

  return sourceMapGenerator.toString();
}

module.exports = {
  surround,
};
<|endoftext|>


<commit_before>/* @flow */
const { execSync } = require(`child_process`)
const execa = require(`execa`)
const fs = require(`fs-extra`)
const sysPath = require(`path`)
const report = require(`./reporter`)
const url = require(`url`)
const os = require('os')
const existsSync = require(`fs-exists-cached`).sync

const spawn = (cmd: string) => {
  const [file, ...args] = cmd.split(/\s+/)
  return execa(file, args, { stdio: `inherit` })
}

// Checks the existence of yarn package
// We use yarnpkg instead of yarn to avoid conflict with Hadoop yarn
// Refer to https://github.com/yarnpkg/yarn/issues/673
//
// Returns true if yarn exists, false otherwise
const shouldUseYarn = () => {
  try {
    execSync(`yarnpkg --version`, { stdio: `ignore` })
    return true
  } catch (e) {
    return false
  }
}

// Executes `npm install` or `yarn install` in rootPath.
const install = async rootPath => {
  const prevDir = process.cwd()

  report.info(`Installing packages...`)
  process.chdir(rootPath)

  try {
    let cmd = shouldUseYarn() ? spawn(`yarnpkg`) : spawn(`npm install`)
    await cmd
  } finally {
    process.chdir(prevDir)
  }

  // changes the project name on package.json, needs improvement

  // const projectDetails = {
  //   name: rootPath,
  //   version: '0.1.0',
  //   private: false,
  // }

  // fs.writeFileSync(
  //   sysPath.join(rootPath, 'package.json'),
  //   JSON.stringify(projectDetails, null, 2) + os.EOL
  // )
}

// Install starter from URI.
const starterInstall = async (src: string, path: string) => {

  await spawn(`git clone https://github.com/${src} ${path} --single-branch`)

  report.success(`Created starter directory layout`)

  await fs.remove(sysPath.join(path, `.git`))

  await install(path)

}

// Get starter by name and runs the starterInstall
const clone = async (starter: string, rootPath: string) => {

  report.info(`Creating new ${starter} project on: ${rootPath}`)

  if (starter === 'cra') {
    await starterInstall('astrocoders/cra-starter', rootPath)
  }

  if (starter === 'gatsby') {
    await starterInstall('astrocoders/gatsby-starter', rootPath)
  }

  if (starter === 'reason') {
    await starterInstall('astrocoders/reasonml-starter', rootPath)
  }

}

type InitOptions = {
  rootPath?: string,
}

/**
 * Main function that clones or copies the cli.
 */
module.exports = async (starter: string, options: InitOptions = {}) => {
  const rootPath = options.rootPath || process.cwd()

  const urlObject = url.parse(rootPath)
  if (urlObject.protocol && urlObject.host) {
    report.panic(
      `It looks like you forgot to add a name for your new project. Try running instead "astro-cli new ${rootPath} [cra|gatsby|reason]"`
    )
    return
  }

  if (existsSync(sysPath.join(rootPath, `package.json`))) {
    report.panic(`Directory ${rootPath} is already an npm project`)
    return
  }

  await clone(starter, rootPath)
}<commit_msg>Update: add package.json project name modifier<commit_after>/* @flow */
const { execSync } = require(`child_process`)
const execa = require(`execa`)
const fs = require(`fs-extra`)
const sysPath = require(`path`)
const report = require(`./reporter`)
const url = require(`url`)
const os = require('os')
const existsSync = require(`fs-exists-cached`).sync

const spawn = (cmd: string) => {
  const [file, ...args] = cmd.split(/\s+/)
  return execa(file, args, { stdio: `inherit` })
}

// Checks the existence of yarn package
// We use yarnpkg instead of yarn to avoid conflict with Hadoop yarn
// Refer to https://github.com/yarnpkg/yarn/issues/673
//
// Returns true if yarn exists, false otherwise
const shouldUseYarn = () => {
  try {
    execSync(`yarnpkg --version`, { stdio: `ignore` })
    return true
  } catch (e) {
    return false
  }
}

// Executes `npm install` or `yarn install` in rootPath.
const install = async rootPath => {
  const prevDir = process.cwd()

  report.info(`Installing packages...`)
  process.chdir(rootPath)

  // changes the project name on package.json, needs improvement

  const json = JSON.parse(fs.readFileSync('package.json'))

  json.name = rootPath

  await fs.writeFileSync(
    sysPath.join('package.json'),
    JSON.stringify(json, null, 2) + os.EOL
  )

  try {
    let cmd = shouldUseYarn() ? spawn(`yarnpkg`) : spawn(`npm install`)
    await cmd
  } finally {
    process.chdir(prevDir)
  }

}

// Install starter from URI.
const starterInstall = async (src: string, path: string) => {

  await spawn(`git clone https://github.com/${src} ${path} --single-branch`)

  report.success(`Created starter directory layout`)

  await fs.remove(sysPath.join(path, `.git`))

  await install(path)

}

// Get starter by name and runs the starterInstall
const clone = async (starter: string, rootPath: string) => {

  report.info(`Creating new ${starter} project on: ${rootPath}`)

  if (starter === 'cra') {
    await starterInstall('astrocoders/cra-starter', rootPath)
  }

  if (starter === 'gatsby') {
    await starterInstall('astrocoders/gatsby-starter', rootPath)
  }

  if (starter === 'reason') {
    await starterInstall('astrocoders/reasonml-starter', rootPath)
  }

}

type InitOptions = {
  rootPath?: string,
}

/**
 * Main function that clones or copies the cli.
 */
module.exports = async (starter: string, options: InitOptions = {}) => {
  const rootPath = options.rootPath || process.cwd()

  const urlObject = url.parse(rootPath)
  if (urlObject.protocol && urlObject.host) {
    report.panic(
      `It looks like you forgot to add a name for your new project. Try running instead "astro-cli new ${rootPath} [cra|gatsby|reason]"`
    )
    return
  }

  if (existsSync(sysPath.join(rootPath, `package.json`))) {
    report.panic(`Directory ${rootPath} is already an npm project`)
    return
  }

  await clone(starter, rootPath)
}<|endoftext|>


<commit_before>/**
 * item and slot component both use similar wrapper
 * we need to know their size change at any time
 */

import Vue from 'vue'
import { ItemProps, SlotProps } from './props'

const Wrapper = {
  created () {
    this.shapeKey = this.horizontal ? 'offsetWidth' : 'offsetHeight'
  },

  mounted () {
    if (typeof ResizeObserver !== 'undefined') {
      this.resizeObserver = new ResizeObserver(() => {
        this.dispatchSizeChange()
      })
      this.resizeObserver.observe(this.$el)
    }
  },

  // since componet will be reused, so disptach when updated
  updated () {
    this.dispatchSizeChange()
  },

  beforeDestroy () {
    if (this.resizeObserver) {
      this.resizeObserver.disconnect()
      this.resizeObserver = null
    }
  },

  methods: {
    getCurrentSize () {
      return this.$el ? this.$el[this.shapeKey] : 0
    },

    // tell parent current size identify by unqiue key
    dispatchSizeChange () {
      this.$parent.$emit(this.event, this.uniqueKey, this.getCurrentSize(), this.hasInitial)
    }
  }
}

// wrapping for item
export const Item = Vue.component('virtual-list-item', {
  mixins: [Wrapper],

  props: ItemProps,

  render (h) {
    const { tag, component, extraProps = {}, index, scopedSlots = {}, uniqueKey } = this
    extraProps.source = this.source
    extraProps.index = index

    return h(tag, {
      key: uniqueKey,
      attrs: {
        role: 'listitem'
      }
    }, [h(component, {
      props: extraProps,
      scopedSlots: scopedSlots
    })])
  }
})

// wrapping for slot
export const Slot = Vue.component('virtual-list-slot', {
  mixins: [Wrapper],

  props: SlotProps,

  render (h) {
    const { tag, uniqueKey } = this

    return h(tag, {
      key: uniqueKey,
      attrs: {
        role: uniqueKey
      }
    }, this.$slots.default)
  }
})
<commit_msg>fix: extraProps mutation in item render<commit_after>/**
 * item and slot component both use similar wrapper
 * we need to know their size change at any time
 */

import Vue from 'vue'
import { ItemProps, SlotProps } from './props'

const Wrapper = {
  created () {
    this.shapeKey = this.horizontal ? 'offsetWidth' : 'offsetHeight'
  },

  mounted () {
    if (typeof ResizeObserver !== 'undefined') {
      this.resizeObserver = new ResizeObserver(() => {
        this.dispatchSizeChange()
      })
      this.resizeObserver.observe(this.$el)
    }
  },

  // since componet will be reused, so disptach when updated
  updated () {
    this.dispatchSizeChange()
  },

  beforeDestroy () {
    if (this.resizeObserver) {
      this.resizeObserver.disconnect()
      this.resizeObserver = null
    }
  },

  methods: {
    getCurrentSize () {
      return this.$el ? this.$el[this.shapeKey] : 0
    },

    // tell parent current size identify by unqiue key
    dispatchSizeChange () {
      this.$parent.$emit(this.event, this.uniqueKey, this.getCurrentSize(), this.hasInitial)
    }
  }
}

// wrapping for item
export const Item = Vue.component('virtual-list-item', {
  mixins: [Wrapper],

  props: ItemProps,

  render (h) {
    const { tag, component, extraProps = {}, index, source, scopedSlots = {}, uniqueKey } = this;
    const props = {
        ...extraProps,
        source,
        index,
    };

    return h(tag, {
      key: uniqueKey,
      attrs: {
        role: 'listitem'
      }
    }, [h(component, {
      props,
      scopedSlots: scopedSlots
    })])
  }
})

// wrapping for slot
export const Slot = Vue.component('virtual-list-slot', {
  mixins: [Wrapper],

  props: SlotProps,

  render (h) {
    const { tag, uniqueKey } = this

    return h(tag, {
      key: uniqueKey,
      attrs: {
        role: uniqueKey
      }
    }, this.$slots.default)
  }
})
<|endoftext|>


<commit_before>'use strict'

var Base, Item, Rule;

Base = require('base');
Rule = require('./rule');

Item = Base.extend({
    attrs : {
        name : '',
        rule : '',
        element : '',
        showMessage : noop,
        hideMessage : noop,
        triggerType : 'submit'
    },
    init : function(){
        var ctx, rules, element;

        ctx = this;
        this.tasks = [];
        element = this.get('element');
        rules = parseRules(this.get('rule'));

        if(rules){
            if(!$.isArray(rules)){
                throw new Error('No validation rule specified or not specified as an array.');
            }

            $.each(rules, function(index, rule){
                var ruleOperator;

                rule = parseRule(rule);
                ruleOperator = Rule.getOperator(rule.name);

                if(!ruleOperator){
                    throw new Error('Validation rule with name "' + rule.name + '" cannot be found.');
                }

                ctx.tasks.push({
                    name : rule.name,
                    ruleOperator : ruleOperator,
                    param : $.extend({}, rule.param, {
                        element : element
                    })
                });
            });
        }

        this.behavior();
    },
    behavior : function(){
        var ctx = this;

        if(this.get('triggerType') === 'blur'){
            this.get('element').parent('form').on('blur.validator', '[name=' + this.get('name') + ']', function(e){
                e.preventDefault();
                ctx.execute();
            });
        }
    },
    execute : function(){
        var pass, ruleName, element;

        pass = true;
        element = this.get('element');

        $.each(this.tasks, function(index, task){
            ruleName = task.name;

            if(!(pass = task.ruleOperator(task.param))){
                return false;
            }
        });

        this.get(pass ? 'hideMessage' : 'showMessage')(element, ruleName);

        return pass;
    },
    destroy : function(){
        this.get('hideMessage')(this.get('element'), null);

        if(this.get('triggerType') === 'blur'){
            this.get('element').parent('form').off('blur.validator', '[name=' + this.get('name') + ']');
        }

        Item.superclass.destroy.call(this);
    }
});

function parseRule(str){
    var match = str.match(/([^{}:\s]*)(\{[^\{\}]*\})?/);

    return {
        name : match[1],
        param : parseJSON(match[2])
    }
};

function parseRules(str){
    if(!str){
        return null;
    }

    return str.match(/[a-zA-Z0-9\-\_]+(\{[^\{\}]*\})?/g);
};

function parseJSON(str){
    var NOTICE, result, arr, index, key, value, tmp;

    if(!str){
        return null;
    }

    NOTICE = 'Invalid option object "' + str + '".';

    result = {};
    arr = str.slice(1, -1).split(',');

    for(index = arr.length - 1; index >= 0; index--){
        arr[index] = $.trim(arr[index]);

        if(!arr[index]){
            throw new Error(NOTICE);
        }

        tmp = arr[index].split(':');
        key = $.trim(tmp[0]);
        value = $.trim(tmp[1]);

        if(!key || !value){
            throw new Error(NOTICE);
        }

        result[getValue(key)] = $.trim(getValue(value));
    }

    return result;
};

function getValue(str){
    if(str.charAt(0) == '"' && str.charAt(str.length - 1) == '"' ||
        str.charAt(0) == "'" && str.charAt(str.length - 1) == "'"){
        return eval(str);
    }

    return str;
};

function noop(){};

module.exports = Item;<commit_msg>add skipHidden attr<commit_after>'use strict'

var Base, Item, Rule;

Base = require('base');
Rule = require('./rule');

Item = Base.extend({
    attrs : {
        name : '',
        rule : '',
        element : '',
        showMessage : noop,
        hideMessage : noop,
        skipHidden : false,
        triggerType : 'submit'
    },
    init : function(){
        var ctx, rules, element;

        ctx = this;
        this.tasks = [];
        element = this.get('element');
        rules = parseRules(this.get('rule'));

        if(rules){
            if(!$.isArray(rules)){
                throw new Error('No validation rule specified or not specified as an array.');
            }

            $.each(rules, function(index, rule){
                var ruleOperator;

                rule = parseRule(rule);
                ruleOperator = Rule.getOperator(rule.name);

                if(!ruleOperator){
                    throw new Error('Validation rule with name "' + rule.name + '" cannot be found.');
                }

                ctx.tasks.push({
                    name : rule.name,
                    ruleOperator : ruleOperator,
                    param : $.extend({}, rule.param, {
                        element : element
                    })
                });
            });
        }

        this.behavior();
    },
    behavior : function(){
        var ctx = this;

        if(this.get('triggerType') === 'blur'){
            this.get('element').parent('form').on('blur.validator', '[name=' + this.get('name') + ']', function(e){
                e.preventDefault();
                ctx.execute();
            });
        }
    },
    execute : function(){
        var pass, ruleName, element;

        pass = true;
        element = this.get('element');

        $.each(this.tasks, function(index, task){
            ruleName = task.name;

            if(!(pass = task.ruleOperator(task.param))){
                return false;
            }
        });

        if(this.get('skipHidden') && !element.is(':visible')){
            pass = true;
        }

        this.get(pass ? 'hideMessage' : 'showMessage')(element, ruleName);

        return pass;
    },
    destroy : function(){
        this.get('hideMessage')(this.get('element'), null);

        if(this.get('triggerType') === 'blur'){
            this.get('element').parent('form').off('blur.validator', '[name=' + this.get('name') + ']');
        }

        Item.superclass.destroy.call(this);
    }
});

function parseRule(str){
    var match = str.match(/([^{}:\s]*)(\{[^\{\}]*\})?/);

    return {
        name : match[1],
        param : parseJSON(match[2])
    }
};

function parseRules(str){
    if(!str){
        return null;
    }

    return str.match(/[a-zA-Z0-9\-\_]+(\{[^\{\}]*\})?/g);
};

function parseJSON(str){
    var NOTICE, result, arr, index, key, value, tmp;

    if(!str){
        return null;
    }

    NOTICE = 'Invalid option object "' + str + '".';

    result = {};
    arr = str.slice(1, -1).split(',');

    for(index = arr.length - 1; index >= 0; index--){
        arr[index] = $.trim(arr[index]);

        if(!arr[index]){
            throw new Error(NOTICE);
        }

        tmp = arr[index].split(':');
        key = $.trim(tmp[0]);
        value = $.trim(tmp[1]);

        if(!key || !value){
            throw new Error(NOTICE);
        }

        result[getValue(key)] = $.trim(getValue(value));
    }

    return result;
};

function getValue(str){
    if(str.charAt(0) == '"' && str.charAt(str.length - 1) == '"' ||
        str.charAt(0) == "'" && str.charAt(str.length - 1) == "'"){
        return eval(str);
    }

    return str;
};

function noop(){};

module.exports = Item;
<|endoftext|>


<commit_before>module.exports = {
    'jest/consistent-test-it': [
        'error',
        {
            fn: 'test',
            withinDescribe: 'test'
        }
    ],
    'jest/no-alias-methods': 'error',
    'jest/no-commented-out-tests': 'error',
    'jest/no-disabled-tests': 'error',
    'jest/no-duplicate-hooks': 'error',
    'jest/no-empty-title': 'error',
    'jest/no-expect-resolves': 'error',
    'jest/no-focused-tests': 'error',
    'jest/no-identical-title': 'error',
    'jest/no-if': 'error',
    'jest/no-jest-import': 'error',
    'jest/no-mocks-import': 'error',
    'jest/no-standalone-expect': 'error',
    'jest/no-test-callback': 'error',
    'jest/no-test-prefixes': 'error',
    'jest/no-test-return-statement': 'error',
    'jest/no-truthy-falsy': 'error',
    'jest/no-try-expect': 'error',
    'jest/prefer-called-with': 'error',
    'jest/prefer-spy-on': 'error',
    'jest/prefer-strict-equal': 'error',
    'jest/prefer-to-be-null': 'error',
    'jest/prefer-to-be-undefined': 'error',
    'jest/prefer-to-contain': 'error',
    'jest/prefer-to-have-length': 'error',
    'jest/prefer-todo': 'error',
    'jest/require-tothrow-message': 'error',
    'jest/valid-describe': 'error',
    'jest/valid-expect': 'error'
};
<commit_msg>Adds `alwaysAwait: true` option to `jest/valid-expect` rule.<commit_after>module.exports = {
    'jest/consistent-test-it': [
        'error',
        {
            fn: 'test',
            withinDescribe: 'test'
        }
    ],
    'jest/no-alias-methods': 'error',
    'jest/no-commented-out-tests': 'error',
    'jest/no-disabled-tests': 'error',
    'jest/no-duplicate-hooks': 'error',
    'jest/no-empty-title': 'error',
    'jest/no-expect-resolves': 'error',
    'jest/no-focused-tests': 'error',
    'jest/no-identical-title': 'error',
    'jest/no-if': 'error',
    'jest/no-jest-import': 'error',
    'jest/no-mocks-import': 'error',
    'jest/no-standalone-expect': 'error',
    'jest/no-test-callback': 'error',
    'jest/no-test-prefixes': 'error',
    'jest/no-test-return-statement': 'error',
    'jest/no-truthy-falsy': 'error',
    'jest/no-try-expect': 'error',
    'jest/prefer-called-with': 'error',
    'jest/prefer-spy-on': 'error',
    'jest/prefer-strict-equal': 'error',
    'jest/prefer-to-be-null': 'error',
    'jest/prefer-to-be-undefined': 'error',
    'jest/prefer-to-contain': 'error',
    'jest/prefer-to-have-length': 'error',
    'jest/prefer-todo': 'error',
    'jest/require-tothrow-message': 'error',
    'jest/valid-describe': 'error',
    'jest/valid-expect': [
        'error',
        {
            alwaysAwait: true
        }
    ]
};
<|endoftext|>


<commit_before>/** @license
 * RequireJS plugin for loading JSON files
 * - depends on Text plugin and it was HEAVILY "inspired" by it as well.
 * Author: Miller Medeiros
 * Version: 0.3.1 (2013/02/04)
 * Released under the MIT license
 */
define(['text'], function(text){

    var CACHE_BUST_QUERY_PARAM = 'bust',
        CACHE_BUST_FLAG = '!bust',
        jsonParse = (typeof JSON !== 'undefined' && typeof JSON.parse === 'function')? JSON.parse : function(val){
            return eval('('+ val +')'); //quick and dirty
        },
        buildMap = {};

    function cacheBust(url){
        url = url.replace(CACHE_BUST_FLAG, '');
        url += (url.indexOf('?') < 0)? '?' : '&';
        return url + CACHE_BUST_QUERY_PARAM +'='+ Math.round(2147483647 * Math.random());
    }

    //API
    return {

        load : function(name, req, onLoad, config) {
            if ( config.isBuild && (config.inlineJSON === false || name.indexOf(CACHE_BUST_QUERY_PARAM +'=') !== -1) ) {
                //avoid inlining cache busted JSON or if inlineJSON:false
                onLoad(null);
            } else {
                text.get(req.toUrl(name), function(data){
                    if (config.isBuild) {
                        buildMap[name] = data;
                        onLoad(data);
                    } else {
                        onLoad(jsonParse(data));
                    }
                },
                    onLoad.error, {
                        accept: 'application/json'
                    }
                );
            }
        },

        normalize : function (name, normalize) {
            //used normalize to avoid caching references to a "cache busted" request
            return (name.indexOf(CACHE_BUST_FLAG) === -1)? name : cacheBust(name);
        },

        //write method based on RequireJS official text plugin by James Burke
        //https://github.com/jrburke/requirejs/blob/master/text.js
        write : function(pluginName, moduleName, write){
            if(moduleName in buildMap){
                var content = buildMap[moduleName];
                write('define("'+ pluginName +'!'+ moduleName +'", function(){ return '+ content +';});\n');
            }
        }

    };
});
<commit_msg>Make loading add ".json" if missing from path<commit_after>/** @license
 * RequireJS plugin for loading JSON files
 * - depends on Text plugin and it was HEAVILY "inspired" by it as well.
 * Author: Miller Medeiros
 * Version: 0.3.1 (2013/02/04)
 * Released under the MIT license
 */
define(['text'], function(text){

    var CACHE_BUST_QUERY_PARAM = 'bust',
        CACHE_BUST_FLAG = '!bust',
        jsonParse = (typeof JSON !== 'undefined' && typeof JSON.parse === 'function')? JSON.parse : function(val){
            return eval('('+ val +')'); //quick and dirty
        },
        buildMap = {};

    function cacheBust(url){
        url = url.replace(CACHE_BUST_FLAG, '');
        url += (url.indexOf('?') < 0)? '?' : '&';
        return url + CACHE_BUST_QUERY_PARAM +'='+ Math.round(2147483647 * Math.random());
    }

    //API
    return {

        load : function(name, req, onLoad, config) {
            // Make sure file part of url ends with .json, add it if not
            name = name.replace(new RegExp("^[^?]*"),function(base){
                return base.substr(-5) === ".json" ? base : base+".json";
            });
            if ( config.isBuild && (config.inlineJSON === false || name.indexOf(CACHE_BUST_QUERY_PARAM +'=') !== -1) ) {
                //avoid inlining cache busted JSON or if inlineJSON:false
                onLoad(null);
            } else {
                text.get(req.toUrl(name), function(data){
                    if (config.isBuild) {
                        buildMap[name] = data;
                        onLoad(data);
                    } else {
                        onLoad(jsonParse(data));
                    }
                },
                    onLoad.error, {
                        accept: 'application/json'
                    }
                );
            }
        },

        normalize : function (name, normalize) {
            //used normalize to avoid caching references to a "cache busted" request
            return (name.indexOf(CACHE_BUST_FLAG) === -1)? name : cacheBust(name);
        },

        //write method based on RequireJS official text plugin by James Burke
        //https://github.com/jrburke/requirejs/blob/master/text.js
        write : function(pluginName, moduleName, write){
            if(moduleName in buildMap){
                var content = buildMap[moduleName];
                write('define("'+ pluginName +'!'+ moduleName +'", function(){ return '+ content +';});\n');
            }
        }

    };
});
<|endoftext|>


<commit_before>"use strict";

var log = require('winston');
var pluralize = require('pluralize');

class Model {

	// Standard constructor
	constructor(useDefaults) {
		// Properties stores the actual data for the schema
		this.properties = {};

		var schema = this.constructor.schema;

		// Initialize the various properties
		Object.keys(schema).forEach((key) => {
			// Insert any defaults if necessary
			var defaultValue = schema[key].defaultValue;

			// If a function is provided as a default, call the function
			if (defaultValue) {
				if (typeof defaultValue === "function") {
					this.properties[key] = defaultValue();
				} else {
					this.properties[key] = defaultValue;
				}
			}

			// Create accessors for the properties on the main class
			if (this.key !== undefined) {
				log.warn(`${key} is already defined in model ${this.constructor.name}. Be sure to access it through ${this.constructor.name}.properties.${key}.`);
			} else {
				Object.defineProperty(this, key, {
					get: () => this.properties[key],
					set: (newValue) => { this.properties[key] = newValue; }
				});
			}
		});
	}

	/**
	 * Find a particular record by id, if an id is specified
	 * @param id	a unique id for the object
	 * @return a Query object
	 */
	static findById(id) {
		// TODO: Implement findById
	}

	/**
	 * Find all records in a specific table
	 * @return a Query object
	 */
	static findAll() {
		// TODO: Implement findAll
	}

	/**
	 * Creation class methods
	 */

	/**
	 * Create a new record in the database.
	 * @param properties	a JS object of properties for the object
	 * @return an Operation object
	 */
	static create(properties) {
		// TODO: implement create
	}

	/**
	 * If a record exists in the database, update it.
	 * If the record does not exist, create a new one.
	 * @param properties	a JS object of properties for the object
	 * @return an Operation object
	 */
	static createOrUpdate(properties) {
		// TODO: implement createOrUpdate
	}

	/**
	 * Creation instance methods
	 */

	/**
	 * Create a new record in the database.
	 * @return an Operation object
	 */
	create() {
		// TODO: implement create
	}

	/**
	 * If a record exists in the database, update it.
	 * If the record does not exist, create a new one.
	 * @return an Operation object
	 */
	createOrUpdate() {
		// TODO: implement createOrUpdate
	}

	/**
	 * Update methods
	 */

	/**
	 * Push any updates made to the object to the database
	 * @return an Operation object
	 */
	update() {
		// TODO: implement update
	}

	/**
	 * Delete an object from the database
	 * @return an Operation object
	 */
	delete() {
		// TODO: implement delete
	}

	/**
	 * Utility methods
	 */

	/**
	 * Get the name that should represent this model in the database
	 * @return the name of the table as a string
	 */
	static get tableName() {
		// Lazy-load the table name
		delete this.tableName;

		if (typeof this.options.tableName === "string") {
			return this.tableName = this.options.tableName;
		}

		return this.tableName = pluralize(this.name).toLowerCase();
	}
}

/**
 * A set of global options for the model.
 * Should NOT be modified at runtime
 */
Model.options = {
	// If true, the rows will only be marked deleted instead of actually removed
	safeDelete:	true,

	// Automatically add timestamps for update and creation times
	timestamp: true,

	// The name of the table in the database
	// If not set, the name will be automatically generated
	tableName: undefined,
};

/**
 * The schema for the data model
 * Represented as a JS object where the property name is the key,
 * and the value is the type from DataTypes
 *
 * Alternatively, the value can be an object with the following options:
 * dataType: the type from DataTypes
 * defaultValue: the default value of the field
 * validator: a special validation function for this field (returns false if bad)
 */
Model.schema = {};

module.exports = Model;<commit_msg>Made inserting defaults an option for creating models, defaulting to off<commit_after>"use strict";

var log = require('winston');
var pluralize = require('pluralize');

class Model {

	// Standard constructor
	constructor(useDefaults) {
		// Properties stores the actual data for the schema
		this.properties = {};

		var schema = this.constructor.schema;

		// Initialize the various properties
		Object.keys(schema).forEach((key) => {

			if (useDefaults) {
				// Insert any defaults if necessary
				var defaultValue = schema[key].defaultValue;

				// If a function is provided as a default, call the function
				if (defaultValue) {
					if (typeof defaultValue === "function") {
						this.properties[key] = defaultValue();
					} else {
						this.properties[key] = defaultValue;
					}
				}
			}

			// Create accessors for the properties on the main class
			if (this.key !== undefined) {
				log.warn(`${key} is already defined in model ${this.constructor.name}. Be sure to access it through ${this.constructor.name}.properties.${key}.`);
			} else {
				Object.defineProperty(this, key, {
					get: () => this.properties[key],
					set: (newValue) => { this.properties[key] = newValue; }
				});
			}
		});
	}

	/**
	 * Find a particular record by id, if an id is specified
	 * @param id	a unique id for the object
	 * @return a Query object
	 */
	static findById(id) {
		// TODO: Implement findById
	}

	/**
	 * Find all records in a specific table
	 * @return a Query object
	 */
	static findAll() {
		// TODO: Implement findAll
	}

	/**
	 * Creation class methods
	 */

	/**
	 * Create a new record in the database.
	 * @param properties	a JS object of properties for the object
	 * @return an Operation object
	 */
	static create(properties) {
		// TODO: implement create
	}

	/**
	 * If a record exists in the database, update it.
	 * If the record does not exist, create a new one.
	 * @param properties	a JS object of properties for the object
	 * @return an Operation object
	 */
	static createOrUpdate(properties) {
		// TODO: implement createOrUpdate
	}

	/**
	 * Creation instance methods
	 */

	/**
	 * Create a new record in the database.
	 * @return an Operation object
	 */
	create() {
		// TODO: implement create
	}

	/**
	 * If a record exists in the database, update it.
	 * If the record does not exist, create a new one.
	 * @return an Operation object
	 */
	createOrUpdate() {
		// TODO: implement createOrUpdate
	}

	/**
	 * Update methods
	 */

	/**
	 * Push any updates made to the object to the database
	 * @return an Operation object
	 */
	update() {
		// TODO: implement update
	}

	/**
	 * Delete an object from the database
	 * @return an Operation object
	 */
	delete() {
		// TODO: implement delete
	}

	/**
	 * Utility methods
	 */

	/**
	 * Get the name that should represent this model in the database
	 * @return the name of the table as a string
	 */
	static get tableName() {
		// Lazy-load the table name
		delete this.tableName;

		if (typeof this.options.tableName === "string") {
			return this.tableName = this.options.tableName;
		}

		return this.tableName = pluralize(this.name).toLowerCase();
	}
}

/**
 * A set of global options for the model.
 * Should NOT be modified at runtime
 */
Model.options = {
	// If true, the rows will only be marked deleted instead of actually removed
	safeDelete:	true,

	// Automatically add timestamps for update and creation times
	timestamp: true,

	// The name of the table in the database
	// If not set, the name will be automatically generated
	tableName: undefined,
};

/**
 * The schema for the data model
 * Represented as a JS object where the property name is the key,
 * and the value is the type from DataTypes
 *
 * Alternatively, the value can be an object with the following options:
 * dataType: the type from DataTypes
 * defaultValue: the default value of the field
 * validator: a special validation function for this field (returns false if bad)
 */
Model.schema = {};

module.exports = Model;<|endoftext|>


<commit_before>var log = require('./helpers/log.js')
var exec = require('exec-sh')

module.exports = function () {
  var command = 'NODE_ENV=development $(npm bin)/snazzy {src,tests,.}/*.js --parser babel-eslint'

  log.info('Running lint')
  exec(command, function (err) {
    if (err) process.exit(1)
    log.success('Code looks good!')
  })
}
<commit_msg>Include subfolders when linting<commit_after>var log = require('./helpers/log.js')
var exec = require('exec-sh')

module.exports = function () {
  var command = 'NODE_ENV=development $(npm bin)/snazzy {src,tests,.}/**/*.js --parser babel-eslint'

  log.info('Running lint')
  exec(command, function (err) {
    if (err) process.exit(1)
    log.success('Code looks good!')
  })
}
<|endoftext|>


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

function run(pattern, callback) {
    glob(pattern, {}, function (err, files) {
        callback(err, files);
    });
}

module.exports = {
    run: run
}

if (require.main === module) (function startFromCLI() {
    var plugins = ['./plugins/SizePlugin', './plugins/LOCPlugin.js'].map(require);

    function analyzeFiles (files) {
        function getDataFromPlugins(plugins) {
            return plugins.map(function (plugin) {
                var res = plugin.readFiles(fs, files);
                console.log("Data from plugin ",plugin.name, ": ", JSON.stringify(res, null, 2), "\n");
                return res;
            });
        }

        function mergeDataFromPlugins(dataFromPlugins) {
            return dataFromPlugins.reduce(function (result, dataFromPlugin) {
                return dataFromPlugin.reduce(function (result, fileData) {
                    var dict = result[fileData.file] || (result[fileData.file] = {});
                    _.assign(dict, fileData);
                    return result;
                }, result);
            }, {});
        }

        return mergeDataFromPlugins(getDataFromPlugins(plugins));

    }

    run("mocks/**/*.js", function (err, files) {
        var data = analyzeFiles(files);
        console.log("Output data: ", JSON.stringify(data, null, 2));
    });
})();
<commit_msg>refactor more: move code to Lupa object<commit_after>var glob = require('glob');
var fs = require('fs');
var _ = require('lodash');

var plugins_ = ['./plugins/SizePlugin', './plugins/LOCPlugin.js'].map(require);

var lupa = module.exports = {
    run: function run(pattern, plugins, callback) {
        var lupa = this;
        glob(pattern, {}, function (err, files) {
            var data = lupa.analyzeFiles(files, plugins);
            callback(err, data);
        });
    },
    analyzeFiles: function analyzeFiles (files, plugins) {
        function getDataFromPlugins(plugins) {
            return plugins.map(function (plugin) {
                var res = plugin.readFiles(fs, files);
                console.log("Data from plugin ",plugin.name, ": ", JSON.stringify(res, null, 2), "\n");
                return res;
            });
        }

        function mergeDataFromPlugins(dataFromPlugins) {
            return dataFromPlugins.reduce(function (result, dataFromPlugin) {
                return dataFromPlugin.reduce(function (result, fileData) {
                    var dict = result[fileData.file] || (result[fileData.file] = {});
                    _.assign(dict, fileData);
                    return result;
                }, result);
            }, {});
        }

        return mergeDataFromPlugins(getDataFromPlugins(plugins));
    }

}

if (require.main === module) (function startFromCLI() {

    lupa.run("mocks/**/*.js", plugins_, function (err, data) {
        console.log("Output data: ", JSON.stringify(data, null, 2));
    });
})();
<|endoftext|>


<commit_before>'use strict';

var noe = require('nr-of-episodes');
var notification = require('./notifications');
var list = require('./list');

list(function(e, data) {
  data = data.filter(function(show) {
    return show.stillWatching;
  });

  setInterval(function(){
    data.forEach(checkShow);
  }, 2000);
});

var checked = [];
var checkShow = function(show) {
  if (checked.indexOf(show.title) === -1) {
    noe(show.title, function(e, d) {
      if (d && !e && d > show.episodes) {
        notification(show.title);
        checked.push(show.title);
      }
    });
  }
}
<commit_msg>:older_man: lint fixes<commit_after>'use strict';

var noe = require('nr-of-episodes');
var notification = require('./notifications');
var list = require('./list');

list(function(e, data) {
  data = data.filter(function(show) {
    return show.stillWatching;
  });

  setInterval(function(){
    data.forEach(checkShow);
  }, 2000);
});

var checked = [];
var checkShow = function(show) {
  if (checked.indexOf(show.title) === -1) {
    noe(show.title, function(e, d) {
      if (d && !e && d > show.episodes) {
        notification(show.title);
        checked.push(show.title);
      }
    });
  }
};
<|endoftext|>


<commit_before>// HumanizeDuration.js - http://git.io/j0HgmQ

(function() {

  var UNITS = {
    year: 31557600000,
    month: 2629800000,
    week: 604800000,
    day: 86400000,
    hour: 3600000,
    minute: 60000,
    second: 1000,
    millisecond: 1
  };

  var languages = {
    ca: {
      year: function(c) { return "any" + ((c !== 1) ? "s" : ""); },
      month: function(c) { return "mes" + ((c !== 1) ? "os" : ""); },
      week: function(c) { return "setman" + ((c !== 1) ? "es" :"a"); },
      day: function(c) { return "di" + ((c !== 1) ? "es" :"a"); },
      hour: function(c) { return "hor" + ((c !== 1) ? "es" :"a"); },
      minute: function(c) { return "minut" + ((c !== 1) ? "s" : ""); },
      second: function(c) { return "segon" + ((c !== 1) ? "s" : ""); },
      millisecond: function(c) { return "milisegon" + ((c !== 1) ? "s" : "" ); }
    },
    da: {
      year: "år",
      month: function(c) { return "måned" + ((c !== 1) ? "er" : ""); },
      week: function(c) { return "uge" + ((c !== 1) ? "r" : ""); },
      day: function(c) { return "dag" + ((c !== 1) ? "e" : ""); },
      hour: function(c) { return "time" + ((c !== 1) ? "r" : ""); },
      minute: function(c) { return "minut" + ((c !== 1) ? "ter" : ""); },
      second: function(c) { return "sekund" + ((c !== 1) ? "er" : ""); },
      millisecond: function(c) { return "millisekund" + ((c !== 1) ? "er" : ""); }
    },
    de: {
      year: function(c) { return "jahr" + ((c !== 1) ? "e" : ""); },
      month: function(c) { return "monat" + ((c !== 1) ? "e" : ""); },
      week: function(c) { return "woche" + ((c !== 1) ? "n" : ""); },
      day: function(c) { return "tag" + ((c !== 1) ? "e" : ""); },
      hour: function(c) { return "stunde" + ((c !== 1) ? "n" : ""); },
      minute: function(c) { return "minute" + ((c !== 1) ? "n" : ""); },
      second: function(c) { return "sekunde" + ((c !== 1) ? "n" : ""); },
      millisecond: function(c) { return "millisekunde" + ((c !== 1) ? "n" : ""); }
    },
    en: {
      year: function(c) { return "year" + ((c !== 1) ? "s" : ""); },
      month: function(c) { return "month" + ((c !== 1) ? "s" : ""); },
      week: function(c) { return "week" + ((c !== 1) ? "s" : ""); },
      day: function(c) { return "day" + ((c !== 1) ? "s" : ""); },
      hour: function(c) { return "hour" + ((c !== 1) ? "s" : ""); },
      minute: function(c) { return "minute" + ((c !== 1) ? "s" : ""); },
      second: function(c) { return "second" + ((c !== 1) ? "s" : ""); },
      millisecond: function(c) { return "millisecond" + ((c !== 1) ? "s" : ""); }
    },
    nl: {
      year: "jaar",
      month: function(c) { return (c === 1) ? "maand" : "maanden"; },
      week: function(c) { return (c === 1) ? "week" : "weken"; },
      day: function(c) { return (c === 1) ? "dag" : "dagen"; },
      hour: "uur",
      minute: function(c) { return (c === 1) ? "minuut" : "minuten"; },
      second: function(c) { return (c === 1) ? "seconde" : "seconden"; },
      millisecond: function(c) { return (c === 1) ? "milliseconde" : "milliseconden"; }
    },
    es: {
      year: function(c) { return "año" + ((c !== 1) ? "s" : ""); },
      month: function(c) { return "mes" + ((c !== 1) ? "es" : ""); },
      week: function(c) { return "semana" + ((c !== 1) ? "s" : ""); },
      day: function(c) { return "día" + ((c !== 1) ? "s" : ""); },
      hour: function(c) { return "hora" + ((c !== 1) ? "s" : ""); },
      minute: function(c) { return "minuto" + ((c !== 1) ? "s" : ""); },
      second: function(c) { return "segundo" + ((c !== 1) ? "s" : ""); },
      millisecond: function(c) { return "milisegundo" + ((c !== 1) ? "s" : "" ); }
    },
    fr: {
      year: function(c) { return "an" + ((c !== 1) ? "s" : ""); },
      month: "mois",
      week: function(c) { return "semaine" + ((c !== 1) ? "s" : ""); },
      day: function(c) { return "jour" + ((c !== 1) ? "s" : ""); },
      hour: function(c) { return "heure" + ((c !== 1) ? "s" : ""); },
      minute: function(c) { return "minute" + ((c !== 1) ? "s" : ""); },
      second: function(c) { return "seconde" + ((c !== 1) ? "s" : ""); },
      millisecond: function(c) { return "milliseconde" + ((c !== 1) ? "s" : ""); }
    },
    ko: {
      year: "년",
      month: "개월",
      week: "주일",
      day: "일",
      hour: "시간",
      minute: "분",
      second: "초",
      millisecond: "밀리 초"
    },
    nob: {
      year: "år",
      month: function(c) { return "måned" + ((c !== 1) ? "er" : ""); },
      week: function(c) { return "uke" + ((c !== 1) ? "r" : ""); },
      day: function(c) { return "dag" + ((c !== 1) ? "er" : ""); },
      hour: function(c) { return "time" + ((c !== 1) ? "r" : ""); },
      minute: function(c) { return "minutt" + ((c !== 1) ? "er" : ""); },
      second: function(c) { return "sekund" + ((c !== 1) ? "er" : ""); },
      millisecond: function(c) { return "millisekund" + ((c !== 1) ? "er" : ""); }
    },
    pl: {
      year: function(c) { return ["rok", "roku", "lata", "lat"][getPolishForm(c)]; },
      month: function(c) { return ["miesiąc", "miesiąca", "miesiące", "miesięcy"][getPolishForm(c)]; },
      week: function(c) { return ["tydzień", "tygodnia", "tygodnie", "tygodni"][getPolishForm(c)]; },
      day: function(c) { return ["dzień", "dnia", "dni", "dni"][getPolishForm(c)]; },
      hour: function(c) { return ["godzina", "godziny", "godziny", "godzin"][getPolishForm(c)]; },
      minute: function(c) { return ["minuta", "minuty", "minuty", "minut"][getPolishForm(c)]; },
      second: function(c) { return ["sekunda", "sekundy", "sekundy", "sekund"][getPolishForm(c)]; },
      millisecond: function(c) { return ["milisekunda", "milisekundy", "milisekundy", "milisekund"][getPolishForm(c)]; }
    },
    pt: {
      year: function(c) { return "ano" + ((c !== 1) ? "s" : ""); },
      month: function(c) { return (c !== 1) ? "meses" : "mês"; },
      week: function(c) { return "semana" + ((c !== 1) ? "s" : ""); },
      day: function(c) { return "dia" + ((c !== 1) ? "s" : ""); },
      hour: function(c) { return "hora" + ((c !== 1) ? "s" : ""); },
      minute: function(c) { return "minuto" + ((c !== 1) ? "s" : ""); },
      second: function(c) { return "segundo" + ((c !== 1) ? "s" : ""); },
      millisecond: function(c) { return "milissegundo" + ((c !== 1) ? "s" : ""); }
    },
    ru: {
      year: function(c) { return ["лет", "год", "года"][getRussianForm(c)]; },
      month: function(c) { return ["месяцев", "месяц", "месяца"][getRussianForm(c)]; },
      week: function(c) { return ["недель", "неделя", "недели"][getRussianForm(c)]; },
      day: function(c) { return ["дней", "день", "дня"][getRussianForm(c)]; },
      hour: function(c) { return ["часов", "час", "часа"][getRussianForm(c)]; },
      minute: function(c) { return ["минут", "минута", "минуты"][getRussianForm(c)]; },
      second: function(c) { return ["секунд", "секунда", "секунды"][getRussianForm(c)]; },
      millisecond: function(c) { return ["миллисекунд", "миллисекунда", "миллисекунды"][getRussianForm(c)]; }
    },
    tr: {
      year: "yıl",
      month: "ay",
      week: "hafta",
      day: "gün",
      hour: "saat",
      minute: "dakika",
      second: "saniye",
      millisecond: "milisaniye"
    },
    "zh-CN": {
      year: "年",
      month: "个月",
      week: "周",
      day: "天",
      hour: "小时",
      minute: "分钟",
      second: "秒",
      millisecond: "毫秒"
    },
    "zh-TW": {
      year: "年",
      month: "個月",
      week: "周",
      day: "天",
      hour: "小時",
      minute: "分鐘",
      second: "秒",
      millisecond: "毫秒"
    },
    ja: {
      year: "年",
      month: "月",
      week: "週",
      day: "日",
      hour: "時間",
      minute: "分",
      second: "秒",
      millisecond: "ミリ秒"
    }
  };

  // You can create a humanizer, which returns a function with defaults
  // parameters.
  function humanizer(passedOptions) {

    var result = function humanizer(ms, passedOptions) {
      var options = extend({}, result, passedOptions || {});
      return doHumanization(ms, options);
    };

    extend(result, {
      language: "en",
      delimiter: ", ",
      units: [
        "year",
        "month",
        "week",
        "day",
        "hour",
        "minute",
        "second"
      ],
      languages: {}
    }, passedOptions);

    return result;

  }

  // The main function is just a wrapper around a default humanizer.
  var defaultHumanizer = humanizer({});
  function humanizeDuration(ms, passedOptions) {
    return defaultHumanizer(ms, passedOptions);
  }

  // doHumanization does the bulk of the work.
  function doHumanization(ms, options) {

    // Make sure we have a positive number.
    // Has the nice sideffect of turning Number objects into primitives.
    ms = Math.abs(ms);

    if (ms === 0) {
      return "0";
    }

    var dictionary = options.languages[options.language] || languages[options.language];
    if (!dictionary) {
      throw new Error("No language " + dictionary + ".");
    }

    var result = [];

    // Start at the top and keep removing units, bit by bit.
    var unitName, unitMS, unitCount, mightBeHalfUnit;
    for (var i = 0, len = options.units.length; i < len; i ++) {

      unitName = options.units[i];
      if (unitName[unitName.length - 1] === "s") { // strip plurals
        unitName = unitName.substring(0, unitName.length - 1);
      }
      unitMS = UNITS[unitName];

      // If it's a half-unit interval, we're done.
      if (result.length === 0) {
        mightBeHalfUnit = (ms / unitMS) * 2;
        if (mightBeHalfUnit === Math.floor(mightBeHalfUnit)) {
          return render(mightBeHalfUnit / 2, unitName, dictionary);
        }
      }

      // What's the number of full units we can fit?
      if ((i + 1) === len) {
        unitCount = ms / unitMS;
      } else {
        unitCount = Math.floor(ms / unitMS);
      }

      // Add the string.
      if (unitCount) {
        result.push(render(unitCount, unitName, dictionary));
      }

      // Remove what we just figured out.
      ms -= unitCount * unitMS;

    }

    return result.join(options.delimiter);

  }

  humanizeDuration.humanizer = humanizer;
  if ((typeof module !== "undefined") && (module.exports)) {
    module.exports = humanizeDuration;
  } else {
    this.humanizeDuration = humanizeDuration;
  }

  function render(count, type, dictionary) {
    var dictionaryValue = dictionary[type];
    var word;
    if (typeof dictionaryValue === "function") {
      word = dictionaryValue(count);
    } else {
      word = dictionaryValue;
    }
    return count + " " + word;
  }

  function extend(destination) {
    var source;
    for (var i = 1; i < arguments.length; i ++) {
      source = arguments[i];
      for (var prop in source) {
        destination[prop] = source[prop];
      }
    }
    return destination;
  }

  // Internal helper function for Polish language.
  function getPolishForm(c) {
    if (c === 1) {
      return 0;
    } else if (Math.floor(c) !== c) {
      return 1;
    } else if (2 <= c % 10 && c % 10 <= 4 && !(10 < c % 100 && c % 100 < 20)) {
      return 2;
    } else {
      return 3;
    }
  }

  // Internal helper function for Russian language.
  function getRussianForm(c) {
    if (Math.floor(c) !== c) {
      return 2;
    } else if (c === 0 || (c >= 5 && c <= 20) || (c % 10 >= 5 && c % 10 <= 9) || (c % 10 === 0) ) {
      return 0;
    } else if (c === 1 || c % 10 === 1) {
      return 1;
    } else if (c > 1) {
      return 2;
    } else {
      return 0;
    }
  }

})();
<commit_msg>Shrink our export strategy<commit_after>// HumanizeDuration.js - http://git.io/j0HgmQ

(function() {

  var UNITS = {
    year: 31557600000,
    month: 2629800000,
    week: 604800000,
    day: 86400000,
    hour: 3600000,
    minute: 60000,
    second: 1000,
    millisecond: 1
  };

  var languages = {
    ca: {
      year: function(c) { return "any" + ((c !== 1) ? "s" : ""); },
      month: function(c) { return "mes" + ((c !== 1) ? "os" : ""); },
      week: function(c) { return "setman" + ((c !== 1) ? "es" :"a"); },
      day: function(c) { return "di" + ((c !== 1) ? "es" :"a"); },
      hour: function(c) { return "hor" + ((c !== 1) ? "es" :"a"); },
      minute: function(c) { return "minut" + ((c !== 1) ? "s" : ""); },
      second: function(c) { return "segon" + ((c !== 1) ? "s" : ""); },
      millisecond: function(c) { return "milisegon" + ((c !== 1) ? "s" : "" ); }
    },
    da: {
      year: "år",
      month: function(c) { return "måned" + ((c !== 1) ? "er" : ""); },
      week: function(c) { return "uge" + ((c !== 1) ? "r" : ""); },
      day: function(c) { return "dag" + ((c !== 1) ? "e" : ""); },
      hour: function(c) { return "time" + ((c !== 1) ? "r" : ""); },
      minute: function(c) { return "minut" + ((c !== 1) ? "ter" : ""); },
      second: function(c) { return "sekund" + ((c !== 1) ? "er" : ""); },
      millisecond: function(c) { return "millisekund" + ((c !== 1) ? "er" : ""); }
    },
    de: {
      year: function(c) { return "jahr" + ((c !== 1) ? "e" : ""); },
      month: function(c) { return "monat" + ((c !== 1) ? "e" : ""); },
      week: function(c) { return "woche" + ((c !== 1) ? "n" : ""); },
      day: function(c) { return "tag" + ((c !== 1) ? "e" : ""); },
      hour: function(c) { return "stunde" + ((c !== 1) ? "n" : ""); },
      minute: function(c) { return "minute" + ((c !== 1) ? "n" : ""); },
      second: function(c) { return "sekunde" + ((c !== 1) ? "n" : ""); },
      millisecond: function(c) { return "millisekunde" + ((c !== 1) ? "n" : ""); }
    },
    en: {
      year: function(c) { return "year" + ((c !== 1) ? "s" : ""); },
      month: function(c) { return "month" + ((c !== 1) ? "s" : ""); },
      week: function(c) { return "week" + ((c !== 1) ? "s" : ""); },
      day: function(c) { return "day" + ((c !== 1) ? "s" : ""); },
      hour: function(c) { return "hour" + ((c !== 1) ? "s" : ""); },
      minute: function(c) { return "minute" + ((c !== 1) ? "s" : ""); },
      second: function(c) { return "second" + ((c !== 1) ? "s" : ""); },
      millisecond: function(c) { return "millisecond" + ((c !== 1) ? "s" : ""); }
    },
    nl: {
      year: "jaar",
      month: function(c) { return (c === 1) ? "maand" : "maanden"; },
      week: function(c) { return (c === 1) ? "week" : "weken"; },
      day: function(c) { return (c === 1) ? "dag" : "dagen"; },
      hour: "uur",
      minute: function(c) { return (c === 1) ? "minuut" : "minuten"; },
      second: function(c) { return (c === 1) ? "seconde" : "seconden"; },
      millisecond: function(c) { return (c === 1) ? "milliseconde" : "milliseconden"; }
    },
    es: {
      year: function(c) { return "año" + ((c !== 1) ? "s" : ""); },
      month: function(c) { return "mes" + ((c !== 1) ? "es" : ""); },
      week: function(c) { return "semana" + ((c !== 1) ? "s" : ""); },
      day: function(c) { return "día" + ((c !== 1) ? "s" : ""); },
      hour: function(c) { return "hora" + ((c !== 1) ? "s" : ""); },
      minute: function(c) { return "minuto" + ((c !== 1) ? "s" : ""); },
      second: function(c) { return "segundo" + ((c !== 1) ? "s" : ""); },
      millisecond: function(c) { return "milisegundo" + ((c !== 1) ? "s" : "" ); }
    },
    fr: {
      year: function(c) { return "an" + ((c !== 1) ? "s" : ""); },
      month: "mois",
      week: function(c) { return "semaine" + ((c !== 1) ? "s" : ""); },
      day: function(c) { return "jour" + ((c !== 1) ? "s" : ""); },
      hour: function(c) { return "heure" + ((c !== 1) ? "s" : ""); },
      minute: function(c) { return "minute" + ((c !== 1) ? "s" : ""); },
      second: function(c) { return "seconde" + ((c !== 1) ? "s" : ""); },
      millisecond: function(c) { return "milliseconde" + ((c !== 1) ? "s" : ""); }
    },
    ko: {
      year: "년",
      month: "개월",
      week: "주일",
      day: "일",
      hour: "시간",
      minute: "분",
      second: "초",
      millisecond: "밀리 초"
    },
    nob: {
      year: "år",
      month: function(c) { return "måned" + ((c !== 1) ? "er" : ""); },
      week: function(c) { return "uke" + ((c !== 1) ? "r" : ""); },
      day: function(c) { return "dag" + ((c !== 1) ? "er" : ""); },
      hour: function(c) { return "time" + ((c !== 1) ? "r" : ""); },
      minute: function(c) { return "minutt" + ((c !== 1) ? "er" : ""); },
      second: function(c) { return "sekund" + ((c !== 1) ? "er" : ""); },
      millisecond: function(c) { return "millisekund" + ((c !== 1) ? "er" : ""); }
    },
    pl: {
      year: function(c) { return ["rok", "roku", "lata", "lat"][getPolishForm(c)]; },
      month: function(c) { return ["miesiąc", "miesiąca", "miesiące", "miesięcy"][getPolishForm(c)]; },
      week: function(c) { return ["tydzień", "tygodnia", "tygodnie", "tygodni"][getPolishForm(c)]; },
      day: function(c) { return ["dzień", "dnia", "dni", "dni"][getPolishForm(c)]; },
      hour: function(c) { return ["godzina", "godziny", "godziny", "godzin"][getPolishForm(c)]; },
      minute: function(c) { return ["minuta", "minuty", "minuty", "minut"][getPolishForm(c)]; },
      second: function(c) { return ["sekunda", "sekundy", "sekundy", "sekund"][getPolishForm(c)]; },
      millisecond: function(c) { return ["milisekunda", "milisekundy", "milisekundy", "milisekund"][getPolishForm(c)]; }
    },
    pt: {
      year: function(c) { return "ano" + ((c !== 1) ? "s" : ""); },
      month: function(c) { return (c !== 1) ? "meses" : "mês"; },
      week: function(c) { return "semana" + ((c !== 1) ? "s" : ""); },
      day: function(c) { return "dia" + ((c !== 1) ? "s" : ""); },
      hour: function(c) { return "hora" + ((c !== 1) ? "s" : ""); },
      minute: function(c) { return "minuto" + ((c !== 1) ? "s" : ""); },
      second: function(c) { return "segundo" + ((c !== 1) ? "s" : ""); },
      millisecond: function(c) { return "milissegundo" + ((c !== 1) ? "s" : ""); }
    },
    ru: {
      year: function(c) { return ["лет", "год", "года"][getRussianForm(c)]; },
      month: function(c) { return ["месяцев", "месяц", "месяца"][getRussianForm(c)]; },
      week: function(c) { return ["недель", "неделя", "недели"][getRussianForm(c)]; },
      day: function(c) { return ["дней", "день", "дня"][getRussianForm(c)]; },
      hour: function(c) { return ["часов", "час", "часа"][getRussianForm(c)]; },
      minute: function(c) { return ["минут", "минута", "минуты"][getRussianForm(c)]; },
      second: function(c) { return ["секунд", "секунда", "секунды"][getRussianForm(c)]; },
      millisecond: function(c) { return ["миллисекунд", "миллисекунда", "миллисекунды"][getRussianForm(c)]; }
    },
    tr: {
      year: "yıl",
      month: "ay",
      week: "hafta",
      day: "gün",
      hour: "saat",
      minute: "dakika",
      second: "saniye",
      millisecond: "milisaniye"
    },
    "zh-CN": {
      year: "年",
      month: "个月",
      week: "周",
      day: "天",
      hour: "小时",
      minute: "分钟",
      second: "秒",
      millisecond: "毫秒"
    },
    "zh-TW": {
      year: "年",
      month: "個月",
      week: "周",
      day: "天",
      hour: "小時",
      minute: "分鐘",
      second: "秒",
      millisecond: "毫秒"
    },
    ja: {
      year: "年",
      month: "月",
      week: "週",
      day: "日",
      hour: "時間",
      minute: "分",
      second: "秒",
      millisecond: "ミリ秒"
    }
  };

  // You can create a humanizer, which returns a function with defaults
  // parameters.
  function humanizer(passedOptions) {

    var result = function humanizer(ms, passedOptions) {
      var options = extend({}, result, passedOptions || {});
      return doHumanization(ms, options);
    };

    extend(result, {
      language: "en",
      delimiter: ", ",
      units: [
        "year",
        "month",
        "week",
        "day",
        "hour",
        "minute",
        "second"
      ],
      languages: {}
    }, passedOptions);

    return result;

  }

  // The main function is just a wrapper around a default humanizer.
  var defaultHumanizer = humanizer({});
  function humanizeDuration(ms, passedOptions) {
    return defaultHumanizer(ms, passedOptions);
  }

  // doHumanization does the bulk of the work.
  function doHumanization(ms, options) {

    // Make sure we have a positive number.
    // Has the nice sideffect of turning Number objects into primitives.
    ms = Math.abs(ms);

    if (ms === 0) {
      return "0";
    }

    var dictionary = options.languages[options.language] || languages[options.language];
    if (!dictionary) {
      throw new Error("No language " + dictionary + ".");
    }

    var result = [];

    // Start at the top and keep removing units, bit by bit.
    var unitName, unitMS, unitCount, mightBeHalfUnit;
    for (var i = 0, len = options.units.length; i < len; i ++) {

      unitName = options.units[i];
      if (unitName[unitName.length - 1] === "s") { // strip plurals
        unitName = unitName.substring(0, unitName.length - 1);
      }
      unitMS = UNITS[unitName];

      // If it's a half-unit interval, we're done.
      if (result.length === 0) {
        mightBeHalfUnit = (ms / unitMS) * 2;
        if (mightBeHalfUnit === Math.floor(mightBeHalfUnit)) {
          return render(mightBeHalfUnit / 2, unitName, dictionary);
        }
      }

      // What's the number of full units we can fit?
      if ((i + 1) === len) {
        unitCount = ms / unitMS;
      } else {
        unitCount = Math.floor(ms / unitMS);
      }

      // Add the string.
      if (unitCount) {
        result.push(render(unitCount, unitName, dictionary));
      }

      // Remove what we just figured out.
      ms -= unitCount * unitMS;

    }

    return result.join(options.delimiter);

  }

  humanizeDuration.humanizer = humanizer;
  if (typeof module !== "undefined") {
    module.exports = humanizeDuration;
  } else {
    this.humanizeDuration = humanizeDuration;
  }

  function render(count, type, dictionary) {
    var dictionaryValue = dictionary[type];
    var word;
    if (typeof dictionaryValue === "function") {
      word = dictionaryValue(count);
    } else {
      word = dictionaryValue;
    }
    return count + " " + word;
  }

  function extend(destination) {
    var source;
    for (var i = 1; i < arguments.length; i ++) {
      source = arguments[i];
      for (var prop in source) {
        destination[prop] = source[prop];
      }
    }
    return destination;
  }

  // Internal helper function for Polish language.
  function getPolishForm(c) {
    if (c === 1) {
      return 0;
    } else if (Math.floor(c) !== c) {
      return 1;
    } else if (2 <= c % 10 && c % 10 <= 4 && !(10 < c % 100 && c % 100 < 20)) {
      return 2;
    } else {
      return 3;
    }
  }

  // Internal helper function for Russian language.
  function getRussianForm(c) {
    if (Math.floor(c) !== c) {
      return 2;
    } else if (c === 0 || (c >= 5 && c <= 20) || (c % 10 >= 5 && c % 10 <= 9) || (c % 10 === 0) ) {
      return 0;
    } else if (c === 1 || c % 10 === 1) {
      return 1;
    } else if (c > 1) {
      return 2;
    } else {
      return 0;
    }
  }

})();
<|endoftext|>


<commit_before>jQuery(function($) {
  $('select[name="projects"]').select2();
  $('select[name="project"]').select2();

  $('.actions .subActions').hide();
  $('.nestedAction .open').click(function() {
    $('.actions > button, .actions .open').hide();
    $(this).closest('.nestedAction').find('.subActions').show();
    return false;
  });

  $('.subActions .cancel').click(function() {
    $(this).closest('.nestedAction').find('.subActions').hide();
    $('.actions > button, .actions .open').show();
    return false;
  });

  $('textarea[name="comment"]').atwho({
    at: '@',
    data: window.buggyData.userNames,
  }).atwho({
    at: '#',
    data: window.buggyData.openBugs,
    displayTpl: '
#${number} ${title}
',
    insertTpl: '#${number}',
    searchKey: 'number',
    callbacks: {
      // We don't want to match at the beginning of the line, because that will
      // be a markdown header instead of a bug mention.
      matcher: function(flag, subtext) {
        var regexp = /^.*\S.*[ \t\f\v]#(\d*)$/gim;
        var match = regexp.exec(subtext);
        if (match)
          return match[1];
        else
          return null;
      }
    }
  });

  // Only allow one request to preview markdown to the server at a time, but
  // always do a preview with the latest content too.
  var requestPending = false;
  var requestCancelled = false;

  function doPreview($container) {
    if (requestPending) {
      requestCancelled = true;
      return;
    }
    requestPending = true;

    var markdown = $container.find('[name="comment"]').val();

    $.post(window.buggyData.previewMarkdownUrl, {preview: markdown}, function(resp) {
      $container.find('.previewTarget').html(resp).show();
      requestPending = false;
      if (requestCancelled) {
        requestCancelled = false;
        doPreview($container);
      }
    });
  }

  $('.previewMarkdown').click(function() {
    var $container = $(this).closest('.commentMarkdown');

    $container.find('[name="comment"]').on('keyup', function() {
      doPreview($container);
    });
    doPreview($container);

    return false;
  });

  // Pjax
  $.pjax.defaults.scrollTo = false;
  var pjaxRequestPending = false;
  var pjaxRequestCanceled = false;

  $(document).on('pjax:send', function() {
    pjaxRequestPending = true;
    pjaxRequestCanceled = false;
    $('#pjax-container').addClass('loading');
  })

  $(document).on('pjax:complete', function() {
    pjaxRequestPending = false;
    $('#add-preset-url').val(location.pathname + location.search)

    if (pjaxRequestCanceled) {
      pjaxRequestCanceled = false;
      pjaxSubmit();
    } else {
      pjaxRequestCanceled = false;
    }

    $('#pjax-container').removeClass('loading');
  })

  function pjaxSubmit() {
    if (pjaxRequestPending) {
      pjaxRequestCanceled = true;
      return;
    } else {
      $('form[data-pjax]').submit();
    }
  }

  $(document).on('click', 'a[data-pjax]', function(event) {
    $.pjax.click(event, '#pjax-container');
  })

  $(document).on('submit', 'form[data-pjax]', function(event) {
    $.pjax.submit(event, '#pjax-container');
  });
  $('form[data-pjax] :input:not(#id_search)').on('change', pjaxSubmit);
  $('form[data-pjax] #id_search').on('keyup', pjaxSubmit);

  $(document).on('pjax:popstate', function(event) {
    location.reload();
  });
});

jQuery.pjax.defaults.timeout = 2500;
<commit_msg>Set pjax 'loading' class earlier<commit_after>jQuery(function($) {
  $('select[name="projects"]').select2();
  $('select[name="project"]').select2();

  $('.actions .subActions').hide();
  $('.nestedAction .open').click(function() {
    $('.actions > button, .actions .open').hide();
    $(this).closest('.nestedAction').find('.subActions').show();
    return false;
  });

  $('.subActions .cancel').click(function() {
    $(this).closest('.nestedAction').find('.subActions').hide();
    $('.actions > button, .actions .open').show();
    return false;
  });

  $('textarea[name="comment"]').atwho({
    at: '@',
    data: window.buggyData.userNames,
  }).atwho({
    at: '#',
    data: window.buggyData.openBugs,
    displayTpl: '
#${number} ${title}
',
    insertTpl: '#${number}',
    searchKey: 'number',
    callbacks: {
      // We don't want to match at the beginning of the line, because that will
      // be a markdown header instead of a bug mention.
      matcher: function(flag, subtext) {
        var regexp = /^.*\S.*[ \t\f\v]#(\d*)$/gim;
        var match = regexp.exec(subtext);
        if (match)
          return match[1];
        else
          return null;
      }
    }
  });

  // Only allow one request to preview markdown to the server at a time, but
  // always do a preview with the latest content too.
  var requestPending = false;
  var requestCancelled = false;

  function doPreview($container) {
    if (requestPending) {
      requestCancelled = true;
      return;
    }
    requestPending = true;

    var markdown = $container.find('[name="comment"]').val();

    $.post(window.buggyData.previewMarkdownUrl, {preview: markdown}, function(resp) {
      $container.find('.previewTarget').html(resp).show();
      requestPending = false;
      if (requestCancelled) {
        requestCancelled = false;
        doPreview($container);
      }
    });
  }

  $('.previewMarkdown').click(function() {
    var $container = $(this).closest('.commentMarkdown');

    $container.find('[name="comment"]').on('keyup', function() {
      doPreview($container);
    });
    doPreview($container);

    return false;
  });

  // Pjax
  $.pjax.defaults.scrollTo = false;
  var pjaxRequestPending = false;
  var pjaxRequestCanceled = false;

  $(document).on('pjax:beforeSend', function() {
    pjaxRequestPending = true;
    pjaxRequestCanceled = false;
    $('#pjax-container').addClass('loading');
  })

  $(document).on('pjax:complete', function() {
    pjaxRequestPending = false;
    $('#add-preset-url').val(location.pathname + location.search)

    if (pjaxRequestCanceled) {
      pjaxRequestCanceled = false;
      pjaxSubmit();
    } else {
      pjaxRequestCanceled = false;
    }

    $('#pjax-container').removeClass('loading');
  })

  function pjaxSubmit() {
    if (pjaxRequestPending) {
      pjaxRequestCanceled = true;
      return;
    } else {
      $('form[data-pjax]').submit();
    }
  }

  $(document).on('click', 'a[data-pjax]', function(event) {
    $.pjax.click(event, '#pjax-container');
  })

  $(document).on('submit', 'form[data-pjax]', function(event) {
    $.pjax.submit(event, '#pjax-container');
  });
  $('form[data-pjax] :input:not(#id_search)').on('change', pjaxSubmit);
  $('form[data-pjax] #id_search').on('keyup', pjaxSubmit);

  $(document).on('pjax:popstate', function(event) {
    location.reload();
  });
});

jQuery.pjax.defaults.timeout = 2500;
<|endoftext|>