<commit_before>import * as textUtils from '~/lib/utils/text_utility';

describe('text_utility', () => {
  describe('addDelimiter', () => {
    it('should add a delimiter to the given string', () => {
      expect(textUtils.addDelimiter('1234')).toEqual('1,234');
      expect(textUtils.addDelimiter('222222')).toEqual('222,222');
    });

    it('should not add a delimiter if string contains no numbers', () => {
      expect(textUtils.addDelimiter('aaaa')).toEqual('aaaa');
    });
  });

  describe('highCountTrim', () => {
    it('returns 99+ for count >= 100', () => {
      expect(textUtils.highCountTrim(105)).toBe('99+');
      expect(textUtils.highCountTrim(100)).toBe('99+');
    });

    it('returns exact number for count < 100', () => {
      expect(textUtils.highCountTrim(45)).toBe(45);
    });
  });

  describe('capitalizeFirstCharacter', () => {
    it('returns string with first letter capitalized', () => {
      expect(textUtils.capitalizeFirstCharacter('gitlab')).toEqual('Gitlab');
      expect(textUtils.highCountTrim(105)).toBe('99+');
      expect(textUtils.highCountTrim(100)).toBe('99+');
    });
  });

  describe('humanize', () => {
    it('should remove underscores and uppercase the first letter', () => {
      expect(textUtils.humanize('foo_bar')).toEqual('Foo bar');
    });
  });

  describe('pluralize', () => {
    it('should pluralize given string', () => {
      expect(textUtils.pluralize('test', 2)).toBe('tests');
    });

    it('should pluralize when count is 0', () => {
      expect(textUtils.pluralize('test', 0)).toBe('tests');
    });

    it('should not pluralize when count is 1', () => {
      expect(textUtils.pluralize('test', 1)).toBe('test');
    });
  });

  describe('dasherize', () => {
    it('should replace underscores with dashes', () => {
      expect(textUtils.dasherize('foo_bar_foo')).toEqual('foo-bar-foo');
    });
  });

  describe('slugify', () => {
    it('should remove accents and convert to lower case', () => {
      expect(textUtils.slugify('João')).toEqual('joão');
    });
  });

  describe('slugifyWithHyphens', () => {
    it('should replaces whitespaces with hyphens and convert to lower case', () => {
      expect(textUtils.slugifyWithHyphens('My Input String')).toEqual('my-input-string');
    });
  });

  describe('stripHtml', () => {
    it('replaces html tag with the default replacement', () => {
      expect(textUtils.stripHtml('This is a text with
html
.')).toEqual(
        'This is a text with html.',
      );
    });

    it('replaces html tags with the provided replacement', () => {
      expect(textUtils.stripHtml('This is a text with
html
.', ' ')).toEqual(
        'This is a text with  html .',
      );
    });

    it('passes through with null string input', () => {
      expect(textUtils.stripHtml(null, ' ')).toEqual(null);
    });

    it('passes through with undefined string input', () => {
      expect(textUtils.stripHtml(undefined, ' ')).toEqual(undefined);
    });
  });

  describe('convertToCamelCase', () => {
    it('converts snake_case string to camelCase string', () => {
      expect(textUtils.convertToCamelCase('snake_case')).toBe('snakeCase');
    });
  });

  describe('convertToSentenceCase', () => {
    it('converts Sentence Case to Sentence case', () => {
      expect(textUtils.convertToSentenceCase('Hello World')).toBe('Hello world');
    });
  });

  describe('truncateSha', () => {
    it('shortens SHAs to 8 characters', () => {
      expect(textUtils.truncateSha('verylongsha')).toBe('verylong');
    });

    it('leaves short SHAs as is', () => {
      expect(textUtils.truncateSha('shortsha')).toBe('shortsha');
    });
  });

  describe('splitCamelCase', () => {
    it('separates a PascalCase word to two', () => {
      expect(textUtils.splitCamelCase('HelloWorld')).toBe('Hello World');
    });
  });

  describe('getFirstCharacterCapitalized', () => {
    it('returns the first character capitalized, if first character is alphabetic', () => {
      expect(textUtils.getFirstCharacterCapitalized('loremIpsumDolar')).toEqual('L');
      expect(textUtils.getFirstCharacterCapitalized('Sit amit !')).toEqual('S');
    });

    it('returns the first character, if first character is non-alphabetic', () => {
      expect(textUtils.getFirstCharacterCapitalized(' lorem')).toEqual(' ');
      expect(textUtils.getFirstCharacterCapitalized('%#!')).toEqual('%');
    });

    it('returns an empty string, if string is falsey', () => {
      expect(textUtils.getFirstCharacterCapitalized('')).toEqual('');
      expect(textUtils.getFirstCharacterCapitalized(null)).toEqual('');
    });
  });

  describe('truncatePathMiddleToLength', () => {
    it('does not truncate text', () => {
      expect(textUtils.truncatePathMiddleToLength('app/test', 50)).toEqual('app/test');
    });

    it('truncates middle of the path', () => {
      expect(textUtils.truncatePathMiddleToLength('app/test/diff', 13)).toEqual('app/…/diff');
    });

    it('truncates multiple times in the middle of the path', () => {
      expect(textUtils.truncatePathMiddleToLength('app/test/merge_request/diff', 13)).toEqual(
        'app/…/…/diff',
      );
    });
  });

  describe('truncateNamespace', () => {
    it(`should return the root namespace if the namespace only includes one level`, () => {
      expect(textUtils.truncateNamespace('a / b')).toBe('a');
    });

    it(`should return the first 2 namespaces if the namespace inlcudes exactly 2 levels`, () => {
      expect(textUtils.truncateNamespace('a / b / c')).toBe('a / b');
    });

    it(`should return the first and last namespaces, separated by "...", if the namespace inlcudes more than 2 levels`, () => {
      expect(textUtils.truncateNamespace('a / b / c / d')).toBe('a / ... / c');
      expect(textUtils.truncateNamespace('a / b / c / d / e / f / g / h / i')).toBe('a / ... / h');
    });

    it(`should return an empty string for invalid inputs`, () => {
      [undefined, null, 4, {}, true, new Date()].forEach(input => {
        expect(textUtils.truncateNamespace(input)).toBe('');
      });
    });

    it(`should not alter strings that aren't formatted as namespaces`, () => {
      ['', ' ', '\t', 'a', 'a \\ b'].forEach(input => {
        expect(textUtils.truncateNamespace(input)).toBe(input);
      });
    });
  });
});
<commit_msg>Resolve CE/EE diff in text_utility_spec<commit_after>import * as textUtils from '~/lib/utils/text_utility';

describe('text_utility', () => {
  describe('addDelimiter', () => {
    it('should add a delimiter to the given string', () => {
      expect(textUtils.addDelimiter('1234')).toEqual('1,234');
      expect(textUtils.addDelimiter('222222')).toEqual('222,222');
    });

    it('should not add a delimiter if string contains no numbers', () => {
      expect(textUtils.addDelimiter('aaaa')).toEqual('aaaa');
    });
  });

  describe('highCountTrim', () => {
    it('returns 99+ for count >= 100', () => {
      expect(textUtils.highCountTrim(105)).toBe('99+');
      expect(textUtils.highCountTrim(100)).toBe('99+');
    });

    it('returns exact number for count < 100', () => {
      expect(textUtils.highCountTrim(45)).toBe(45);
    });
  });

  describe('humanize', () => {
    it('should remove underscores and uppercase the first letter', () => {
      expect(textUtils.humanize('foo_bar')).toEqual('Foo bar');
    });
  });

  describe('pluralize', () => {
    it('should pluralize given string', () => {
      expect(textUtils.pluralize('test', 2)).toBe('tests');
    });

    it('should pluralize when count is 0', () => {
      expect(textUtils.pluralize('test', 0)).toBe('tests');
    });

    it('should not pluralize when count is 1', () => {
      expect(textUtils.pluralize('test', 1)).toBe('test');
    });
  });

  describe('dasherize', () => {
    it('should replace underscores with dashes', () => {
      expect(textUtils.dasherize('foo_bar_foo')).toEqual('foo-bar-foo');
    });
  });

  describe('slugify', () => {
    it('should remove accents and convert to lower case', () => {
      expect(textUtils.slugify('João')).toEqual('joão');
    });
  });

  describe('capitalizeFirstCharacter', () => {
    it('returns string with first letter capitalized', () => {
      expect(textUtils.capitalizeFirstCharacter('gitlab')).toEqual('Gitlab');
    });
  });

  describe('slugifyWithHyphens', () => {
    it('should replaces whitespaces with hyphens and convert to lower case', () => {
      expect(textUtils.slugifyWithHyphens('My Input String')).toEqual('my-input-string');
    });
  });

  describe('stripHtml', () => {
    it('replaces html tag with the default replacement', () => {
      expect(textUtils.stripHtml('This is a text with
html
.')).toEqual(
        'This is a text with html.',
      );
    });

    it('replaces html tags with the provided replacement', () => {
      expect(textUtils.stripHtml('This is a text with
html
.', ' ')).toEqual(
        'This is a text with  html .',
      );
    });

    it('passes through with null string input', () => {
      expect(textUtils.stripHtml(null, ' ')).toEqual(null);
    });

    it('passes through with undefined string input', () => {
      expect(textUtils.stripHtml(undefined, ' ')).toEqual(undefined);
    });
  });

  describe('convertToCamelCase', () => {
    it('converts snake_case string to camelCase string', () => {
      expect(textUtils.convertToCamelCase('snake_case')).toBe('snakeCase');
    });
  });

  describe('convertToSentenceCase', () => {
    it('converts Sentence Case to Sentence case', () => {
      expect(textUtils.convertToSentenceCase('Hello World')).toBe('Hello world');
    });
  });

  describe('truncateSha', () => {
    it('shortens SHAs to 8 characters', () => {
      expect(textUtils.truncateSha('verylongsha')).toBe('verylong');
    });

    it('leaves short SHAs as is', () => {
      expect(textUtils.truncateSha('shortsha')).toBe('shortsha');
    });
  });

  describe('splitCamelCase', () => {
    it('separates a PascalCase word to two', () => {
      expect(textUtils.splitCamelCase('HelloWorld')).toBe('Hello World');
    });
  });

  describe('getFirstCharacterCapitalized', () => {
    it('returns the first character capitalized, if first character is alphabetic', () => {
      expect(textUtils.getFirstCharacterCapitalized('loremIpsumDolar')).toEqual('L');
      expect(textUtils.getFirstCharacterCapitalized('Sit amit !')).toEqual('S');
    });

    it('returns the first character, if first character is non-alphabetic', () => {
      expect(textUtils.getFirstCharacterCapitalized(' lorem')).toEqual(' ');
      expect(textUtils.getFirstCharacterCapitalized('%#!')).toEqual('%');
    });

    it('returns an empty string, if string is falsey', () => {
      expect(textUtils.getFirstCharacterCapitalized('')).toEqual('');
      expect(textUtils.getFirstCharacterCapitalized(null)).toEqual('');
    });
  });

  describe('truncatePathMiddleToLength', () => {
    it('does not truncate text', () => {
      expect(textUtils.truncatePathMiddleToLength('app/test', 50)).toEqual('app/test');
    });

    it('truncates middle of the path', () => {
      expect(textUtils.truncatePathMiddleToLength('app/test/diff', 13)).toEqual('app/…/diff');
    });

    it('truncates multiple times in the middle of the path', () => {
      expect(textUtils.truncatePathMiddleToLength('app/test/merge_request/diff', 13)).toEqual(
        'app/…/…/diff',
      );
    });
  });

  describe('truncateNamespace', () => {
    it(`should return the root namespace if the namespace only includes one level`, () => {
      expect(textUtils.truncateNamespace('a / b')).toBe('a');
    });

    it(`should return the first 2 namespaces if the namespace inlcudes exactly 2 levels`, () => {
      expect(textUtils.truncateNamespace('a / b / c')).toBe('a / b');
    });

    it(`should return the first and last namespaces, separated by "...", if the namespace inlcudes more than 2 levels`, () => {
      expect(textUtils.truncateNamespace('a / b / c / d')).toBe('a / ... / c');
      expect(textUtils.truncateNamespace('a / b / c / d / e / f / g / h / i')).toBe('a / ... / h');
    });

    it(`should return an empty string for invalid inputs`, () => {
      [undefined, null, 4, {}, true, new Date()].forEach(input => {
        expect(textUtils.truncateNamespace(input)).toBe('');
      });
    });

    it(`should not alter strings that aren't formatted as namespaces`, () => {
      ['', ' ', '\t', 'a', 'a \\ b'].forEach(input => {
        expect(textUtils.truncateNamespace(input)).toBe(input);
      });
    });
  });
});
<|endoftext|>


<commit_before>/**
 * Copyright 2016 The AMP HTML Authors. All Rights Reserved.
 *
 * 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 installCustomElements from
    'document-register-element/build/document-register-element.node';
import {
  FakeCustomElements,
  FakeWindow,
  interceptEventListeners,
} from './fake-dom';
import {doNotLoadExternalResourcesInTest} from './iframe';
import {
  adopt,
  adoptShadowMode,
  installAmpdocServices,
  installRuntimeServices,
  registerForUnitTest,
} from '../src/runtime';
import {cssText} from '../build/css';
import {installDocService} from '../src/service/ampdoc-impl';
import {installExtensionsService} from '../src/service/extensions-impl';
import {resetScheduledElementForTesting} from '../src/custom-element';
import * as sinon from 'sinon';

/** Should have something in the name, otherwise nothing is shown. */
const SUB = ' ';

/** @type {number} */
let iframeCount = 0;

/**
 * @typedef {{
 *   fakeRegisterElement: (boolean|undefined),
 * }}
 */
export let TestSpec;

/**
 * - ampdoc: "single", "shadow", "multi", "none".
 *
 * @typedef {{
 *   runtimeOn: (boolean|undefined),
 *   ampdoc: (string),
 *   params: (!Object<string, string>|undefined),
 * }}
 */
export let AmpTestSpec;

/**
 * @typedef {{
 *   win: !Window,
 *   extensions: !Extensions,
 *   ampdocService: !AmpDocService,
 *   ampdoc: (!AmpDoc|undefined),
 *   flushVsync: function(),
 * }}
 */
export let AmpTestEnv;

/**
 * A test with a sandbox.
 * @param {string} name
 * @param {!TestSpec} spec
 * @param {function()} fn
 */
export const sandboxed = describeEnv(spec => []);

/**
 * A test with a fake window.
 * @param {string} name
 * @param {{
 *   win: !FakeWindowSpec,
 *   amp: (!AmpTestSpec|undefined),
 * }} spec
 * @param {function({
 *   win: !FakeWindow,
 *   amp: (!AmpTestEnv|undefined),
 * })} fn
 */
export const fakeWin = describeEnv(spec => [
      new FakeWinFixture(spec),
      new AmpFixture(spec),
    ]);

/**
 * A test with a real (iframed) window.
 * @param {string} name
 * @param {{
 *   fakeRegisterElement: (boolean|undefined),
 *   amp: (!AmpTestSpec|undefined),
 * }} spec
 * @param {function({
 *   win: !Window,
 *   iframe: !HTMLIFrameElement,
 *   amp: (!AmpTestEnv|undefined),
 * })} fn
 */
export const realWin = describeEnv(spec => [
      new RealWinFixture(spec),
      new AmpFixture(spec),
    ]);

/**
 * A test with in a described environment.
 * @param {function(!Object):!Array<?Fixture>} factory
 */
function describeEnv(factory) {
  /**
   * @param {string} name
   * @param {!Object} spec
   * @param {function(!Object)} fn
   * @param {function(string, function())} describeFunc
   */
  const templateFunc = function(name, spec, fn, describeFunc) {
    const fixtures = [new SandboxFixture(spec)];
    factory(spec).forEach(fixture => {
      if (fixture && fixture.isOn()) {
        fixtures.push(fixture);
      }
    });
    return describeFunc(name, function() {

      const env = Object.create(null);

      beforeEach(() => {
        let totalPromise = undefined;
        // Set up all fixtures.
        fixtures.forEach((fixture, index) => {
          if (totalPromise) {
            totalPromise = totalPromise.then(() => fixture.setup(env));
          } else {
            const res = fixture.setup(env);
            if (res && typeof res.then == 'function') {
              totalPromise = res;
            }
          }
        });
        return totalPromise;
      });

      afterEach(() => {
        // Tear down all fixtures.
        fixtures.forEach(fixture => {
          fixture.teardown(env);
        });

        // Delete all other keys.
        for (const key in env) {
          delete env[key];
        }
      });

      describe(SUB, function() {
        fn.call(this, env);
      });
    });
  };

  /**
   * @param {string} name
   * @param {!Object} spec
   * @param {function(!Object)} fn
   */
  const mainFunc = function(name, spec, fn) {
    return templateFunc(name, spec, fn, describe);
  };

  /**
   * @param {string} name
   * @param {!Object} spec
   * @param {function(!Object)} fn
   */
  mainFunc.only = function(name, spec, fn) {
    return templateFunc(name, spec, fn, describe./*OK*/only);
  };

  return mainFunc;
}

/** @interface */
class Fixture {

  /** @return {boolean} */
  isOn() {}

  /**
   * @param {!Object} env
   * @return {!Promise|undefined}
   */
  setup(env) {}

  /**
   * @param {!Object} env
   */
  teardown(env) {}
}

/** @implements {Fixture} */
class SandboxFixture {

  /** @param {!TestSpec} spec */
  constructor(spec) {
    /** @const */
    this.spec = spec;

    /** @private {boolean} */
    this.sandboxOwner_ = false;
  }

  /** @override */
  isOn() {
    return true;
  }

  /** @override */
  setup(env) {
    const spec = this.spec;

    // Sandbox.
    let sandbox = global.sandbox;
    if (!sandbox) {
      sandbox = global.sandbox = sinon.sandbox.create();
      this.sandboxOwner_ = true;
    }
    env.sandbox = sandbox;
  }

  /** @override */
  teardown(env) {
    // Sandbox.
    if (this.sandboxOwner_) {
      env.sandbox.restore();
      delete global.sandbox;
      this.sandboxOwner_ = false;
    }
  }
}

/** @implements {Fixture} */
class FakeWinFixture {

  /** @param {!{win: !FakeWindowSpec}} spec */
  constructor(spec) {
    /** @const */
    this.spec = spec;
  }

  /** @override */
  isOn() {
    return true;
  }

  /** @override */
  setup(env) {
    env.win = new FakeWindow(this.spec.win || {});
  }

  /** @override */
  teardown(env) {
  }
}

/** @implements {Fixture} */
class RealWinFixture {

  /** @param {!{fakeRegisterElement: boolean, ampCss: boolean}} spec */
  constructor(spec) {
    /** @const */
    this.spec = spec;
  }

  /** @override */
  isOn() {
    return true;
  }

  /** @override */
  setup(env) {
    const spec = this.spec;
    return new Promise(function(resolve, reject) {
      const iframe = document.createElement('iframe');
      env.iframe = iframe;
      iframe.name = 'test_' + iframeCount++;
      iframe.srcdoc = '<!doctype>' +
          '' +
          '

';
      iframe.onload = function() {
        const win = iframe.contentWindow;
        env.win = win;

        // Flag as being a test window.
        win.AMP_TEST_IFRAME = true;

        doNotLoadExternalResourcesInTest(win);

        // Install AMP CSS if requested.
        if (spec.ampCss) {
          installRuntimeStylesPromise(win);
        }

        if (spec.fakeRegisterElement) {
          win.customElements = new FakeCustomElements(win);
        } else {
          installCustomElements(win);
        }

        // Intercept event listeners
        interceptEventListeners(win);
        interceptEventListeners(win.document);
        interceptEventListeners(win.document.documentElement);
        interceptEventListeners(win.document.body);
        env.interceptEventListeners = interceptEventListeners;

        resolve();
      };
      iframe.onerror = reject;
      document.body.appendChild(iframe);
    });
  }

  /** @override */
  teardown(env) {
    // TODO(dvoytenko): test that window is returned in a good condition.
    if (env.iframe.parentNode) {
      env.iframe.parentNode.removeChild(env.iframe);
    }
  }
}

/** @implements {Fixture} */
class AmpFixture {

  /**
   * @param {!{amp: (boolean|!AmpTestSpec)}} spec
   */
  constructor(spec) {
    /** @const */
    this.spec = spec;
  }

  /** @override */
  isOn() {
    return !!this.spec.amp;
  }

  /** @override */
  setup(env) {
    const spec = this.spec.amp;
    const win = env.win;
    let completePromise;

    win.ampExtendedElements = {};
    if (!spec.runtimeOn) {
      win.name = '__AMP__off=1';
    }
    const ampdocType = spec.ampdoc || 'single';
    const singleDoc = ampdocType == 'single';
    const ampdocService = installDocService(win, singleDoc);
    env.ampdocService  = ampdocService;
    env.extensions = installExtensionsService(win);
    installRuntimeServices(win);
    env.flushVsync = function() {
      win.services.vsync.obj.runScheduledTasks_();
    };
    if (singleDoc) {
      // Install AMP CSS for main runtime, if it hasn't been installed yet.
      completePromise = installRuntimeStylesPromise(win);
      const ampdoc = ampdocService.getAmpDoc(win.document);
      env.ampdoc = ampdoc;
      installAmpdocServices(ampdoc, spec.params);
      adopt(win);
    } else if (ampdocType == 'multi') {
      adoptShadowMode(win);
      // Notice that ampdoc's themselves install runtime styles in shadow roots.
      // Thus, not changes needed here.
    }

    return completePromise;
  }

  /** @override */
  teardown(env) {
    const win = env.win;
    if (win.customElements && win.customElements.elements) {
      for (const k in win.customElements.elements) {
        resetScheduledElementForTesting(win, k);
      }
    }
  }
}

/**
 * @param {!Window} win
 */
function installRuntimeStylesPromise(win) {
  if (win.document.querySelector('style[amp-runtime]')) {
    // Already installed.
    return;
  }
  const style = document.createElement('style');
  style.setAttribute('amp-runtime', '');
  style.textContent = cssText;
  win.document.head.appendChild(style);
}
<commit_msg>Force-override window.customElements (#5826)<commit_after>/**
 * Copyright 2016 The AMP HTML Authors. All Rights Reserved.
 *
 * 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 installCustomElements from
    'document-register-element/build/document-register-element.node';
import {
  FakeCustomElements,
  FakeWindow,
  interceptEventListeners,
} from './fake-dom';
import {doNotLoadExternalResourcesInTest} from './iframe';
import {
  adopt,
  adoptShadowMode,
  installAmpdocServices,
  installRuntimeServices,
  registerForUnitTest,
} from '../src/runtime';
import {cssText} from '../build/css';
import {installDocService} from '../src/service/ampdoc-impl';
import {installExtensionsService} from '../src/service/extensions-impl';
import {resetScheduledElementForTesting} from '../src/custom-element';
import * as sinon from 'sinon';

/** Should have something in the name, otherwise nothing is shown. */
const SUB = ' ';

/** @type {number} */
let iframeCount = 0;

/**
 * @typedef {{
 *   fakeRegisterElement: (boolean|undefined),
 * }}
 */
export let TestSpec;

/**
 * - ampdoc: "single", "shadow", "multi", "none".
 *
 * @typedef {{
 *   runtimeOn: (boolean|undefined),
 *   ampdoc: (string),
 *   params: (!Object<string, string>|undefined),
 * }}
 */
export let AmpTestSpec;

/**
 * @typedef {{
 *   win: !Window,
 *   extensions: !Extensions,
 *   ampdocService: !AmpDocService,
 *   ampdoc: (!AmpDoc|undefined),
 *   flushVsync: function(),
 * }}
 */
export let AmpTestEnv;

/**
 * A test with a sandbox.
 * @param {string} name
 * @param {!TestSpec} spec
 * @param {function()} fn
 */
export const sandboxed = describeEnv(spec => []);

/**
 * A test with a fake window.
 * @param {string} name
 * @param {{
 *   win: !FakeWindowSpec,
 *   amp: (!AmpTestSpec|undefined),
 * }} spec
 * @param {function({
 *   win: !FakeWindow,
 *   amp: (!AmpTestEnv|undefined),
 * })} fn
 */
export const fakeWin = describeEnv(spec => [
      new FakeWinFixture(spec),
      new AmpFixture(spec),
    ]);

/**
 * A test with a real (iframed) window.
 * @param {string} name
 * @param {{
 *   fakeRegisterElement: (boolean|undefined),
 *   amp: (!AmpTestSpec|undefined),
 * }} spec
 * @param {function({
 *   win: !Window,
 *   iframe: !HTMLIFrameElement,
 *   amp: (!AmpTestEnv|undefined),
 * })} fn
 */
export const realWin = describeEnv(spec => [
      new RealWinFixture(spec),
      new AmpFixture(spec),
    ]);

/**
 * A test with in a described environment.
 * @param {function(!Object):!Array<?Fixture>} factory
 */
function describeEnv(factory) {
  /**
   * @param {string} name
   * @param {!Object} spec
   * @param {function(!Object)} fn
   * @param {function(string, function())} describeFunc
   */
  const templateFunc = function(name, spec, fn, describeFunc) {
    const fixtures = [new SandboxFixture(spec)];
    factory(spec).forEach(fixture => {
      if (fixture && fixture.isOn()) {
        fixtures.push(fixture);
      }
    });
    return describeFunc(name, function() {

      const env = Object.create(null);

      beforeEach(() => {
        let totalPromise = undefined;
        // Set up all fixtures.
        fixtures.forEach((fixture, index) => {
          if (totalPromise) {
            totalPromise = totalPromise.then(() => fixture.setup(env));
          } else {
            const res = fixture.setup(env);
            if (res && typeof res.then == 'function') {
              totalPromise = res;
            }
          }
        });
        return totalPromise;
      });

      afterEach(() => {
        // Tear down all fixtures.
        fixtures.forEach(fixture => {
          fixture.teardown(env);
        });

        // Delete all other keys.
        for (const key in env) {
          delete env[key];
        }
      });

      describe(SUB, function() {
        fn.call(this, env);
      });
    });
  };

  /**
   * @param {string} name
   * @param {!Object} spec
   * @param {function(!Object)} fn
   */
  const mainFunc = function(name, spec, fn) {
    return templateFunc(name, spec, fn, describe);
  };

  /**
   * @param {string} name
   * @param {!Object} spec
   * @param {function(!Object)} fn
   */
  mainFunc.only = function(name, spec, fn) {
    return templateFunc(name, spec, fn, describe./*OK*/only);
  };

  return mainFunc;
}

/** @interface */
class Fixture {

  /** @return {boolean} */
  isOn() {}

  /**
   * @param {!Object} env
   * @return {!Promise|undefined}
   */
  setup(env) {}

  /**
   * @param {!Object} env
   */
  teardown(env) {}
}

/** @implements {Fixture} */
class SandboxFixture {

  /** @param {!TestSpec} spec */
  constructor(spec) {
    /** @const */
    this.spec = spec;

    /** @private {boolean} */
    this.sandboxOwner_ = false;
  }

  /** @override */
  isOn() {
    return true;
  }

  /** @override */
  setup(env) {
    const spec = this.spec;

    // Sandbox.
    let sandbox = global.sandbox;
    if (!sandbox) {
      sandbox = global.sandbox = sinon.sandbox.create();
      this.sandboxOwner_ = true;
    }
    env.sandbox = sandbox;
  }

  /** @override */
  teardown(env) {
    // Sandbox.
    if (this.sandboxOwner_) {
      env.sandbox.restore();
      delete global.sandbox;
      this.sandboxOwner_ = false;
    }
  }
}

/** @implements {Fixture} */
class FakeWinFixture {

  /** @param {!{win: !FakeWindowSpec}} spec */
  constructor(spec) {
    /** @const */
    this.spec = spec;
  }

  /** @override */
  isOn() {
    return true;
  }

  /** @override */
  setup(env) {
    env.win = new FakeWindow(this.spec.win || {});
  }

  /** @override */
  teardown(env) {
  }
}

/** @implements {Fixture} */
class RealWinFixture {

  /** @param {!{fakeRegisterElement: boolean, ampCss: boolean}} spec */
  constructor(spec) {
    /** @const */
    this.spec = spec;
  }

  /** @override */
  isOn() {
    return true;
  }

  /** @override */
  setup(env) {
    const spec = this.spec;
    return new Promise(function(resolve, reject) {
      const iframe = document.createElement('iframe');
      env.iframe = iframe;
      iframe.name = 'test_' + iframeCount++;
      iframe.srcdoc = '<!doctype>' +
          '' +
          '

';
      iframe.onload = function() {
        const win = iframe.contentWindow;
        env.win = win;

        // Flag as being a test window.
        win.AMP_TEST_IFRAME = true;

        doNotLoadExternalResourcesInTest(win);

        // Install AMP CSS if requested.
        if (spec.ampCss) {
          installRuntimeStylesPromise(win);
        }

        if (spec.fakeRegisterElement) {
          const customElements = new FakeCustomElements(win);
          Object.defineProperty(win, 'customElements', {
            get: () => customElements,
          });
        } else {
          installCustomElements(win);
        }

        // Intercept event listeners
        interceptEventListeners(win);
        interceptEventListeners(win.document);
        interceptEventListeners(win.document.documentElement);
        interceptEventListeners(win.document.body);
        env.interceptEventListeners = interceptEventListeners;

        resolve();
      };
      iframe.onerror = reject;
      document.body.appendChild(iframe);
    });
  }

  /** @override */
  teardown(env) {
    // TODO(dvoytenko): test that window is returned in a good condition.
    if (env.iframe.parentNode) {
      env.iframe.parentNode.removeChild(env.iframe);
    }
  }
}

/** @implements {Fixture} */
class AmpFixture {

  /**
   * @param {!{amp: (boolean|!AmpTestSpec)}} spec
   */
  constructor(spec) {
    /** @const */
    this.spec = spec;
  }

  /** @override */
  isOn() {
    return !!this.spec.amp;
  }

  /** @override */
  setup(env) {
    const spec = this.spec.amp;
    const win = env.win;
    let completePromise;

    win.ampExtendedElements = {};
    if (!spec.runtimeOn) {
      win.name = '__AMP__off=1';
    }
    const ampdocType = spec.ampdoc || 'single';
    const singleDoc = ampdocType == 'single';
    const ampdocService = installDocService(win, singleDoc);
    env.ampdocService  = ampdocService;
    env.extensions = installExtensionsService(win);
    installRuntimeServices(win);
    env.flushVsync = function() {
      win.services.vsync.obj.runScheduledTasks_();
    };
    if (singleDoc) {
      // Install AMP CSS for main runtime, if it hasn't been installed yet.
      completePromise = installRuntimeStylesPromise(win);
      const ampdoc = ampdocService.getAmpDoc(win.document);
      env.ampdoc = ampdoc;
      installAmpdocServices(ampdoc, spec.params);
      adopt(win);
    } else if (ampdocType == 'multi') {
      adoptShadowMode(win);
      // Notice that ampdoc's themselves install runtime styles in shadow roots.
      // Thus, not changes needed here.
    }

    return completePromise;
  }

  /** @override */
  teardown(env) {
    const win = env.win;
    if (win.customElements && win.customElements.elements) {
      for (const k in win.customElements.elements) {
        resetScheduledElementForTesting(win, k);
      }
    }
  }
}

/**
 * @param {!Window} win
 */
function installRuntimeStylesPromise(win) {
  if (win.document.querySelector('style[amp-runtime]')) {
    // Already installed.
    return;
  }
  const style = document.createElement('style');
  style.setAttribute('amp-runtime', '');
  style.textContent = cssText;
  win.document.head.appendChild(style);
}
<|endoftext|>


<commit_before>define(['helpers/converters/DatasetSorter'], function(DatasetSorter){
    describe('DatasetSorter', function (){
        var converter;
        var datasets = [{
                        "code": "A045",
                        "description": "Enteritis durch Campylobacter",
                        "year": 2013,

                        "categorised_data": {
                            "categories": {
                                "interval": [{
                                    "categories": {
                                        "percentile": [{
                                            "categories": {},
                                            "percentile": 5,
                                            "amount": 3.0
                                        }, {"categories": {}, "percentile": 10, "amount": 4.0}, {
                                            "categories": {},
                                            "percentile": 25,
                                            "amount": 5.0
                                        }, {"categories": {}, "percentile": 50, "amount": 7.0}, {
                                            "categories": {},
                                            "percentile": 75,
                                            "amount": 9.0
                                        }, {"categories": {}, "percentile": 90, "amount": 14.0}, {
                                            "categories": {},
                                            "percentile": 95,
                                            "amount": 18.0
                                        }]
                                    }, "interval": {"from": 70}, "n": 377, "dad": 8, "sa": 4, "min": 2, "max": 30
                                }]
                            }
                        }
                    }, {
                        "code": "A045",
                        "description": "Enteritis durch Campylobacter",
                        "year": 2013,
                        "icd_code_id": {"$oid": "5490074848e276ea1b793f79"},
                        "categorised_data": {
                            "categories": {
                                "interval": [{
                                    "categories": {
                                        "percentile": [{
                                            "categories": {},
                                            "percentile": 5,
                                            "amount": 3.0
                                        }, {"categories": {}, "percentile": 10, "amount": 3.0}, {
                                            "categories": {},
                                            "percentile": 25,
                                            "amount": 4.0
                                        }, {"categories": {}, "percentile": 50, "amount": 5.0}, {
                                            "categories": {},
                                            "percentile": 75,
                                            "amount": 6.0
                                        }, {"categories": {}, "percentile": 90, "amount": 8.0}, {
                                            "categories": {},
                                            "percentile": 95,
                                            "amount": 9.0
                                        }]
                                    },
                                    "interval": {"from": 40, "to": 69},
                                    "n": 415,
                                    "dad": 5,
                                    "sa": 2,
                                    "min": 1,
                                    "max": 19
                                }]
                            }
                        }
                    }, {
                        "code": "A045",
                        "description": "Enteritis durch Campylobacter",
                        "year": 2013,
                        "icd_code_id": {"$oid": "5490074848e276ea1b793f79"},
                        "categorised_data": {
                            "categories": {
                                "interval": [{
                                    "categories": {
                                        "percentile": [{
                                            "categories": {},
                                            "percentile": 5,
                                            "amount": 2.0
                                        }, {"categories": {}, "percentile": 10, "amount": 2.0}, {
                                            "categories": {},
                                            "percentile": 25,
                                            "amount": 2.0
                                        }, {"categories": {}, "percentile": 50, "amount": 3.0}, {
                                            "categories": {},
                                            "percentile": 75,
                                            "amount": 4.0
                                        }, {"categories": {}, "percentile": 90, "amount": 5.0}, {
                                            "categories": {},
                                            "percentile": 95,
                                            "amount": 5.0
                                        }]
                                    },
                                    "interval": {"from": 0, "to": 14},
                                    "n": 63,
                                    "dad": 3,
                                    "sa": 1,
                                    "min": 2,
                                    "max": 11
                                }]
                            }
                        }
                    }, {
                        "code": "A045",
                        "description": "Enteritis durch Campylobacter",
                        "year": 2013,
                        "icd_code_id": {"$oid": "5490074848e276ea1b793f79"},
                        "categorised_data": {
                            "categories": {
                                "interval": [{
                                    "categories": {
                                        "percentile": [{
                                            "categories": {},
                                            "percentile": 5,
                                            "amount": 2.0
                                        }, {"categories": {}, "percentile": 10, "amount": 2.0}, {
                                            "categories": {},
                                            "percentile": 25,
                                            "amount": 3.0
                                        }, {"categories": {}, "percentile": 50, "amount": 4.0}, {
                                            "categories": {},
                                            "percentile": 75,
                                            "amount": 5.0
                                        }, {"categories": {}, "percentile": 90, "amount": 6.0}, {
                                            "categories": {},
                                            "percentile": 95,
                                            "amount": 7.0
                                        }]
                                    },
                                    "interval": {"from": 15, "to": 39},
                                    "n": 322,
                                    "dad": 3,
                                    "sa": 1,
                                    "min": 2,
                                    "max": 11
                                }]
                            }
                        }
                    }];

        beforeEach(function(){

        });

	it("should be able to know that 1 = 1", function (){
            var converter = new DatasetSorter(datasets);

            var expectedResult = 1;

            expect(1).toEqual(expectedResult);
        });

    });
});<commit_msg>More DataSorter Tests<commit_after>define(['helpers/converters/DatasetSorter'], function(DatasetSorter){
    describe('DatasetSorter', function (){
        var sorter;
	var datasets = [{
                        "code": "A045",
                        "description": "Enteritis durch Campylobacter",
                        "year": 2013,

                        "categorised_data": {
                            "categories": {
                                "interval": [{
                                    "categories": {
                                        "percentile": [{
                                            "categories": {},
                                            "percentile": 5,
                                            "amount": 3.0
                                        }, {"categories": {}, "percentile": 10, "amount": 4.0}, {
                                            "categories": {},
                                            "percentile": 25,
                                            "amount": 5.0
                                        }, {"categories": {}, "percentile": 50, "amount": 7.0}, {
                                            "categories": {},
                                            "percentile": 75,
                                            "amount": 9.0
                                        }, {"categories": {}, "percentile": 90, "amount": 14.0}, {
                                            "categories": {},
                                            "percentile": 95,
                                            "amount": 18.0
                                        }]
                                    }, "interval": {"from": 70}, "n": 377, "dad": 8, "sa": 4, "min": 2, "max": 30
                                }]
                            }
                        }
                    }, {
                        "code": "A045",
                        "description": "Enteritis durch Campylobacter",
                        "year": 2013,
                        "icd_code_id": {"$oid": "5490074848e276ea1b793f79"},
                        "categorised_data": {
                            "categories": {
                                "interval": [{
                                    "categories": {
                                        "percentile": [{
                                            "categories": {},
                                            "percentile": 5,
                                            "amount": 3.0
                                        }, {"categories": {}, "percentile": 10, "amount": 3.0}, {
                                            "categories": {},
                                            "percentile": 25,
                                            "amount": 4.0
                                        }, {"categories": {}, "percentile": 50, "amount": 5.0}, {
                                            "categories": {},
                                            "percentile": 75,
                                            "amount": 6.0
                                        }, {"categories": {}, "percentile": 90, "amount": 8.0}, {
                                            "categories": {},
                                            "percentile": 95,
                                            "amount": 9.0
                                        }]
                                    },
                                    "interval": {"from": 40, "to": 69},
                                    "n": 415,
                                    "dad": 5,
                                    "sa": 2,
                                    "min": 1,
                                    "max": 19
                                }]
                            }
                        }
                    }, {
                        "code": "A045",
                        "description": "Enteritis durch Campylobacter",
                        "year": 2013,
                        "icd_code_id": {"$oid": "5490074848e276ea1b793f79"},
                        "categorised_data": {
                            "categories": {
                                "interval": [{
                                    "categories": {
                                        "percentile": [{
                                            "categories": {},
                                            "percentile": 5,
                                            "amount": 2.0
                                        }, {"categories": {}, "percentile": 10, "amount": 2.0}, {
                                            "categories": {},
                                            "percentile": 25,
                                            "amount": 2.0
                                        }, {"categories": {}, "percentile": 50, "amount": 3.0}, {
                                            "categories": {},
                                            "percentile": 75,
                                            "amount": 4.0
                                        }, {"categories": {}, "percentile": 90, "amount": 5.0}, {
                                            "categories": {},
                                            "percentile": 95,
                                            "amount": 5.0
                                        }]
                                    },
                                    "interval": {"from": 0, "to": 14},
                                    "n": 63,
                                    "dad": 3,
                                    "sa": 1,
                                    "min": 2,
                                    "max": 11
                                }]
                            }
                        }
                    }, {
                        "code": "A045",
                        "description": "Enteritis durch Campylobacter",
                        "year": 2013,
                        "icd_code_id": {"$oid": "5490074848e276ea1b793f79"},
                        "categorised_data": {
                            "categories": {
                                "interval": [{
                                    "categories": {
                                        "percentile": [{
                                            "categories": {},
                                            "percentile": 5,
                                            "amount": 2.0
                                        }, {"categories": {}, "percentile": 10, "amount": 2.0}, {
                                            "categories": {},
                                            "percentile": 25,
                                            "amount": 3.0
                                        }, {"categories": {}, "percentile": 50, "amount": 4.0}, {
                                            "categories": {},
                                            "percentile": 75,
                                            "amount": 5.0
                                        }, {"categories": {}, "percentile": 90, "amount": 6.0}, {
                                            "categories": {},
                                            "percentile": 95,
                                            "amount": 7.0
                                        }]
                                    },
                                    "interval": {"from": 15, "to": 39},
                                    "n": 322,
                                    "dad": 3,
                                    "sa": 1,
                                    "min": 2,
                                    "max": 11
                                }]
                            }
                        }
                    }];

        beforeEach(function(){

        });

	it("should be able to sort datasets", function (){
	    var sorter = new DatasetSorter(datasets);
            var sortedData = sorter.sortByIntervalsAscending();

	    var firstIntervalFrom = sortedData[0].categorised_data.categories.interval[0].interval.from;
	    var firstIntervalTo = sortedData[0].categorised_data.categories.interval[0].interval.to;
	    var secondIntervalFrom = sortedData[1].categorised_data.categories.interval[0].interval.from;
	    var secondIntervalTo = sortedData[1].categorised_data.categories.interval[0].interval.to;
	    var thirdIntervalFrom = sortedData[2].categorised_data.categories.interval[0].interval.from;
	    var thirdIntervalTo = sortedData[2].categorised_data.categories.interval[0].interval.to;
	    var fourthIntervalFrom = sortedData[3].categorised_data.categories.interval[0].interval.from;
	    var fourthIntervalTo = sortedData[3].categorised_data.categories.interval[0].interval.to;

	    expect(0).toEqual(firstIntervalFrom);
	    expect(14).toEqual(firstIntervalTo);
	    expect(15).toEqual(secondIntervalFrom);
	    expect(39).toEqual(secondIntervalTo);
	    expect(40).toEqual(thirdIntervalFrom);
	    expect(69).toEqual(thirdIntervalTo);
	    expect(70).toEqual(fourthIntervalFrom);
	    expect(undefined).toEqual(fourthIntervalTo);
        });

	it("should leave empty datasets alone", function() {
	    var datasets = [];
	    var sorter = new DatasetSorter(datasets);

	    var sortedDataset = sorter.sortByIntervalsAscending();

	    expect(datasets).toEqual(sortedDataset);
	});

    });
});<|endoftext|>


<commit_before>// Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %>
'use strict';

var gulp = require('gulp'),
    $ = require('gulp-load-plugins')(),
    minimist = require('minimist');

var paths = {
  styles: 'app/styles/**/*.scss',
  scripts: 'app/scripts/**/*.js',
  images: 'app/images/**/*.{gif,jpg,png,svg,webp}',
  extras: 'app/*.*',
  html: ['app/**/*.html'],
  index: 'app/**/_layout.html',
  clean: ['.tmp/*', 'public/**/*',
      '!public/assets', '!public/assets/**/*',
      '!public/index.php', '!public/.htaccess']
};

var knownOptions = {
  string: 'env',
  default: { env: process.env.NODE_ENV || 'staging' }
};

var options = minimist(process.argv.slice(2), knownOptions);

/**
 * gulp deploy-init
 */
gulp.task('deploy-init', function() {
  var server = options.env === 'production'
    ? '<%= remoteProduction %>'
    : '<%= remoteStaging %>';

  var branch = options.env === 'production'
    ? 'dokku-production'
    : 'dokku-staging';

  var slug = '<%= _.slugify(slug) %>';

  return gulp.src('')
    .pipe($.shell([
      'git remote add ' + branch + ' dokku@' + server + ':' + slug,
      'git push ' + branch + ' master',
      'ssh dokku@' + server + ' mariadb:create ' + slug,
      'ssh dokku@' + server + ' mariadb:link ' + slug + ' ' + slug + ''
    ]));
});

/**
 * gulp deploy
 */
gulp.task('deploy', function() {
  var branch = options.env === 'production'
    ? 'dokku-production'
    : 'dokku-staging';

  return gulp.src('')
    .pipe($.shell([
      'git push ' + branch + ' master'
    ]));
});

/**
 * gulp db-dump-local
 */
gulp.task('db-dump-local', ['build'], function() {
  var slug = '<%= _.slugify(slug) %>';

  return gulp.src('')
    .pipe($.shell([
      '[ -d ".tmp" ] || mkdir .tmp',
      'vagrant ssh --command "mysqldump -uroot -proot ' + slug + ' > /vagrant/.tmp/local.sql"'
    ]));
});

/**
 * gulp db-dump-remote
 */
gulp.task('db-dump-remote', ['build'], function() {
  var server = options.env === 'production'
    ? '<%= remoteProduction %>'
    : '<%= remoteStaging %>';

  var file = options.env === 'production'
    ? 'remote--production.sql'
    : 'remote--staging.sql';

  var slug = '<%= _.slugify(slug) %>';

  return gulp.src('')
    .pipe($.shell([
      '[ -d ".tmp" ] || mkdir .tmp',
      'ssh dokku@' + server + ' mariadb:dumpraw ' + slug + ' | tee .tmp/' + file + ' > /dev/null'
    ]));
});

/**
 * gulp db-push
 */
gulp.task('db-push', ['db-dump-local'], function() {
  var server = options.env === 'production'
    ? '<%= remoteProduction %>'
    : '<%= remoteStaging %>';

  var slug = '<%= _.slugify(slug) %>';

  return gulp.src('')
    .pipe($.shell([
      'ssh dokku@' + server + ' mariadb:console ' + slug + ' < .tmp/local.sql'
    ]));
});

/**
 * gulp db-pull
 */
gulp.task('db-pull', ['db-dump-remote'], function(){
  var file = options.env === 'production'
    ? 'remote--production.sql'
    : 'remote--staging.sql';

  var slug = '<%= _.slugify(slug) %>';

   return gulp.src('')
    .pipe($.shell([
      'vagrant ssh --command "mysql -uroot -proot ' + slug + ' < /vagrant/.tmp/ ' + file + '"'
    ]));
});

/**
 * gulp db-dump
 */
gulp.task('db-dump', [
    'clean',
    'db-dump-local',
    'db-dump-remote'
  ], function() {
    var file = options.env === 'production'
      ? 'remote--production.sql'
      : 'remote--staging.sql';

    return gulp.src([
        '.tmp/local.sql',
        '.tmp/ ' + file
      ])
      .pipe(gulp.dest('databases'));
});

/**
 * gulp styles
 */
gulp.task('styles', function() {
  return gulp.src([paths.styles])
    .pipe($.plumber())
    .pipe($.rubySass({
      loadPath: 'bower_components'
      style: 'expanded',
      precision: 10
    }))
    .pipe(gulp.dest('public/styles'))
});

/**
 * gulp scripts
 */
gulp.task('scripts', function() {
  return gulp.src(paths.scripts)
    .pipe($.changed('public/scripts'))
    .pipe($.jshint())
    .pipe($.jshint.reporter('jshint-stylish'))
    .pipe(gulp.dest('public/scripts'));
});

/**
 * gulp images
 */
gulp.task('images', function () {
  return gulp.src(paths.images)
    .pipe($.changed('public/images'))
    .pipe($.cache($.imagemin({
      progressive: true,
      interlaced: true
    })))
    .pipe(gulp.dest('public/images'));
});

/**
 * gulp extras
 */
gulp.task('extras', function() {
  return gulp.src(paths.extras, { dot: true })
    .pipe($.changed('public'))
    .pipe(gulp.dest('public'));
});

/**
 * gulp clean
 */
gulp.task('clean', function(cb) {
  require('del')(paths.clean, cb);
});

/**
 * gulp html
 */
gulp.task('html', function() {
  return gulp.src(paths.html)
    .pipe($.changed('public'))
    .pipe(gulp.dest('public'));
})

/**
 * gulp build
 */
gulp.task('build', ['clean'], function() {
  gulp.start('build-useref');
});

/**
 * gulp build-useref
 */
gulp.task('build-useref', [
    'html',
    'images',
    'scripts',
    'styles',
    'extras'
  ], function() {
  var assets = $.useref.assets({searchPath: '{public,app}'});

  return gulp.src(paths.index)
    .pipe($.if(options.env !== 'production',
      $.multinject(['http://localhost:35729/livereload.js?snipver=1'], 'livereload')
    ))
    .pipe(assets)
    .pipe($.if(options.env === 'production', $.if('*.js', $.uglify())))
    .pipe($.if(options.env === 'production', $.if('*.css', $.csso())))
    .pipe($.if(options.env === 'production', $.if('*.css', $.autoprefixer('last 1 version'))))
    .pipe(assets.restore())
    .pipe($.useref())
    .pipe(gulp.dest('public'));
});

/**
 * gulp watch
 */
gulp.task('watch', function() {
  gulp.start('build-useref');

  $.livereload.listen();
  gulp.watch('public/**/*', $.livereload.changed);

  gulp.watch(paths.extras,  ['extras']);
  gulp.watch(paths.html,    ['html']);
  gulp.watch(paths.index,   ['build-useref']);
  gulp.watch(paths.scripts, ['scripts']);
  gulp.watch(paths.styles,  ['styles']);
  gulp.watch(paths.images,  ['images']);
});

/**
 * gulp
 */
gulp.task('default', ['build']);<commit_msg>gulpfile<commit_after>// Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %>
'use strict';

var gulp = require('gulp'),
    $ = require('gulp-load-plugins')(),
    minimist = require('minimist');

var paths = {
  styles: 'app/styles/**/*.scss',
  scripts: 'app/scripts/**/*.js',
  images: 'app/images/**/*.{gif,jpg,png,svg,webp}',
  extras: 'app/*.*',
  html: ['app/**/*.html'],
  index: 'app/**/_layout.html',
  clean: ['.tmp/*', 'public/**/*',
      '!public/assets', '!public/assets/**/*',
      '!public/index.php', '!public/.htaccess']
};

var knownOptions = {
  string: 'env',
  default: { env: process.env.NODE_ENV || 'staging' }
};

var options = minimist(process.argv.slice(2), knownOptions);

/**
 * gulp deploy-init
 */
gulp.task('deploy-init', function() {
  var server = options.env === 'production'
    ? '<%= remoteProduction %>'
    : '<%= remoteStaging %>';

  var branch = options.env === 'production'
    ? 'dokku-production'
    : 'dokku-staging';

  var slug = '<%= _.slugify(slug) %>';

  return gulp.src('')
    .pipe($.shell([
      'git remote add ' + branch + ' dokku@' + server + ':' + slug,
      'git push ' + branch + ' master',
      'ssh dokku@' + server + ' mariadb:create ' + slug,
      'ssh dokku@' + server + ' mariadb:link ' + slug + ' ' + slug + ''
    ]));
});

/**
 * gulp deploy
 */
gulp.task('deploy', function() {
  var branch = options.env === 'production'
    ? 'dokku-production'
    : 'dokku-staging';

  return gulp.src('')
    .pipe($.shell([
      'git push ' + branch + ' master'
    ]));
});

/**
 * gulp db-dump-local
 */
gulp.task('db-dump-local', ['build'], function() {
  var slug = '<%= _.slugify(slug) %>';

  return gulp.src('')
    .pipe($.shell([
      '[ -d ".tmp" ] || mkdir .tmp',
      'vagrant ssh --command "mysqldump -uroot -proot ' + slug + ' > /vagrant/.tmp/local.sql"'
    ]));
});

/**
 * gulp db-dump-remote
 */
gulp.task('db-dump-remote', ['build'], function() {
  var server = options.env === 'production'
    ? '<%= remoteProduction %>'
    : '<%= remoteStaging %>';

  var file = options.env === 'production'
    ? 'remote--production.sql'
    : 'remote--staging.sql';

  var slug = '<%= _.slugify(slug) %>';

  return gulp.src('')
    .pipe($.shell([
      '[ -d ".tmp" ] || mkdir .tmp',
      'ssh dokku@' + server + ' mariadb:dumpraw ' + slug + ' | tee .tmp/' + file + ' > /dev/null'
    ]));
});

/**
 * gulp db-push
 */
gulp.task('db-push', ['db-dump-local'], function() {
  var server = options.env === 'production'
    ? '<%= remoteProduction %>'
    : '<%= remoteStaging %>';

  var slug = '<%= _.slugify(slug) %>';

  return gulp.src('')
    .pipe($.shell([
      'ssh dokku@' + server + ' mariadb:console ' + slug + ' < .tmp/local.sql'
    ]));
});

/**
 * gulp db-pull
 */
gulp.task('db-pull', ['db-dump-remote'], function(){
  var file = options.env === 'production'
    ? 'remote--production.sql'
    : 'remote--staging.sql';

  var slug = '<%= _.slugify(slug) %>';

   return gulp.src('')
    .pipe($.shell([
      'vagrant ssh --command "mysql -uroot -proot ' + slug + ' < /vagrant/.tmp/ ' + file + '"'
    ]));
});

/**
 * gulp db-dump
 */
gulp.task('db-dump', [
    'clean',
    'db-dump-local',
    'db-dump-remote'
  ], function() {
    var file = options.env === 'production'
      ? 'remote--production.sql'
      : 'remote--staging.sql';

    return gulp.src([
        '.tmp/local.sql',
        '.tmp/ ' + file
      ])
      .pipe(gulp.dest('databases'));
});

/**
 * gulp styles
 */
gulp.task('styles', function() {
  return gulp.src(paths.styles)
    .pipe($.plumber())
    .pipe($.rubySass({
      loadPath: 'bower_components',
      style: 'expanded',
      precision: 10
    }))
    .pipe(gulp.dest('public/styles'))
});

/**
 * gulp scripts
 */
gulp.task('scripts', function() {
  return gulp.src(paths.scripts)
    .pipe($.changed('public/scripts'))
    .pipe($.jshint())
    .pipe($.jshint.reporter('jshint-stylish'))
    .pipe(gulp.dest('public/scripts'));
});

/**
 * gulp images
 */
gulp.task('images', function () {
  return gulp.src(paths.images)
    .pipe($.changed('public/images'))
    .pipe($.cache($.imagemin({
      progressive: true,
      interlaced: true
    })))
    .pipe(gulp.dest('public/images'));
});

/**
 * gulp extras
 */
gulp.task('extras', function() {
  return gulp.src(paths.extras, { dot: true })
    .pipe($.changed('public'))
    .pipe(gulp.dest('public'));
});

/**
 * gulp clean
 */
gulp.task('clean', function(cb) {
  require('del')(paths.clean, cb);
});

/**
 * gulp html
 */
gulp.task('html', function() {
  return gulp.src(paths.html)
    .pipe($.changed('public'))
    .pipe(gulp.dest('public'));
})

/**
 * gulp build
 */
gulp.task('build', ['clean'], function() {
  gulp.start('build-useref');
});

/**
 * gulp build-useref
 */
gulp.task('build-useref', [
    'html',
    'images',
    'scripts',
    'styles',
    'extras'
  ], function() {
  var assets = $.useref.assets({searchPath: '{public,app}'});

  return gulp.src(paths.index)
    .pipe($.if(options.env !== 'production',
      $.multinject(['http://localhost:35729/livereload.js?snipver=1'], 'livereload')
    ))
    .pipe(assets)
    .pipe($.if(options.env === 'production', $.if('*.js', $.uglify())))
    .pipe($.if(options.env === 'production', $.if('*.css', $.csso())))
    .pipe($.if(options.env === 'production', $.if('*.css', $.autoprefixer('last 1 version'))))
    .pipe(assets.restore())
    .pipe($.useref())
    .pipe(gulp.dest('public'));
});

/**
 * gulp watch
 */
gulp.task('watch', function() {
  gulp.start('build-useref');

  $.livereload.listen();
  gulp.watch('public/**/*', $.livereload.changed);

  gulp.watch(paths.extras,  ['extras']);
  gulp.watch(paths.html,    ['html']);
  gulp.watch(paths.index,   ['build-useref']);
  gulp.watch(paths.scripts, ['scripts']);
  gulp.watch(paths.styles,  ['styles']);
  gulp.watch(paths.images,  ['images']);
});

/**
 * gulp
 */
gulp.task('default', ['build']);<|endoftext|>


<commit_before>'use strict';

//Initial few tests, need to expand.

var chai = require('chai'),
	chaiModel = require('./helpers/canvas.js'),
	assert = require('chai').assert,
	expect = require('chai').expect;

chai.use(chaiModel);

var Canvas = require('../canvas/canvas.js');

console.log('canvas tests yet to be fully implemented');
//note: working on canvas-connector tests first.

describe('Canvas', function() {

	//Test Canvas Creation
    describe('#new Canvas()', function () {
        var canvas = new Canvas();
        it('new canvas should be of the Canvas class', function (){
            expect(canvas).to.be.a.canvas(Canvas.type);
        });

        /*

        it('new connector should have the colour "Blue"', function (){
            assert.equal(connector.colour, 'Blue', 'New Connector should be Blue');
            //expect(connector).to.be.a.connector(Connector.type);
        });
		*/

    });
});
<commit_msg>updated connector drawing function<commit_after>'use strict';

//Initial few tests, need to expand.

var chai = require('chai'),
	chaiModel = require('./helpers/canvas.js'),
	assert = require('chai').assert,
	expect = require('chai').expect;

chai.use(chaiModel);

var Canvas = require('../canvas/canvas.js');

console.log('canvas tests yet to be fully implemented');
//note: working on canvas-connector tests first.

describe('Canvas', function() {

	//var canvas=document.getElementById("canvas");

	//Test Canvas Creation
    describe('#new Canvas()', function () {
        var canvas = new Canvas();
        it('new canvas should be of the Canvas class', function (){
            expect(canvas).to.be.a.canvas(Canvas.type);
        });

        /*

        it('new connector should have the colour "Blue"', function (){
            assert.equal(connector.colour, 'Blue', 'New Connector should be Blue');
            //expect(connector).to.be.a.connector(Connector.type);
        });
		*/

    });

    describe('#initialized Canvas()', function () {
        var canvas = new Canvas();
        var context = null;  // need to mock the context element
        canvas.initialize(context, 'new canvas');

        it('initialized canvas should be of the Canvas class', function (){
            expect(canvas).to.be.a.canvas(Canvas.type);
        });

        it('initialized canvas should start in the stopped state', function (){
            assert.equal(canvas.getState == 'stop');
            //expect(connector).to.be.a.connector(Connector.type);
        });

    });

});
<|endoftext|>


<commit_before>var expect  = require("chai").expect;
var request = require("request");

describe("Applicant Server", function() {
    describe("Applicants List", function() {
      var url = "http://localhost:8082/applicants";

      it("returns dummy applicants", function(done) {
        request(url, function(error, response, body) {
          expect(response.statusCode).to.equal(200);

          var data = JSON.parse(body);
          expect(data).to.have.length(4);
          expect(data[0].name).to.equal('Joe Schweitzer');

          done();
        });
      });
    });

    describe("Search", function() {
      var url = "http://localhost:8082/search";

      it("returns dummy applicants", function(done) {
        request(url, function(error, response, body) {
          expect(response.statusCode).to.equal(200);

          var data = JSON.parse(body);
          expect(data).to.have.length(4);
          expect(data[0].name).to.equal('Joe Schweitzer');

          done();
        });
      });
    });
});
<commit_msg>fixed test<commit_after>var expect  = require("chai").expect;
var request = require("request");

describe("Applicant Server", function() {
    describe("Applicants List", function() {
      var url = "http://localhost:8082/applicants";

      it("returns dummy applicants", function(done) {
        request(url, function(error, response, body) {
          expect(response.statusCode).to.equal(200);

          var data = JSON.parse(body);
          expect(data).to.have.length(4);
          expect(data[0].name).to.equal('Joe Schweitzer');

          done();
        });
      });
    });

    describe("Search", function() {
      var url = "http://localhost:8082/search";

      it("returns dummy applicants", function(done) {
        request(url, function(error, response, body) {
          expect(response.statusCode).to.equal(200);

          var data = JSON.parse(body);
          expect(data).to.have.length(3);
          expect(data[0].name).to.equal('Joe Schweitzer');

          done();
        });
      });
    });
});
<|endoftext|>


<commit_before>import getItemModelName from 'appkit/utils/model';

export default {
  baseUrl: 'http://server.webhook.com/search/',

  search: function (query, page, typeName) {

    Ember.Logger.log('searchIndex::search', arguments);

    if (Ember.isNone(query)) {
      return Ember.RSVP.Promise.reject(new Ember.Error('Search query is required.'));
    }

    return new Ember.RSVP.Promise(function (resolve, reject) {

      window.ENV.search(query, page || 1, typeName || null, function(error, results) {
        if (error) {
          Ember.Logger.warn('searchIndex::search::error', error);
          reject(error);
        } else {
          Ember.Logger.info('searchIndex::search::results', results);
          resolve(results);
        }
      });
    });

  },

  indexItem: function (item, contentType) {

    var searchData = {};

    // Simplify search indexing by storing all objects as strings.
    Ember.$.each(item.get('data'), function (key, value) {
      if (typeof value === 'object') {
        searchData[key] = JSON.stringify(value);
      } else {
        searchData[key] = value;
      }
    });

    return Ember.$.ajax({
      url: this.baseUrl + 'index/',
      type: 'POST',
      data: Ember.$.extend(this.siteAndToken(), {
        id: item.get('id'),
        data: JSON.stringify(searchData),
        typeName: contentType.get('id'),
        oneOff: contentType.get('oneOff')
      })
    });
  },

  indexType: function (contentType) {

    var indexItem = this.indexItem.bind(this);
    var modelName = getItemModelName(contentType);
    var store = window.App.__container__.lookup('store:main');

    return new Ember.RSVP.Promise(function (resolve, reject) {
      store.find(modelName).then(function (items) {

        var idsToDelete = [1,2,3];

        return items.reduce(function (cur, next) {
          return cur.then(function () {
            return indexItem(next, contentType);
          });
        }, Ember.RSVP.resolve());

        // var itemPromises = [];
        //
        // items.forEach(function (item) {
        //   itemPromises.push(indexItem(item, contentType));
        // });
        //
        // Ember.RSVP.Promise.all(itemPromises).then(resolve).catch(reject);

      });

    });
  },

  indexSite: function () {
    var store = window.App.__container__.lookup('store:main');
    var indexType = this.indexType.bind(this);

    return new Ember.RSVP.Promise(function (resolve, reject) {
      store.find('contentType').then(function (contentTypes) {

        var contentTypePromises = [];

        contentTypes.forEach(function (contentType) {
          contentTypePromises.push(indexType(contentType));
        });

        Ember.RSVP.Promise.all(contentTypePromises).then(resolve).catch(reject);

      });

    });

  },

  deleteItem: function (item, contentType) {
    return Ember.$.ajax({
      url: this.baseUrl + 'delete/',
      type: 'POST',
      data: Ember.$.extend(this.siteAndToken(), {
        id: item.get('id'),
        typeName: contentType.get('id')
      })
    });
  },

  deleteType: function (contentType) {
    return Ember.$.ajax({
      url: this.baseUrl + 'delete/type/',
      type: 'POST',
      data: Ember.$.extend(this.siteAndToken(), {
        typeName: contentType.get('id')
      })
    });
  },

  deleteSite: function () {
    return Ember.$.ajax({
      url: this.baseUrl + 'delete/index/',
      type: 'POST',
      data: this.siteAndToken()
    });
  },

  reindex: function () {

    return this.deleteSite().then(this.indexSite.bind(this));

  },

  siteAndToken: function () {
    var session = window.App.__container__.lookup('controller:application').get('session');

    return {
      site: session.get('site.name'),
      token: session.get('site.token')
    };
  }

};
<commit_msg>cleanup and add logging<commit_after>import getItemModelName from 'appkit/utils/model';

export default {
  baseUrl: 'http://server.webhook.com/search/',

  search: function (query, page, typeName) {

    Ember.Logger.log('searchIndex::search', arguments);

    if (Ember.isNone(query)) {
      return Ember.RSVP.Promise.reject(new Ember.Error('Search query is required.'));
    }

    return new Ember.RSVP.Promise(function (resolve, reject) {

      window.ENV.search(query, page || 1, typeName || null, function(error, results) {
        if (error) {
          Ember.Logger.warn('searchIndex::search::error', error);
          reject(error);
        } else {
          Ember.Logger.info('searchIndex::search::results', results);
          resolve(results);
        }
      });
    });

  },

  indexItem: function (item, contentType) {

    var searchData = {};

    // Simplify search indexing by storing all objects as strings.
    Ember.$.each(item.get('data'), function (key, value) {
      if (typeof value === 'object') {
        searchData[key] = JSON.stringify(value);
      } else {
        searchData[key] = value;
      }
    });

    var ajaxData = Ember.$.extend(this.siteAndToken(), {
      id: item.get('id'),
      data: JSON.stringify(searchData),
      typeName: contentType.get('id'),
      oneOff: contentType.get('oneOff')
    });

    Ember.Logger.log("SearchIndex::indexItem::%@::%@".fmt(contentType.get('id'), item.get('data.name')), ajaxData);

    return Ember.$.ajax({
      url: this.baseUrl + 'index/',
      type: 'POST',
      data: ajaxData
    });
  },

  indexType: function (contentType) {

    var indexItem = this.indexItem.bind(this);
    var modelName = getItemModelName(contentType);
    var store = window.App.__container__.lookup('store:main');

    return new Ember.RSVP.Promise(function (resolve, reject) {
      store.find(modelName).then(function (items) {

        return items.reduce(function (cur, next) {
          return cur.then(function () {
            return indexItem(next, contentType);
          });
        }, Ember.RSVP.resolve());

      });

    });
  },

  indexSite: function () {
    var store = window.App.__container__.lookup('store:main');
    var indexType = this.indexType.bind(this);

    return new Ember.RSVP.Promise(function (resolve, reject) {
      store.find('contentType').then(function (contentTypes) {

        var contentTypePromises = [];

        contentTypes.forEach(function (contentType) {
          contentTypePromises.push(indexType(contentType));
        });

        Ember.RSVP.Promise.all(contentTypePromises).then(resolve).catch(reject);

      });

    });

  },

  deleteItem: function (item, contentType) {
    return Ember.$.ajax({
      url: this.baseUrl + 'delete/',
      type: 'POST',
      data: Ember.$.extend(this.siteAndToken(), {
        id: item.get('id'),
        typeName: contentType.get('id')
      })
    });
  },

  deleteType: function (contentType) {
    return Ember.$.ajax({
      url: this.baseUrl + 'delete/type/',
      type: 'POST',
      data: Ember.$.extend(this.siteAndToken(), {
        typeName: contentType.get('id')
      })
    });
  },

  deleteSite: function () {
    return Ember.$.ajax({
      url: this.baseUrl + 'delete/index/',
      type: 'POST',
      data: this.siteAndToken()
    });
  },

  reindex: function () {

    return this.deleteSite().then(this.indexSite.bind(this));

  },

  siteAndToken: function () {
    var session = window.App.__container__.lookup('controller:application').get('session');

    return {
      site: session.get('site.name'),
      token: session.get('site.token')
    };
  }

};
<|endoftext|>


<commit_before>/* Shots View - displays a list of shots */

var ShotModelFirebase = require('../models/shotModelFirebase.js');
var ShotModel = require('../models/shotModel.js');
var ShotView = require('../views/shotView.js');
var shotsTemplate = require('./templates/shotsTemplate.hbs');

module.exports = Backbone.View.extend({
    el: '.shots',

    template: shotsTemplate,

    initialize: function(options) {
      this.render();

      this.project = options.project;  // Save project name in case we need to add

      var view = this;

      /*this.collection.bind('add', function(shot) {
        view.$el.append(new ShotView({model: shot}).render().el);
      }); */

      this.collection.bind('all', function(name, e) {
        console.log(name);
      });
    },

    events: {
      'click .save': 'createShot'
    },

    createShot: function(shot) {

      if($('#text').val()) {
        var input = {
          id: $('#text').val()
        };

        tmp = this.collection.create(input);

        $('#text').val('');
      }
    },

    render: function() {
      // Display 'new shot' menu

      // var model = new ShotModel({id: 'testing'});
      this.collection.add({id: 'test_shot'});
      console.log(this.collection.toJSON());
      this.collection.save();

      this.$el.append(this.template());
      // Display each shot in a list
      /*if(_.size(this.collection) > 0) {
        // Only do this if we have shots
        var view = this;  // this.collection.each overrides this to refer to current collection

        this.collection.each(function(shotModel) {
          var shotView = new ShotView({model: shotModel});
          view.$el.append(shotView.el);
        });
      } */
    }
  });
<commit_msg>Removed debugging shots view<commit_after><|endoftext|>


<commit_before>/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib 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.
*/

'use strict';

// MODULES //

var PINF = require( '@stdlib/constants/math/float64-pinf' );
var NINF = require( '@stdlib/constants/math/float64-ninf' );

// MAIN //

/**
* Returns an accumulator function which incrementally computes a mid-range.
*
* @returns {Function} accumulator function
*
* @example
* var accumulator = incrmidrange();
*/
function incrmidrange() {
	var max = NINF;
	var min = PINF;
	var sum = null;

	return accumulator;

	/**
	* If provided a value, the accumulator function returns an updated mid-range. If not provided a value, the accumulator function returns the current mid-range.
	*
	* @private
	* @param {number} [x] - new value
	* @returns {number} mid-range
	*
	* @example
	* var midrange = accumulator();
	* // returns null
	*
	* midrange = accumulator( 3.14 );
	* // returns 3.14
	*
	* midrange = accumulator( -5.0 );
	* // returns ~-0.93
	*
	* midrange = accumulator( 10.1 );
	* // returns 2.55
	*
	* midrange = accumulator();
	* // returns 2.55
	*/
	function accumulator( x ) {
		if ( arguments.length === 0 ) {
			if ( sum === null ) {
				return sum;
			}
			return sum / 2.0;
		}
		if ( x > max ) {
			max = x;
		}
		if ( x < min ) {
			min = x;
		}
		sum = max + min;
		return sum / 2.0;
	}
}

// EXPORTS //

module.exports = incrmidrange;
<commit_msg>Avoid switching types<commit_after>/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib 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.
*/

'use strict';

// MODULES //

var PINF = require( '@stdlib/constants/math/float64-pinf' );
var NINF = require( '@stdlib/constants/math/float64-ninf' );

// MAIN //

/**
* Returns an accumulator function which incrementally computes a mid-range.
*
* @returns {Function} accumulator function
*
* @example
* var accumulator = incrmidrange();
*/
function incrmidrange() {
	var max = NINF;
	var min = PINF;
	var sum;

	return accumulator;

	/**
	* If provided a value, the accumulator function returns an updated mid-range. If not provided a value, the accumulator function returns the current mid-range.
	*
	* @private
	* @param {number} [x] - new value
	* @returns {number} mid-range
	*
	* @example
	* var midrange = accumulator();
	* // returns null
	*
	* midrange = accumulator( 3.14 );
	* // returns 3.14
	*
	* midrange = accumulator( -5.0 );
	* // returns ~-0.93
	*
	* midrange = accumulator( 10.1 );
	* // returns 2.55
	*
	* midrange = accumulator();
	* // returns 2.55
	*/
	function accumulator( x ) {
		if ( arguments.length === 0 ) {
			if ( sum === void 0 ) {
				return null;
			}
			return sum / 2.0;
		}
		if ( x > max ) {
			max = x;
		}
		if ( x < min ) {
			min = x;
		}
		sum = max + min;
		return sum / 2.0;
	}
}

// EXPORTS //

module.exports = incrmidrange;
<|endoftext|>


<commit_before>'use strict';
const _ = require('lodash');
const db = require('../schemas');

class MemberWorkTime {
    static findByProjectIdAndUserId (projectId, userId, options = {}) {
        return db.transaction({transaction: options.transaction}, async transaction => {
            const member = await db.Member.findOne({where: {projectId, userId}, transaction});
            if (!member) { return []; }
            const workTimes = db.MemberWorkTime.findAll(_.assign({memberId: member.id}, options, {transaction}));
            return workTimes.map(x => x.toJSON());
        });
    }

    static findByProjectId (projectId, options = {}) {
        return db.transaction({transaction: options.transaction}, async transaction => {
            const members = await db.Member.findAll({where: {projectId}, transaction});
            const res = [];
            for (let member of members) {
                const workTimes = await db.MemberWorkTime.findAll(_.assign({where: {memberId: member.id}}, options, {transaction}));
                workTimes.forEach(workTime => {
                    res.push(_.assign(workTime.toJSON(), {userId: member.userId}));
                });
            }
            return res;
        });
    }

    static create (projectId, userId, iterationId, {promisedMinutes, actualMinutes = 0}, {transaction} = {}) {
        return db.transaction({transaction}, async transaction => {
            const member = await db.Member.findOne({where: {projectId, userId}, transaction});
            if (!member) { throw new Error(`member was not found given {projectId: ${projectId}, userId: ${userId}}`); }

            const res = await db.MemberWorkTime.create({
                memberId: member.id,
                projectId,
                iterationId,
                promisedMinutes,
                actualMinutes
            });

            return res.toJSON();
        });
    }

    static updatePromisedWorkTime (projectId, userId, iterationId, promisedMinutes, {transaction} = {}) {
        return db.transaction({transaction}, async transaction => {
            const member = await db.Member.findOne({where: {projectId, userId}, transaction});
            if (!member) { throw new Error(`member was not found by {projectId: ${projectId}, userId: ${userId}}`); }

            const memberWorkTime = await db.MemberWorkTime.findOne({
                where: {memberId: member.id, iterationId},
                transaction
            });

            let res;
            if (memberWorkTime) {
                await db.MemberWorkTime.update({promisedMinutes}, {where: {id: memberWorkTime.id}}, transaction);
                res = await db.MemberWorkTime.findOne({where: {id: memberWorkTime.id}}, transaction);
            } else {
                res = await db.MemberWorkTime.create({
                    memberId: member.id,
                    iterationId,
                    promisedMinutes
                }, {transaction});
            }

            return _.assign(res.toJSON(), {userId: member.userId});
        });
    }

    static calcAll (projectId, {transaction} = {}) {
        return db.transaction({transaction}, async transaction => {
            const tasks = await db.Task.findAll({
                where: {projectId},
                include: [{model: db.Work, as: 'works', separate: true}],
                transaction
            });
            const works = _.chain(tasks).map(x => x.works || []).flatten().filter(x => x.isEnded).value();

            const members = await db.Member.findAll({where: {projectId}, transaction});
            const iterations = await db.Iteration.findAll({where: {projectId}, transaction});

            const memberWorks = {};
            members.forEach(x => { memberWorks[x.userId] = []; });
            works.forEach(work => memberWorks[work.userId].push(work));

            const actualTimes = [];

            for (let member of members) {
                for (let iteration of iterations) {
                    const works = memberWorks[member.userId];
                    const time = MemberWorkTime._calcOneIterationWorkTime(works, iteration.startTime, iteration.endTime);
                    actualTimes.push({memberId: member.id, iterationId: iteration.id, time});
                }
            }

            for (let {memberId, iterationId, time} of actualTimes) {
                const memberWorkTime = await db.MemberWorkTime.findOne({where: {memberId, iterationId}, transaction});

                const actualMinutes = Math.floor(time / 60 / 1000);

                if (memberWorkTime) {
                    await db.MemberWorkTime.update({actualMinutes}, {where: {id: memberWorkTime.id}}, transaction);
                } else {
                    await db.MemberWorkTime.create({
                        memberId,
                        iterationId,
                        promisedMinutes: 0,
                        actualMinutes
                    }, {transaction});
                }
            }

            return actualTimes;
        });
    }

    static _calcOneIterationWorkTime (works, start, end) {
        return works.reduce((sum, work) => {
            const s = Number(new Date(work.startTime));
            const e = Number(new Date(work.endTime));
            const time = MemberWorkTime._calcDuplicationTime(start, end, s, e);
            return sum + time;
        }, 0);
    }

    static _calcDuplicationTime (s1, e1, s2, e2) {
        if (s1 > s2) { return MemberWorkTime._calcDuplicationTime(s2, e2, s1, e1); }
        if (e1 <= s2) { return 0; }
        if (e1 < e2) { return e1 - s2; }
        return e2 - s2;
    }
}

module.exports = MemberWorkTime;

<commit_msg>fix stats transaction<commit_after>'use strict';
const _ = require('lodash');
const db = require('../schemas');

class MemberWorkTime {
    static findByProjectIdAndUserId (projectId, userId, options = {}) {
        return db.transaction({transaction: options.transaction}, async transaction => {
            const member = await db.Member.findOne({where: {projectId, userId}, transaction});
            if (!member) { return []; }
            const workTimes = db.MemberWorkTime.findAll(_.assign({memberId: member.id}, options, {transaction}));
            return workTimes.map(x => x.toJSON());
        });
    }

    static findByProjectId (projectId, options = {}) {
        return db.transaction({transaction: options.transaction}, async transaction => {
            const members = await db.Member.findAll({where: {projectId}, transaction});
            const res = [];
            for (let member of members) {
                const workTimes = await db.MemberWorkTime.findAll(_.assign({where: {memberId: member.id}}, options, {transaction}));
                workTimes.forEach(workTime => {
                    res.push(_.assign(workTime.toJSON(), {userId: member.userId}));
                });
            }
            return res;
        });
    }

    static create (projectId, userId, iterationId, {promisedMinutes, actualMinutes = 0}, {transaction} = {}) {
        return db.transaction({transaction}, async transaction => {
            const member = await db.Member.findOne({where: {projectId, userId}, transaction});
            if (!member) { throw new Error(`member was not found given {projectId: ${projectId}, userId: ${userId}}`); }

            const res = await db.MemberWorkTime.create({
                memberId: member.id,
                projectId,
                iterationId,
                promisedMinutes,
                actualMinutes
            });

            return res.toJSON();
        });
    }

    static updatePromisedWorkTime (projectId, userId, iterationId, promisedMinutes, {transaction} = {}) {
        return db.transaction({transaction}, async transaction => {
            const member = await db.Member.findOne({where: {projectId, userId}, transaction});
            if (!member) { throw new Error(`member was not found by {projectId: ${projectId}, userId: ${userId}}`); }

            const memberWorkTime = await db.MemberWorkTime.findOne({
                where: {memberId: member.id, iterationId},
                transaction
            });

            let res;
            if (memberWorkTime) {
                await db.MemberWorkTime.update({promisedMinutes}, {where: {id: memberWorkTime.id}, transaction});
                res = await db.MemberWorkTime.findOne({where: {id: memberWorkTime.id}, transaction});
            } else {
                res = await db.MemberWorkTime.create({
                    memberId: member.id,
                    iterationId,
                    promisedMinutes
                }, {transaction});
            }

            return _.assign(res.toJSON(), {userId: member.userId});
        });
    }

    static calcAll (projectId, {transaction} = {}) {
        return db.transaction({transaction}, async transaction => {
            const tasks = await db.Task.findAll({
                where: {projectId},
                include: [{model: db.Work, as: 'works', separate: true}],
                transaction
            });
            const works = _.chain(tasks).map(x => x.works || []).flatten().filter(x => x.isEnded).value();

            const members = await db.Member.findAll({where: {projectId}, transaction});
            const iterations = await db.Iteration.findAll({where: {projectId}, transaction});

            const memberWorks = {};
            members.forEach(x => { memberWorks[x.userId] = []; });
            works.forEach(work => memberWorks[work.userId].push(work));

            const actualTimes = [];

            for (let member of members) {
                for (let iteration of iterations) {
                    const works = memberWorks[member.userId];
                    const time = MemberWorkTime._calcOneIterationWorkTime(works, iteration.startTime, iteration.endTime);
                    actualTimes.push({memberId: member.id, iterationId: iteration.id, time});
                }
            }

            for (let {memberId, iterationId, time} of actualTimes) {
                const memberWorkTime = await db.MemberWorkTime.findOne({where: {memberId, iterationId}, transaction});

                const actualMinutes = Math.floor(time / 60 / 1000);

                if (memberWorkTime) {
                    await db.MemberWorkTime.update({actualMinutes}, {where: {id: memberWorkTime.id}}, transaction);
                } else {
                    await db.MemberWorkTime.create({
                        memberId,
                        iterationId,
                        promisedMinutes: 0,
                        actualMinutes
                    }, {transaction});
                }
            }

            return actualTimes;
        });
    }

    static _calcOneIterationWorkTime (works, start, end) {
        return works.reduce((sum, work) => {
            const s = Number(new Date(work.startTime));
            const e = Number(new Date(work.endTime));
            const time = MemberWorkTime._calcDuplicationTime(start, end, s, e);
            return sum + time;
        }, 0);
    }

    static _calcDuplicationTime (s1, e1, s2, e2) {
        if (s1 > s2) { return MemberWorkTime._calcDuplicationTime(s2, e2, s1, e1); }
        if (e1 <= s2) { return 0; }
        if (e1 < e2) { return e1 - s2; }
        return e2 - s2;
    }
}

module.exports = MemberWorkTime;

<|endoftext|>


<commit_before>Template.editPointForm.helpers({
  services: function () {
    return Services.find();
  },
  topics: function () {
    return Topics.find();
  },
  currentUserEmailAddress: function () {
    return Meteor.user() ? Meteor.user().emails[0].address : '';
  },
  pointChecked: function (pointValue) {
    return this.tosdr.point === pointValue ? 'checked' : '';
  },
  pointBinding: function (pointValue) {
    return this.tosdr.binding ? 'checked' : '';
  },
  pointIrrelevant: function (pointValue) {
    return this.tosdr.irrelevant ? 'checked' : '';
  },
  pointDisputed: function (pointValue) {
    return this.tosdr.disputed ? 'checked' : '';
  },
  source: function () {
    if (this.tosdr.sources && this.tosdr.sources[0]) {
      return this.tosdr.sources[0];
    } else {
      return '';
    }
  },
  disabled: function () {
    if (!utils.isModerator()) {
      return 'disabled';
    }
  }
});

Template.editPointForm.rendered = function () {
  $("#services").select2({placeholder: "Select at least one service"});
  $("#topics").select2({placeholder: "Select at least one topic"});
};

function isOptionSelected(selectedValues) {
  return _.contains(selectedValues, this.id) ? 'selected' : '';
}

var selectOption = {
  isSelected: isOptionSelected
}

Template.serviceOption.helpers(selectOption);
Template.topicOption.helpers(selectOption);
<commit_msg>Fixes #36<commit_after>Template.editPointForm.helpers({
  services: function () {
    return Services.find();
  },
  topics: function () {
    return Topics.find();
  },
  currentUserEmailAddress: function () {
    return Meteor.user() ? Meteor.user().emails[0].address : '';
  },
  pointChecked: function (pointValue) {
    return this.tosdr.point === pointValue ? 'checked' : '';
  },
  pointBinding: function (pointValue) {
    return this.tosdr.binding ? 'checked' : '';
  },
  pointIrrelevant: function (pointValue) {
    return this.tosdr.irrelevant ? 'checked' : '';
  },
  pointDisputed: function (pointValue) {
    return this.tosdr.disputed ? 'checked' : '';
  },
  source: function () {
    if (this.tosdr.sources && this.tosdr.sources[0]) {
      return this.tosdr.sources[0];
    } else {
      return '';
    }
  },
  disabled: function () {
    if (!utils.isModerator() && Iron.Location.get().path !== '/points/submit') {
      return 'disabled';
    }
  }
});

Template.editPointForm.rendered = function () {
  $("#services").select2({placeholder: "Select at least one service"});
  $("#topics").select2({placeholder: "Select at least one topic"});
};

function isOptionSelected(selectedValues) {
  return _.contains(selectedValues, this.id) ? 'selected' : '';
}

var selectOption = {
  isSelected: isOptionSelected
}

Template.serviceOption.helpers(selectOption);
Template.topicOption.helpers(selectOption);
<|endoftext|>