<commit_before>import { keys, bindAll, each, isUndefined } from 'underscore';
import Dragger from 'utils/Dragger';

module.exports = {
  run(editor, sender, opts = {}) {
    bindAll(
      this,
      'setPosition',
      'onStart',
      'onDrag',
      'onEnd',
      'getPosition',
      'getGuidesStatic',
      'renderGuide',
      'getGuidesTarget'
    );
    const { target, event, mode, dragger = {} } = opts;
    const { Canvas } = editor;
    const el = target.getEl();
    const scale = Canvas.getZoomMultiplier();
    const config = {
      scale,
      doc: el.ownerDocument,
      onStart: this.onStart,
      onEnd: this.onEnd,
      onDrag: this.onDrag,
      getPosition: this.getPosition,
      setPosition: this.setPosition,
      getGuidesStatic: () => this.guidesStatic,
      getGuidesTarget: () => this.guidesTarget,
      ...dragger
    };
    this.setupGuides();
    this.opts = opts;
    this.editor = editor;
    this.em = editor.getModel();
    this.target = target;
    this.isTran = mode == 'translate';
    this.guidesContainer = this.getGuidesContainer();
    this.guidesTarget = this.getGuidesTarget();
    this.guidesStatic = this.getGuidesStatic();
    window.guidesTarget = this.guidesTarget;
    let drg = this.dragger;

    if (!drg) {
      drg = new Dragger(config);
      this.dragger = drg;
    } else {
      drg.setOptions(config);
    }

    event && drg.start(event);
    this.toggleDrag(1);

    return drg;
  },

  stop() {
    this.toggleDrag();
  },

  setupGuides() {
    (this.guides || []).forEach(item => {
      const { guide } = item;
      guide && guide.parentNode.removeChild(guide);
    });
    this.guides = [];
  },

  getGuidesContainer() {
    let { guidesEl } = this;

    if (!guidesEl) {
      const { editor, em, opts } = this;
      const pfx = editor.getConfig('stylePrefix');
      const elInfoX = document.createElement('div');
      const elInfoY = document.createElement('div');
      const guideContent = `

`;
      guidesEl = document.createElement('div');
      guidesEl.className = `${pfx}guides`;
      elInfoX.className = `${pfx}guide-info ${pfx}guide-info__x`;
      elInfoY.className = `${pfx}guide-info ${pfx}guide-info__y`;
      elInfoX.innerHTML = guideContent;
      elInfoY.innerHTML = guideContent;
      guidesEl.appendChild(elInfoX);
      guidesEl.appendChild(elInfoY);
      editor.Canvas.getToolsEl().appendChild(guidesEl);
      this.guidesEl = guidesEl;
      this.elGuideInfoX = elInfoX;
      this.elGuideInfoY = elInfoY;
      this.elGuideInfoContentX = elInfoX.querySelector(
        `.${pfx}guide-info__content`
      );
      this.elGuideInfoContentY = elInfoY.querySelector(
        `.${pfx}guide-info__content`
      );
      em.on('canvas:update', () => {
        this.updateGuides();
        opts.debug && this.guides.forEach(item => this.renderGuide(item));
      });
    }

    return guidesEl;
  },

  getGuidesStatic() {
    let result = [];
    const el = this.target.getEl();
    each(
      el.parentNode.children,
      item =>
        (result = result.concat(el !== item ? this.getElementGuides(item) : []))
    );
    return result;
  },

  getGuidesTarget() {
    return this.getElementGuides(this.target.getEl());
  },

  updateGuides(guides) {
    (guides || this.guides).forEach(item => {
      const { origin } = item;
      const { top, height, left, width } = editor.Canvas.getElementPos(origin);

      switch (item.type) {
        case 't':
          return (item.y = top);
        case 'b':
          return (item.y = top + height);
        case 'l':
          return (item.x = left);
        case 'r':
          return (item.x = left + width);
        case 'x':
          return (item.x = left + width / 2);
        case 'y':
          return (item.y = top + height / 2);
      }
    });
  },

  getGuidePosUpdate(item, rect) {
    const result = {};
    const { top, height, left, width } = rect;

    switch (item.type) {
      case 't':
        result.y = top;
        break;
      case 'b':
        result.y = top + height;
        break;
      case 'l':
        result.x = left;
        break;
      case 'r':
        result.x = left + width;
        break;
      case 'x':
        result.x = left + width / 2;
        break;
      case 'y':
        result.y = top + height / 2;
        break;
    }

    return result;
  },

  renderGuide(item = {}) {
    const el = item.guide || document.createElement('div');
    const { Canvas } = this.editor;
    const { topScroll, top } = Canvas.getRect();
    const frameTop = Canvas.getCanvasView().getFrameOffset().top;
    // const elRect = this.getGuidePosUpdate(item, el.getBoundingClientRect());
    const un = 'px';
    const guideSize = item.active ? 2 : 1;
    let numEl = el.children[0];
    el.style = `position: absolute; background-color: ${
      item.active ? 'green' : 'red'
    };`;

    if (!el.children.length) {
      numEl = document.createElement('div');
      numEl.style =
        'position: absolute; color: red; padding: 5px; top: 0; left: 0;';
      el.appendChild(numEl);
    }

    if (item.y) {
      el.style.width = '100%';
      el.style.height = `${guideSize}${un}`;
      el.style.top = `${item.y}${un}`;
      el.style.left = 0;
      // numEl.innerHTML = elRect.y;
    } else {
      el.style.width = `${guideSize}${un}`;
      el.style.height = '100%';
      el.style.left = `${item.x}${un}`;
      el.style.top = `${topScroll - frameTop + top}${un}`;
      // numEl.innerHTML = elRect.x;
      // numEl.innerHTML = el.style.left;
    }

    !item.guide && this.guidesContainer.appendChild(el);
    return el;
  },

  getElementGuides(el) {
    const { editor, opts } = this;
    const { top, height, left, width } = editor.Canvas.getElementPos(el);
    const guides = [
      { type: 't', y: top }, // Top
      { type: 'b', y: top + height }, // Bottom
      { type: 'l', x: left }, // Left
      { type: 'r', x: left + width }, // Right
      { type: 'x', x: left + width / 2 }, // Mid x
      { type: 'y', y: top + height / 2 } // Mid y
    ].map(item => ({
      ...item,
      origin: el,
      originRect: editor.Canvas.getElementPos(el),
      guide: opts.debug && this.renderGuide(item)
    }));
    guides.forEach(item => this.guides.push(item));

    return guides;
  },

  getTranslate(transform, axis = 'x') {
    let result = 0;
    (transform || '').split(' ').forEach(item => {
      const itemStr = item.trim();
      const fn = `translate${axis.toUpperCase()}(`;
      if (itemStr.indexOf(fn) === 0)
        result = parseFloat(itemStr.replace(fn, ''));
    });
    return result;
  },

  setTranslate(transform, axis, value) {
    const fn = `translate${axis.toUpperCase()}(`;
    const val = `${fn}${value})`;
    let result = (transform || '')
      .split(' ')
      .map(item => {
        const itemStr = item.trim();
        if (itemStr.indexOf(fn) === 0) item = val;
        return item;
      })
      .join(' ');
    if (result.indexOf(fn) < 0) result += ` ${val}`;

    return result;
  },

  getPosition() {
    const { target, isTran } = this;
    const { left, top, transform } = target.getStyle();
    let x = 0;
    let y = 0;

    if (isTran) {
      x = this.getTranslate(transform);
      y = this.getTranslate(transform, 'y');
    } else {
      (x = parseFloat(left)), (y = parseFloat(top));
    }

    return { x, y };
  },

  setPosition({ x, y, end, position, width, height }) {
    const { target, isTran } = this;
    const unit = 'px';
    const en = !end ? 1 : ''; // this will trigger the final change
    const left = `${x}${unit}`;
    const top = `${y}${unit}`;

    if (isTran) {
      let transform = target.getStyle()['transform'] || '';
      transform = this.setTranslate(transform, 'x', left);
      transform = this.setTranslate(transform, 'y', top);
      return target.addStyle({ transform, en }, { avoidStore: !end });
    }

    const adds = { position, width, height };
    const style = { left, top, en };
    keys(adds).forEach(add => {
      const prop = adds[add];
      if (prop) style[add] = prop;
    });
    target.addStyle(style, { avoidStore: !end });
  },

  onStart() {
    const { target, editor, isTran } = this;
    const style = target.getStyle();
    const position = 'absolute';
    if (isTran) return;

    if (style.position !== position) {
      const { left, top, width, height } = editor.Canvas.offset(target.getEl());
      this.setPosition({ x: left, y: top, position, width, height });
    }
  },

  onDrag() {
    const { guidesTarget, opts } = this;
    this.updateGuides(guidesTarget);
    opts.debug && guidesTarget.forEach(item => this.renderGuide(item));
    opts.guidesInfo &&
      this.renderGuideInfo(guidesTarget.filter(item => item.active));
  },

  onEnd() {
    const { editor, opts, id } = this;
    const { onEnd } = opts;
    onEnd && onEnd();
    editor.stopCommand(id);
    // this.hideGuidesInfo();
  },

  hideGuidesInfo() {
    ['X', 'Y'].forEach(item => {
      const guide = this[`elGuideInfo${item}`];
      if (guide) guide.style.display = 'none';
    });
  },

  /**
   * Render guides with spacing information
   */
  renderGuideInfo(guides = []) {
    const { guidesStatic, editor } = this;
    this.hideGuidesInfo();

    guides.forEach(item => {
      const { origin, x } = item;
      const rectOrigin = editor.Canvas.getElementPos(origin);
      const axis = isUndefined(x) ? 'y' : 'x';
      const isY = axis === 'y';
      const origEdge1 = rectOrigin[isY ? 'left' : 'top'];
      const origEdge1Raw = rectOrigin.rect[isY ? 'left' : 'top'];
      const origEdge2 = isY
        ? origEdge1 + rectOrigin.width
        : origEdge1 + rectOrigin.height;
      const origEdge2Raw = isY
        ? origEdge1Raw + rectOrigin.rect.width
        : origEdge1Raw + rectOrigin.rect.height;
      const elGuideInfo = this[`elGuideInfo${axis.toUpperCase()}`];
      const elGuideInfoCnt = this[`elGuideInfoContent${axis.toUpperCase()}`];
      const guideInfoStyle = elGuideInfo.style;
      const res = guidesStatic
        .filter(stat => stat[axis] === item[axis])
        .map(stat => {
          const { left, width, top, height } = stat.originRect;
          const statEdge1 = isY ? left : top;
          const statEdge2 = isY ? left + width : top + height;
          return {
            gap:
              statEdge2 < origEdge1
                ? origEdge1 - statEdge2
                : statEdge1 - origEdge2,
            guide: stat
          };
        })
        .filter(item => item.gap > 0)
        .sort((a, b) => a.gap - b.gap)
        .map(item => item.guide)[0];

      if (res) {
        const { left, width, top, height, rect } = res.originRect;
        const isEdge1 = isY ? left < rectOrigin.left : top < rectOrigin.top;
        const statEdge1 = isY ? left : top;
        const statEdge1Raw = isY ? rect.left : rect.top;
        const statEdge2 = isY ? left + width : top + height;
        const statEdge2Raw = isY
          ? rect.left + rect.width
          : rect.top + rect.height;
        const pos2 = `${isY ? item.y : item.x}px`;
        const size = isEdge1 ? origEdge1 - statEdge2 : statEdge1 - origEdge2;
        const sizeRaw = isEdge1
          ? origEdge1Raw - statEdge2Raw
          : statEdge1Raw - origEdge2Raw;
        guideInfoStyle.display = '';
        guideInfoStyle[isY ? 'top' : 'left'] = pos2;
        guideInfoStyle[isY ? 'left' : 'top'] = `${
          isEdge1 ? statEdge2 : origEdge2
        }px`;
        guideInfoStyle[isY ? 'width' : 'height'] = `${size}px`;
        elGuideInfoCnt.innerHTML = `${Math.round(sizeRaw)}px`;
        console.log('size', size, 'sizeRaw', sizeRaw);
      }
      // elGuideInfo.innerHTML = length
    });
  },

  toggleDrag(on) {
    const { ppfx, editor } = this;
    const methodCls = on ? 'add' : 'remove';
    const canvas = this.getCanvas();
    const classes = [`${ppfx}is__grabbing`];
    classes.forEach(cls => canvas.classList[methodCls](cls));
    editor.Canvas[on ? 'startAutoscroll' : 'stopAutoscroll']();
  }
};
<commit_msg>Hide guides on drag end<commit_after>import { keys, bindAll, each, isUndefined } from 'underscore';
import Dragger from 'utils/Dragger';

module.exports = {
  run(editor, sender, opts = {}) {
    bindAll(
      this,
      'setPosition',
      'onStart',
      'onDrag',
      'onEnd',
      'getPosition',
      'getGuidesStatic',
      'renderGuide',
      'getGuidesTarget'
    );
    const { target, event, mode, dragger = {} } = opts;
    const { Canvas } = editor;
    const el = target.getEl();
    const scale = Canvas.getZoomMultiplier();
    const config = {
      scale,
      doc: el.ownerDocument,
      onStart: this.onStart,
      onEnd: this.onEnd,
      onDrag: this.onDrag,
      getPosition: this.getPosition,
      setPosition: this.setPosition,
      getGuidesStatic: () => this.guidesStatic,
      getGuidesTarget: () => this.guidesTarget,
      ...dragger
    };
    this.setupGuides();
    this.opts = opts;
    this.editor = editor;
    this.em = editor.getModel();
    this.target = target;
    this.isTran = mode == 'translate';
    this.guidesContainer = this.getGuidesContainer();
    this.guidesTarget = this.getGuidesTarget();
    this.guidesStatic = this.getGuidesStatic();
    window.guidesTarget = this.guidesTarget;
    let drg = this.dragger;

    if (!drg) {
      drg = new Dragger(config);
      this.dragger = drg;
    } else {
      drg.setOptions(config);
    }

    event && drg.start(event);
    this.toggleDrag(1);

    return drg;
  },

  stop() {
    this.toggleDrag();
  },

  setupGuides() {
    (this.guides || []).forEach(item => {
      const { guide } = item;
      guide && guide.parentNode.removeChild(guide);
    });
    this.guides = [];
  },

  getGuidesContainer() {
    let { guidesEl } = this;

    if (!guidesEl) {
      const { editor, em, opts } = this;
      const pfx = editor.getConfig('stylePrefix');
      const elInfoX = document.createElement('div');
      const elInfoY = document.createElement('div');
      const guideContent = `

`;
      guidesEl = document.createElement('div');
      guidesEl.className = `${pfx}guides`;
      elInfoX.className = `${pfx}guide-info ${pfx}guide-info__x`;
      elInfoY.className = `${pfx}guide-info ${pfx}guide-info__y`;
      elInfoX.innerHTML = guideContent;
      elInfoY.innerHTML = guideContent;
      guidesEl.appendChild(elInfoX);
      guidesEl.appendChild(elInfoY);
      editor.Canvas.getToolsEl().appendChild(guidesEl);
      this.guidesEl = guidesEl;
      this.elGuideInfoX = elInfoX;
      this.elGuideInfoY = elInfoY;
      this.elGuideInfoContentX = elInfoX.querySelector(
        `.${pfx}guide-info__content`
      );
      this.elGuideInfoContentY = elInfoY.querySelector(
        `.${pfx}guide-info__content`
      );
      em.on('canvas:update', () => {
        this.updateGuides();
        opts.debug && this.guides.forEach(item => this.renderGuide(item));
      });
    }

    return guidesEl;
  },

  getGuidesStatic() {
    let result = [];
    const el = this.target.getEl();
    each(
      el.parentNode.children,
      item =>
        (result = result.concat(el !== item ? this.getElementGuides(item) : []))
    );
    return result;
  },

  getGuidesTarget() {
    return this.getElementGuides(this.target.getEl());
  },

  updateGuides(guides) {
    (guides || this.guides).forEach(item => {
      const { origin } = item;
      const { top, height, left, width } = editor.Canvas.getElementPos(origin);

      switch (item.type) {
        case 't':
          return (item.y = top);
        case 'b':
          return (item.y = top + height);
        case 'l':
          return (item.x = left);
        case 'r':
          return (item.x = left + width);
        case 'x':
          return (item.x = left + width / 2);
        case 'y':
          return (item.y = top + height / 2);
      }
    });
  },

  getGuidePosUpdate(item, rect) {
    const result = {};
    const { top, height, left, width } = rect;

    switch (item.type) {
      case 't':
        result.y = top;
        break;
      case 'b':
        result.y = top + height;
        break;
      case 'l':
        result.x = left;
        break;
      case 'r':
        result.x = left + width;
        break;
      case 'x':
        result.x = left + width / 2;
        break;
      case 'y':
        result.y = top + height / 2;
        break;
    }

    return result;
  },

  renderGuide(item = {}) {
    const el = item.guide || document.createElement('div');
    const { Canvas } = this.editor;
    const { topScroll, top } = Canvas.getRect();
    const frameTop = Canvas.getCanvasView().getFrameOffset().top;
    // const elRect = this.getGuidePosUpdate(item, el.getBoundingClientRect());
    const un = 'px';
    const guideSize = item.active ? 2 : 1;
    let numEl = el.children[0];
    el.style = `position: absolute; background-color: ${
      item.active ? 'green' : 'red'
    };`;

    if (!el.children.length) {
      numEl = document.createElement('div');
      numEl.style =
        'position: absolute; color: red; padding: 5px; top: 0; left: 0;';
      el.appendChild(numEl);
    }

    if (item.y) {
      el.style.width = '100%';
      el.style.height = `${guideSize}${un}`;
      el.style.top = `${item.y}${un}`;
      el.style.left = 0;
      // numEl.innerHTML = elRect.y;
    } else {
      el.style.width = `${guideSize}${un}`;
      el.style.height = '100%';
      el.style.left = `${item.x}${un}`;
      el.style.top = `${topScroll - frameTop + top}${un}`;
      // numEl.innerHTML = elRect.x;
      // numEl.innerHTML = el.style.left;
    }

    !item.guide && this.guidesContainer.appendChild(el);
    return el;
  },

  getElementGuides(el) {
    const { editor, opts } = this;
    const { top, height, left, width } = editor.Canvas.getElementPos(el);
    const guides = [
      { type: 't', y: top }, // Top
      { type: 'b', y: top + height }, // Bottom
      { type: 'l', x: left }, // Left
      { type: 'r', x: left + width }, // Right
      { type: 'x', x: left + width / 2 }, // Mid x
      { type: 'y', y: top + height / 2 } // Mid y
    ].map(item => ({
      ...item,
      origin: el,
      originRect: editor.Canvas.getElementPos(el),
      guide: opts.debug && this.renderGuide(item)
    }));
    guides.forEach(item => this.guides.push(item));

    return guides;
  },

  getTranslate(transform, axis = 'x') {
    let result = 0;
    (transform || '').split(' ').forEach(item => {
      const itemStr = item.trim();
      const fn = `translate${axis.toUpperCase()}(`;
      if (itemStr.indexOf(fn) === 0)
        result = parseFloat(itemStr.replace(fn, ''));
    });
    return result;
  },

  setTranslate(transform, axis, value) {
    const fn = `translate${axis.toUpperCase()}(`;
    const val = `${fn}${value})`;
    let result = (transform || '')
      .split(' ')
      .map(item => {
        const itemStr = item.trim();
        if (itemStr.indexOf(fn) === 0) item = val;
        return item;
      })
      .join(' ');
    if (result.indexOf(fn) < 0) result += ` ${val}`;

    return result;
  },

  getPosition() {
    const { target, isTran } = this;
    const { left, top, transform } = target.getStyle();
    let x = 0;
    let y = 0;

    if (isTran) {
      x = this.getTranslate(transform);
      y = this.getTranslate(transform, 'y');
    } else {
      (x = parseFloat(left)), (y = parseFloat(top));
    }

    return { x, y };
  },

  setPosition({ x, y, end, position, width, height }) {
    const { target, isTran } = this;
    const unit = 'px';
    const en = !end ? 1 : ''; // this will trigger the final change
    const left = `${x}${unit}`;
    const top = `${y}${unit}`;

    if (isTran) {
      let transform = target.getStyle()['transform'] || '';
      transform = this.setTranslate(transform, 'x', left);
      transform = this.setTranslate(transform, 'y', top);
      return target.addStyle({ transform, en }, { avoidStore: !end });
    }

    const adds = { position, width, height };
    const style = { left, top, en };
    keys(adds).forEach(add => {
      const prop = adds[add];
      if (prop) style[add] = prop;
    });
    target.addStyle(style, { avoidStore: !end });
  },

  onStart() {
    const { target, editor, isTran } = this;
    const style = target.getStyle();
    const position = 'absolute';
    if (isTran) return;

    if (style.position !== position) {
      const { left, top, width, height } = editor.Canvas.offset(target.getEl());
      this.setPosition({ x: left, y: top, position, width, height });
    }
  },

  onDrag() {
    const { guidesTarget, opts } = this;
    this.updateGuides(guidesTarget);
    opts.debug && guidesTarget.forEach(item => this.renderGuide(item));
    opts.guidesInfo &&
      this.renderGuideInfo(guidesTarget.filter(item => item.active));
  },

  onEnd() {
    const { editor, opts, id } = this;
    const { onEnd } = opts;
    onEnd && onEnd();
    editor.stopCommand(id);
    this.hideGuidesInfo();
  },

  hideGuidesInfo() {
    ['X', 'Y'].forEach(item => {
      const guide = this[`elGuideInfo${item}`];
      if (guide) guide.style.display = 'none';
    });
  },

  /**
   * Render guides with spacing information
   */
  renderGuideInfo(guides = []) {
    const { guidesStatic, editor } = this;
    this.hideGuidesInfo();

    guides.forEach(item => {
      const { origin, x } = item;
      const rectOrigin = editor.Canvas.getElementPos(origin);
      const axis = isUndefined(x) ? 'y' : 'x';
      const isY = axis === 'y';
      const origEdge1 = rectOrigin[isY ? 'left' : 'top'];
      const origEdge1Raw = rectOrigin.rect[isY ? 'left' : 'top'];
      const origEdge2 = isY
        ? origEdge1 + rectOrigin.width
        : origEdge1 + rectOrigin.height;
      const origEdge2Raw = isY
        ? origEdge1Raw + rectOrigin.rect.width
        : origEdge1Raw + rectOrigin.rect.height;
      const elGuideInfo = this[`elGuideInfo${axis.toUpperCase()}`];
      const elGuideInfoCnt = this[`elGuideInfoContent${axis.toUpperCase()}`];
      const guideInfoStyle = elGuideInfo.style;

      // Find the nearest element
      const res = guidesStatic
        .filter(stat => stat[axis] === item[axis])
        .map(stat => {
          const { left, width, top, height } = stat.originRect;
          const statEdge1 = isY ? left : top;
          const statEdge2 = isY ? left + width : top + height;
          return {
            gap:
              statEdge2 < origEdge1
                ? origEdge1 - statEdge2
                : statEdge1 - origEdge2,
            guide: stat
          };
        })
        .filter(item => item.gap > 0)
        .sort((a, b) => a.gap - b.gap)
        .map(item => item.guide)[0];

      if (res) {
        const { left, width, top, height, rect } = res.originRect;
        const isEdge1 = isY ? left < rectOrigin.left : top < rectOrigin.top;
        const statEdge1 = isY ? left : top;
        const statEdge1Raw = isY ? rect.left : rect.top;
        const statEdge2 = isY ? left + width : top + height;
        const statEdge2Raw = isY
          ? rect.left + rect.width
          : rect.top + rect.height;
        const pos2 = `${isY ? item.y : item.x}px`;
        const size = isEdge1 ? origEdge1 - statEdge2 : statEdge1 - origEdge2;
        const sizeRaw = isEdge1
          ? origEdge1Raw - statEdge2Raw
          : statEdge1Raw - origEdge2Raw;
        guideInfoStyle.display = '';
        guideInfoStyle[isY ? 'top' : 'left'] = pos2;
        guideInfoStyle[isY ? 'left' : 'top'] = `${
          isEdge1 ? statEdge2 : origEdge2
        }px`;
        guideInfoStyle[isY ? 'width' : 'height'] = `${size}px`;
        elGuideInfoCnt.innerHTML = `${Math.round(sizeRaw)}px`;
      }
    });
  },

  toggleDrag(on) {
    const { ppfx, editor } = this;
    const methodCls = on ? 'add' : 'remove';
    const canvas = this.getCanvas();
    const classes = [`${ppfx}is__grabbing`];
    classes.forEach(cls => canvas.classList[methodCls](cls));
    editor.Canvas[on ? 'startAutoscroll' : 'stopAutoscroll']();
  }
};
<|endoftext|>


<commit_before>// Copyright 2014-2015, Renasar Technologies Inc.
/* jshint node: true */

'use strict';

var di = require('di'),
    express = require('express');

module.exports = versionRouterFactory;

di.annotate(versionRouterFactory, new di.Provide('Http.Api.Versions'));
di.annotate(versionRouterFactory,
    new di.Inject(
        'common-api-presenter',
        'ChildProcess',
        '_',
        'Logger'
    )
);

function versionRouterFactory (presenter, ChildProcess, _, Logger) {
    var logger = Logger.initialize(versionRouterFactory);
    var router = express.Router();
    /**
     * @api {get} /api/common/versions GET /
     * @apiDescription get versions of packages installed
     * @apiName versions-get
     * @apiGroup versions
     *
     * @apiSuccessExample {json} Success-Response:
     *     HTTP/1.1 200 Ok
     *     [
     *         {
     *             "package": "renasar-http",
     *             "version": "1.0-19"
     *         },
     *         {
     *             "package": "renasar-tftp",
     *             "version": "1.0-19"
     *         },
     *     ]
     *
     * @apiErrorExample {json} Error-Response:
     *     HTTP/1.1 501 Not Implemented
     *
     */

    router.get('/versions', presenter.middleware(function (req, res) {
        var process = new ChildProcess().run("/usr/bin/dpkg", ["-l", "renasar-*"]);
        return process.then(function(results) {
            // break up the STDOUT into an array of lines
            var lines = results.stdout.split('\n');
            // grab the lines that start with "ii " - indicating package listings
            var packagelines = _.filter(lines, function(line) { return line.match(/^ii\s/); });
            // convert the raw string lines into objects
            var transformed = _.transform(packagelines, function(result, item) {
                // parse out the fields - split on one or more whitespace characters
                var fields = item.split(/\s+/);
                // generate a dict of package, version keys for each line
                return result.push({
                    'package': fields[1],
                    'version': fields[2]
                });
            });
            return transformed;
        }).catch(function(error) {
            logger.warning("Unable to retrieve package versions", { error: error };
            res.status(501);
            return { 'error': 'Not Implemented' };
        });
    }));

    return router;
}
<commit_msg>I'm an idiot, fixing the obvious typo<commit_after>// Copyright 2014-2015, Renasar Technologies Inc.
/* jshint node: true */

'use strict';

var di = require('di'),
    express = require('express');

module.exports = versionRouterFactory;

di.annotate(versionRouterFactory, new di.Provide('Http.Api.Versions'));
di.annotate(versionRouterFactory,
    new di.Inject(
        'common-api-presenter',
        'ChildProcess',
        '_',
        'Logger'
    )
);

function versionRouterFactory (presenter, ChildProcess, _, Logger) {
    var logger = Logger.initialize(versionRouterFactory);
    var router = express.Router();
    /**
     * @api {get} /api/common/versions GET /
     * @apiDescription get versions of packages installed
     * @apiName versions-get
     * @apiGroup versions
     *
     * @apiSuccessExample {json} Success-Response:
     *     HTTP/1.1 200 Ok
     *     [
     *         {
     *             "package": "renasar-http",
     *             "version": "1.0-19"
     *         },
     *         {
     *             "package": "renasar-tftp",
     *             "version": "1.0-19"
     *         },
     *     ]
     *
     * @apiErrorExample {json} Error-Response:
     *     HTTP/1.1 501 Not Implemented
     *
     */

    router.get('/versions', presenter.middleware(function (req, res) {
        var process = new ChildProcess().run("/usr/bin/dpkg", ["-l", "renasar-*"]);
        return process.then(function(results) {
            // break up the STDOUT into an array of lines
            var lines = results.stdout.split('\n');
            // grab the lines that start with "ii " - indicating package listings
            var packagelines = _.filter(lines, function(line) { return line.match(/^ii\s/); });
            // convert the raw string lines into objects
            var transformed = _.transform(packagelines, function(result, item) {
                // parse out the fields - split on one or more whitespace characters
                var fields = item.split(/\s+/);
                // generate a dict of package, version keys for each line
                return result.push({
                    'package': fields[1],
                    'version': fields[2]
                });
            });
            return transformed;
        }).catch(function(error) {
            logger.warning("Unable to retrieve package versions", { error: error });
            res.status(501);
            return { 'error': 'Not Implemented' };
        });
    }));

    return router;
}
<|endoftext|>


<commit_before>'use strict';

const privateMap = require('./private-map');
const request = require('request');

/**
* @module applications
*/

module.exports = {
  find: find,
  create: create,
  update: update,
  remove: remove,
};

/**
  A function to get all the push applications or just 1 push application
  @param {string} [pushAppId] - The id of the push application
  @returns {Promise} A promise that will resolve with the Array of application objects or if a pushAppId is specified, just the application object
  @example
  adminClient(baseUrl, settings)
    .then((client) => {
      client.applications.find()
        .then((applications) => {
        console.log(applications) // [{...},{...}, ...]
      });
    });
 */
function find(client) {
  return function find(pushAppId) {
    return new Promise((resolve, reject) => {
      const req = {
        url: pushAppId ? `${client.baseUrl}/rest/applications/${pushAppId}` : `${client.baseUrl}/rest/applications/`,
        auth: {
          bearer: privateMap.get(client).accessToken
        },
        json: true
      };

      request(req, (err, resp, body) => {
        if (err) {
          return reject(err);
        }

        if (resp.statusCode !== 200) {
          return reject(body);
        }

        return resolve(body);
      });
    });
  };
}

/**
  A function to create a new Push Application
  @param {object} pushApp - The JSON representation of the push application to create.  pushApp.name is required
  @returns {Promise} A promise that resolves with the JSON representation of the created push application.
  @example
  adminClient(baseUrl, settings)
    .then((client) => {
      client.applications.create(pushApplication)
        .then((newPushApp) => {
          console.log(newPushApp); //{...}
      });
    });
 */
function create(client) {
  return function create(pushApp) {
    return new Promise((resolve, reject) => {
      const req = {
        url: `${client.baseUrl}/rest/applications/`,
        auth: {
          bearer: privateMap.get(client).accessToken
        },
        body: pushApp,
        json: true,
        method: 'POST'
      };

      request(req, (err, resp, body) => {
        if (err) {
          return reject(err);
        }

        if (resp.statusCode !== 201) {
          return reject(body);
        }

        return resolve(body);
      });
    });
  };
}

/**
  A function to update an existing Push Application
  @param {object} pushApp - The JSON representation of the push application to update.  pushApp.pushApplicationID and pushApp.name is required. ATM, it looks like the only fields that are updatable are name and description
  @returns {Promise} A promise that resolves with No Content
  @example
  adminClient(baseUrl, settings)
    .then((client) => {
      client.applications.update(pushApplication)
        .then(() => {
          console.log('success');
      });
    });
 */
function update(client) {
  return function update(pushApp) {
    return new Promise((resolve, reject) => {
      const req = {
        url: `${client.baseUrl}/rest/applications/${pushApp.pushApplicationID}`,
        auth: {
          bearer: privateMap.get(client).accessToken
        },
        body: pushApp,
        json: true,
        method: 'PUT'
      };

      request(req, (err, resp, body) => {
        if (err) {
          return reject(err);
        }

        if (resp.statusCode !== 204) {
          return reject(body);
        }

        return resolve(body);
      });
    });
  };
}

/**
  A function to delete a Push Application
  @param {string} pushAppId - The id of the push application to delete
  @returns {Promise} A promise that resolves with No Content.
  @example
  adminClient(baseUrl, settings)
    .then((client) => {
      client.applications.remove(pushApplicationId)
        .then(() => {
          console.log('success');
      });
    });
 */
function remove(client) {
  return function remove(pushAppId) {
    return new Promise((resolve, reject) => {
      const req = {
        url: `${client.baseUrl}/rest/applications/${pushAppId}`,
        auth: {
          bearer: privateMap.get(client).accessToken
        },
        json: true,
        method: 'DELETE'
      };

      request(req, (err, resp, body) => {
        if (err) {
          return reject(err);
        }

        if (resp.statusCode !== 204) {
          return reject(body);
        }

        return resolve(body);
      });
    });
  };
}
<commit_msg>remove trailing comma<commit_after>'use strict';

const privateMap = require('./private-map');
const request = require('request');

/**
* @module applications
*/

module.exports = {
  find: find,
  create: create,
  update: update,
  remove: remove
};

/**
  A function to get all the push applications or just 1 push application
  @param {string} [pushAppId] - The id of the push application
  @returns {Promise} A promise that will resolve with the Array of application objects or if a pushAppId is specified, just the application object
  @example
  adminClient(baseUrl, settings)
    .then((client) => {
      client.applications.find()
        .then((applications) => {
        console.log(applications) // [{...},{...}, ...]
      });
    });
 */
function find(client) {
  return function find(pushAppId) {
    return new Promise((resolve, reject) => {
      const req = {
        url: pushAppId ? `${client.baseUrl}/rest/applications/${pushAppId}` : `${client.baseUrl}/rest/applications/`,
        auth: {
          bearer: privateMap.get(client).accessToken
        },
        json: true
      };

      request(req, (err, resp, body) => {
        if (err) {
          return reject(err);
        }

        if (resp.statusCode !== 200) {
          return reject(body);
        }

        return resolve(body);
      });
    });
  };
}

/**
  A function to create a new Push Application
  @param {object} pushApp - The JSON representation of the push application to create.  pushApp.name is required
  @returns {Promise} A promise that resolves with the JSON representation of the created push application.
  @example
  adminClient(baseUrl, settings)
    .then((client) => {
      client.applications.create(pushApplication)
        .then((newPushApp) => {
          console.log(newPushApp); //{...}
      });
    });
 */
function create(client) {
  return function create(pushApp) {
    return new Promise((resolve, reject) => {
      const req = {
        url: `${client.baseUrl}/rest/applications/`,
        auth: {
          bearer: privateMap.get(client).accessToken
        },
        body: pushApp,
        json: true,
        method: 'POST'
      };

      request(req, (err, resp, body) => {
        if (err) {
          return reject(err);
        }

        if (resp.statusCode !== 201) {
          return reject(body);
        }

        return resolve(body);
      });
    });
  };
}

/**
  A function to update an existing Push Application
  @param {object} pushApp - The JSON representation of the push application to update.  pushApp.pushApplicationID and pushApp.name is required. ATM, it looks like the only fields that are updatable are name and description
  @returns {Promise} A promise that resolves with No Content
  @example
  adminClient(baseUrl, settings)
    .then((client) => {
      client.applications.update(pushApplication)
        .then(() => {
          console.log('success');
      });
    });
 */
function update(client) {
  return function update(pushApp) {
    return new Promise((resolve, reject) => {
      const req = {
        url: `${client.baseUrl}/rest/applications/${pushApp.pushApplicationID}`,
        auth: {
          bearer: privateMap.get(client).accessToken
        },
        body: pushApp,
        json: true,
        method: 'PUT'
      };

      request(req, (err, resp, body) => {
        if (err) {
          return reject(err);
        }

        if (resp.statusCode !== 204) {
          return reject(body);
        }

        return resolve(body);
      });
    });
  };
}

/**
  A function to delete a Push Application
  @param {string} pushAppId - The id of the push application to delete
  @returns {Promise} A promise that resolves with No Content.
  @example
  adminClient(baseUrl, settings)
    .then((client) => {
      client.applications.remove(pushApplicationId)
        .then(() => {
          console.log('success');
      });
    });
 */
function remove(client) {
  return function remove(pushAppId) {
    return new Promise((resolve, reject) => {
      const req = {
        url: `${client.baseUrl}/rest/applications/${pushAppId}`,
        auth: {
          bearer: privateMap.get(client).accessToken
        },
        json: true,
        method: 'DELETE'
      };

      request(req, (err, resp, body) => {
        if (err) {
          return reject(err);
        }

        if (resp.statusCode !== 204) {
          return reject(body);
        }

        return resolve(body);
      });
    });
  };
}
<|endoftext|>


<commit_before>import { toHaveNoViolations } from "jest-axe";

expect.extend(toHaveNoViolations);

jest.setTimeout(10000);

describe("/", () => {
  let page;
  beforeAll(async () => {
    page = await global.BROWSER.newPage();
    await page.goto(global.ROOT);

    await page.addScriptTag({ path: require.resolve("axe-core") });
  });

  it("loads", async () => {
    const text = await page.evaluate(() => document.body.textContent);
    expect(text).toContain("draftail");
  });

  it("a11y", async () => {
    const result = await page.evaluate(
      () =>
        new Promise((resolve) => {
          window.axe.run((err, results) => {
            if (err) throw err;
            resolve(results);
          });
        }),
    );
    expect(result).toHaveNoViolations();
  });
});
<commit_msg>Fix index load sanity check using the wrong string<commit_after>import { toHaveNoViolations } from "jest-axe";

expect.extend(toHaveNoViolations);

jest.setTimeout(10000);

describe("/", () => {
  let page;
  beforeAll(async () => {
    page = await global.BROWSER.newPage();
    await page.goto(global.ROOT);

    await page.addScriptTag({ path: require.resolve("axe-core") });
  });

  it("loads", async () => {
    const text = await page.evaluate(() => document.body.textContent);
    expect(text).toContain("Draftail");
  });

  it("a11y", async () => {
    const result = await page.evaluate(
      () =>
        new Promise((resolve) => {
          window.axe.run((err, results) => {
            if (err) throw err;
            resolve(results);
          });
        }),
    );
    expect(result).toHaveNoViolations();
  });
});
<|endoftext|>


<commit_before>import assign from 'lodash/assign'
import PropTypes from 'prop-types'

// Decorators to help declaring properties and context types on React
// components without using the tedious static properties syntax.
//
// ```js
// @propTypes({
//   children: propTypes.node.isRequired
// }, {
//   store: propTypes.object.isRequired
// })
// class MyComponent extends React.Component {}
// ```
const propTypes = (propTypes, contextTypes) => target => {
  if (propTypes !== undefined) {
    target.propTypes = {
      ...target.propTypes,
      ...propTypes,
    }
  }
  if (contextTypes !== undefined) {
    target.contextTypes = {
      ...target.contextTypes,
      ...contextTypes,
    }
  }

  return target
}
assign(propTypes, PropTypes)

export { propTypes as default }
<commit_msg>chore(prop-types-decorator): deprecate<commit_after>import assign from 'lodash/assign'
import PropTypes from 'prop-types'

// Deprecated because :
// - unnecessary
// - not standard in the React ecosystem
if (__DEV__) {
  console.warn(`DEPRECATED: use prop-types directly:
class MyComponent extends React.Component {
  static propTypes = {
    foo: PropTypes.string.isRequired
  }
}`)
}

// Decorators to help declaring properties and context types on React
// components without using the tedious static properties syntax.
//
// ```js
// @propTypes({
//   children: propTypes.node.isRequired
// }, {
//   store: propTypes.object.isRequired
// })
// class MyComponent extends React.Component {}
// ```
const propTypes = (propTypes, contextTypes) => target => {
  if (propTypes !== undefined) {
    target.propTypes = {
      ...target.propTypes,
      ...propTypes,
    }
  }
  if (contextTypes !== undefined) {
    target.contextTypes = {
      ...target.contextTypes,
      ...contextTypes,
    }
  }

  return target
}
assign(propTypes, PropTypes)

export { propTypes as default }
<|endoftext|>


<commit_before>'use babel';

import 'atom';
import child_process from 'child_process';
import AtomPhpunitView from './atom-phpunit-view.js';

export default {

  config: {
    successAsNotifications: {
      order: 1,
      description: 'Show successful output as a notification instead of using the output panel',
      type: 'boolean',
      default: true
    },
    useVendor: {
      order: 2,
      description: 'Uses the project\'s phpunit binary (./vendor/bin/phpunit)',
      type: 'boolean',
      default: true
    },
    phpunitPath: {
      order: 3,
      title: 'PHPUnit Binary Path',
      description: 'Used only if \'Use Vendor\' is not ticked.',
      type: 'string',
      default: '/usr/local/bin/phpunit'
    }
  },

  exec: null,

  activate(state) {
    this.exec = child_process.exec;
    this.errorView = new AtomPhpunitView(state.atomPhpunitViewState);
    this.outputPanel = atom.workspace.addBottomPanel({
      item: this.errorView.getElement(),
      visible: false
    });

    atom.commands.add('atom-workspace', {
      'atom-phpunit:run-test': () => this.runTest(),
      'atom-phpunit:run-class': () => this.runClass(),
      'atom-phpunit:run-suite': () => this.runSuite(),
      'atom-phpunit:toggle-output': () => this.toggleOutput()
    });
  },

  serialize() {
    return {
      atomPhpunitViewState: this.errorView.serialize()
    };
  },

  deactivate() {
    this.outputPanel.destroy();
    this.errorView.destroy();
  },

  runTest() {
    if (this.outputPanel.isVisible()) {
      this.errorView.update('No Output');
      this.outputPanel.hide();
    }

    filepath = this.getFilepath();
    if (!filepath) {
      atom.notifications.addError('Failed to get filename! Make sure you are in the test file you want run.');
      return;
    }

    func = this.getFunctionName();
    if (!func) {
      atom.notifications.addError('Function name not found! Make sure your cursor is inside the test you want to run.');
      return;
    }

    this.execute(filepath, func);
  },

  runClass() {
    if (this.outputPanel.isVisible()) {
      this.errorView.update('No Output');
      this.outputPanel.hide();
    }
    filepath = this.getFilepath();
    if (!filepath) {
      atom.notifications.addError('Failed to get filename! Make sure you are in the test file you want run.');
      return;
    }

    this.execute(filepath);
  },

  runSuite() {
    if (this.outputPanel.isVisible()) {
      this.errorView.update('No Output');
      this.outputPanel.hide();
    }

    filepath = this.getFilepath();
    if (!filepath) {
      atom.notifications.addError('Failed to find phpunit! Make sure you are in the test file from the suit you want run.');
      return;
    }

    this.execute();
  },

  toggleOutput() {
    this.outputPanel.isVisible()
      ? this.outputPanel.hide()
      : this.outputPanel.show();
  },

  execute(filepath, functionName) {
    if (atom.config.get('atom-phpunit.useVendor'))
      cmd = './vendor/bin/phpunit';
    else
      cmd = atom.config.get('atom-phpunit.phpunitPath');

    if (typeof functionName !== 'undefined')
      cmd += ` --filter=${functionName}`;

    if (typeof filepath !== 'undefined')
      cmd += ` ${filepath}`;

    console.log(`atom-phpunit: ${cmd}`);

    this.exec(cmd, {cwd: this.getProjectFolderPath()}, (error, stdout, stderr) => {
      if (error && stderr) {
        this.errorView.update(stderr, false);
        this.outputPanel.show();
      } else if (error) {
        this.errorView.update(stdout, false);
        this.outputPanel.show();
      } else {
        this.errorView.update(stdout, true);
        if (atom.config.get('atom-phpunit.successAsNotifications')) {
          atom.notifications.addSuccess('Test Passed!', {description: cmd, detail: stdout});
        } else {
          this.outputPanel.show();
        }
      }
    });
  },

  getFunctionName() {
    let editor = atom.workspace.getActiveTextEditor();
    if (!editor)
      return false;

    let pos = editor.getCursorBufferPosition();
    let buffer = editor.getBuffer();

    for (var row = pos.row; row--; row > 0) {
      let line = buffer.lineForRow(row);
      if (line.includes('function ')) {
        let parts = line.match(/function\s+([^\s(]+)\s*\(/);
        if (parts && parts.length > 1)
          return parts[1];
      }
    }

    return false
  },

  getFilepath() {
    let editor = atom.workspace.getActivePaneItem();
    if (!editor)
      return false;

    let buffer = editor.buffer;
    if (!buffer)
      return false;

    let file = buffer.file;

    if (!file.path) {
      return false;
    }

    return file.path;
  },

  getProjectFolderPath() {
    return atom.project.relativizePath(this.getFilepath())[0];
  }

};
<commit_msg>Add option to save current file before running tests.<commit_after>'use babel';

import 'atom';
import child_process from 'child_process';
import AtomPhpunitView from './atom-phpunit-view.js';

export default {

  config: {
    saveBeforeTest: {
      order: 1,
      description: 'Save current file before running test(s)',
      type: 'boolean',
      default: false
    },
    successAsNotifications: {
      order: 2,
      description: 'Show successful output as a notification instead of using the output panel',
      type: 'boolean',
      default: true
    },
    useVendor: {
      order: 3,
      description: 'Uses the project\'s phpunit binary (./vendor/bin/phpunit)',
      type: 'boolean',
      default: true
    },
    phpunitPath: {
      order: 4,
      title: 'PHPUnit Binary Path',
      description: 'Used only if \'Use Vendor\' is not ticked.',
      type: 'string',
      default: '/usr/local/bin/phpunit'
    }
  },

  exec: null,

  activate(state) {
    this.exec = child_process.exec;
    this.errorView = new AtomPhpunitView(state.atomPhpunitViewState);
    this.outputPanel = atom.workspace.addBottomPanel({
      item: this.errorView.getElement(),
      visible: false
    });

    atom.commands.add('atom-workspace', {
      'atom-phpunit:run-test': () => this.runTest(),
      'atom-phpunit:run-class': () => this.runClass(),
      'atom-phpunit:run-suite': () => this.runSuite(),
      'atom-phpunit:toggle-output': () => this.toggleOutput()
    });
  },

  serialize() {
    return {
      atomPhpunitViewState: this.errorView.serialize()
    };
  },

  deactivate() {
    this.outputPanel.destroy();
    this.errorView.destroy();
  },

  runTest() {
    if (this.outputPanel.isVisible()) {
      this.errorView.update('No Output');
      this.outputPanel.hide();
    }

    filepath = this.getFilepath();
    if (!filepath) {
      atom.notifications.addError('Failed to get filename! Make sure you are in the test file you want run.');
      return;
    }

    func = this.getFunctionName();
    if (!func) {
      atom.notifications.addError('Function name not found! Make sure your cursor is inside the test you want to run.');
      return;
    }

    this.execute(filepath, func);
  },

  runClass() {
    if (this.outputPanel.isVisible()) {
      this.errorView.update('No Output');
      this.outputPanel.hide();
    }
    filepath = this.getFilepath();
    if (!filepath) {
      atom.notifications.addError('Failed to get filename! Make sure you are in the test file you want run.');
      return;
    }

    this.execute(filepath);
  },

  runSuite() {
    if (this.outputPanel.isVisible()) {
      this.errorView.update('No Output');
      this.outputPanel.hide();
    }

    filepath = this.getFilepath();
    if (!filepath) {
      atom.notifications.addError('Failed to find phpunit! Make sure you are in the test file from the suit you want run.');
      return;
    }

    this.execute();
  },

  toggleOutput() {
    this.outputPanel.isVisible()
      ? this.outputPanel.hide()
      : this.outputPanel.show();
  },

  execute(filepath, functionName) {
    if ( atom.config.get('atom-phpunit.saveBeforeTest') &&
         atom.workspace.getActiveTextEditor().isModified() )
      atom.workspace.getActiveTextEditor().save()

    if (atom.config.get('atom-phpunit.useVendor'))
      cmd = './vendor/bin/phpunit';
    else
      cmd = atom.config.get('atom-phpunit.phpunitPath');

    if (typeof functionName !== 'undefined')
      cmd += ` --filter=${functionName}`;

    if (typeof filepath !== 'undefined')
      cmd += ` ${filepath}`;

    console.log(`atom-phpunit: ${cmd}`);

    this.exec(cmd, {cwd: this.getProjectFolderPath()}, (error, stdout, stderr) => {
      if (error && stderr) {
        this.errorView.update(stderr, false);
        this.outputPanel.show();
      } else if (error) {
        this.errorView.update(stdout, false);
        this.outputPanel.show();
      } else {
        this.errorView.update(stdout, true);
        if (atom.config.get('atom-phpunit.successAsNotifications')) {
          atom.notifications.addSuccess('Test Passed!', {description: cmd, detail: stdout});
        } else {
          this.outputPanel.show();
        }
      }
    });
  },

  getFunctionName() {
    let editor = atom.workspace.getActiveTextEditor();
    if (!editor)
      return false;

    let pos = editor.getCursorBufferPosition();
    let buffer = editor.getBuffer();

    for (var row = pos.row; row--; row > 0) {
      let line = buffer.lineForRow(row);
      if (line.includes('function ')) {
        let parts = line.match(/function\s+([^\s(]+)\s*\(/);
        if (parts && parts.length > 1)
          return parts[1];
      }
    }

    return false
  },

  getFilepath() {
    let editor = atom.workspace.getActivePaneItem();
    if (!editor)
      return false;

    let buffer = editor.buffer;
    if (!buffer)
      return false;

    let file = buffer.file;

    if (!file.path) {
      return false;
    }

    return file.path;
  },

  getProjectFolderPath() {
    return atom.project.relativizePath(this.getFilepath())[0];
  }

};
<|endoftext|>


<commit_before>import actionTypes from '../constants/actionTypes';

function setMessage(state, action) {
	let newState = { ...state };

	newState.message = action.payload.message;

	return newState;
}

function setWhen(state, action) {
	let newState = { ...state };

	newState.when = action.payload.when;

	return newState;
}

function setAuthor(state, action) {
	let newState = { ...state };

	newState.author = action.payload.author;

	return newState;
}

function setTodo(state, action) {
	let newState = { ...state };

	newState.getTodoId = action.payload.todo.id;
	newState.getTodoMessage = action.payload.todo.TODO;
	newState.getTodoWhen = action.payload.todo.when;
	newState.getTodoAuthor = action.payload.todo.author;

	return newState;
}

function setFindTodoId(state, action) {
	let newState = { ...state };

	newState.findTodoId = action.payload.find.id;

	return newState;
}

function setDeleteTodoId(state, action) {
	let newState = { ...state };

	newState.deleteTodoId = action.payload.delete.id;

	return newState;
}

function setLoadingMessage(state, action) {
	let newState = { ...state };

	newState.loadingMessage = action.payload.loadingMessage;

	return newState;
}

function addToLog(state, action) {
	let newState = { ...state };

	newState.log += `${new Date().toISOString()} - ${action.payload.log}\n`;

	return newState;
}

function setShouldNotGetTodoOnMount(state, action) {
	let newState = { ...state };

	newState.shouldNotGetTodoOnMount = action.payload.shouldNotGetTodoOnMount;

	return newState;
}

export default function (state = { log: '', findTodoId: '' }, action) {
	switch (action.type) {
		case actionTypes.SET_MESSAGE:
			return setMessage(state, action);
		case actionTypes.SET_WHEN:
			return setWhen(state, action);
		case actionTypes.SET_AUTHOR:
			return setAuthor(state, action);
		case actionTypes.SET_TODO:
			return setTodo(state, action);
		case actionTypes.SET_FIND_TODO_ID:
			return setFindTodoId(state, action);
		case actionTypes.SET_DELETE_TODO_ID:
			return setDeleteTodoId(state, action);
		case actionTypes.SET_LOADING_MESSAGE:
			return setLoadingMessage(state, action);
		case actionTypes.ADD_TO_LOG:
			return addToLog(state, action);
		case actionTypes.SET_SHOULD_NOT_GET_TODO_ON_MOUNT:
			return setShouldNotGetTodoOnMount(state, action);
		default:
			return state;
	}
}
<commit_msg>refactor: don't use initial state on log to get around undefined<commit_after>import actionTypes from '../constants/actionTypes';

function setMessage(state, action) {
	let newState = { ...state };

	newState.message = action.payload.message;

	return newState;
}

function setWhen(state, action) {
	let newState = { ...state };

	newState.when = action.payload.when;

	return newState;
}

function setAuthor(state, action) {
	let newState = { ...state };

	newState.author = action.payload.author;

	return newState;
}

function setTodo(state, action) {
	let newState = { ...state };

	newState.getTodoId = action.payload.todo.id;
	newState.getTodoMessage = action.payload.todo.TODO;
	newState.getTodoWhen = action.payload.todo.when;
	newState.getTodoAuthor = action.payload.todo.author;

	return newState;
}

function setFindTodoId(state, action) {
	let newState = { ...state };

	newState.findTodoId = action.payload.find.id;

	return newState;
}

function setDeleteTodoId(state, action) {
	let newState = { ...state };

	newState.deleteTodoId = action.payload.delete.id;

	return newState;
}

function setLoadingMessage(state, action) {
	let newState = { ...state };

	newState.loadingMessage = action.payload.loadingMessage;

	return newState;
}

function addToLog(state, action) {
	let newState = { ...state };

	if (!newState.log) {
		newState.log = '';
	}

	newState.log += `${new Date().toISOString()} - ${action.payload.log}\n`;

	return newState;
}

function setShouldNotGetTodoOnMount(state, action) {
	let newState = { ...state };

	newState.shouldNotGetTodoOnMount = action.payload.shouldNotGetTodoOnMount;

	return newState;
}

export default function (state = { }, action) {
	switch (action.type) {
		case actionTypes.SET_MESSAGE:
			return setMessage(state, action);
		case actionTypes.SET_WHEN:
			return setWhen(state, action);
		case actionTypes.SET_AUTHOR:
			return setAuthor(state, action);
		case actionTypes.SET_TODO:
			return setTodo(state, action);
		case actionTypes.SET_FIND_TODO_ID:
			return setFindTodoId(state, action);
		case actionTypes.SET_DELETE_TODO_ID:
			return setDeleteTodoId(state, action);
		case actionTypes.SET_LOADING_MESSAGE:
			return setLoadingMessage(state, action);
		case actionTypes.ADD_TO_LOG:
			return addToLog(state, action);
		case actionTypes.SET_SHOULD_NOT_GET_TODO_ON_MOUNT:
			return setShouldNotGetTodoOnMount(state, action);
		default:
			return state;
	}
}
<|endoftext|>


<commit_before>/**
* service.game Module
*
* Description
*/
angular.module('service.GameManager', [
    'resource.GameData',
    'service.GridService',
    'service.Piece'
])
.factory('GameManager', [
    'GameData',
    'GridService',
    'Piece',
function (
    GameData,
    GridService,
    Piece
){
    var game = {
        currentPiece: null,
        score: 0
    };

    game.newGame = function newGame() {
        game.currentPiece = new Piece({
            x: 4,
            y: 0
        });
        GridService.buildEmptyGameBoard();
    };

    game.setGameStart = function setGameStart() {
        GameData.gameStart = !GameData.gameStart;
        return this;
    };

    game.getGameSpeed = function getGameSpeed() {
        return GameData.speed;
    };

    game.setPause = function setPause() {
        GameData.gamePause = !GameData.gamePause;
        return this;
    };

    game.isPause = function isPause() {
        return GameData.gamePause;
    };

    game.isGameStart = function isGameStart() {
        return GameData.gameStart;
    };

    game.getScore = function getScore() {
        return game.score;
    };

    game.getCurrentPiece = function getCurrentPiece() {
        return game.currentPiece;
    };

    game.getCurrentPattern = function getCurrentPattern() {
        return game.currentPiece.getPattern();
    };

    game.getCurrentShape = function getCurrentShape() {
        return game.currentPiece.getShape();
    };

    game.rotatePiece = function rotatePiece() {
        return game.currentPiece.rotatePiece();
    };

    game.getPositionX = function getPositionX() {
        return game.currentPiece.getPositionX();
    };

    game.getPositionY = function getPositionY() {
        return game.currentPiece.getPositionY();
    };

    game.moveCurrentPiece = function moveCurrentPiece() {
        var speedY = game.getPositionY() + 1;
        game.currentPiece.updatePosition({
            y: speedY
        }, function(){
            game.insertPiece();
            GridService.checkAndClearFilledRow(function() {
                game.score += 100;
            });
        });
    };

    game.insertPiece = function insertPiece() {
        GridService.insertPiece(game.currentPiece);
        game.currentPiece.destroy();
        game.currentPiece = null;
        game.createNewPiece();
    };

    game.createNewPiece = function createNewPiece() {
        game.currentPiece = new Piece({
            x: 4,
            y: 0
        });
    };

    game.movePieceInLevel = function movePieceInLevel(direction) {
        var velocity = (direction === 'left') ? -1 : 1;
            speedX = game.getPositionX() + velocity;
        game.currentPiece.updatePosition({
            x: speedX
        });
    };

    game.move = function move(key) {
        switch(key) {
            case 'up': game.rotatePiece();
                break;
            case 'left': game.movePieceInLevel('left');
                break;
            case 'right': game.movePieceInLevel('right');
                break;
            case 'down': game.moveCurrentPiece();
                break;
            case 'space':
                break;
            case 'p':
            case 'esc': game.setPause();
                break;
            default:
                break;
        }
    };

    return game;
}]);<commit_msg>don't create piece before the game start<commit_after>/**
* service.game Module
*
* Description
*/
angular.module('service.GameManager', [
    'resource.GameData',
    'service.GridService',
    'service.Piece'
])
.factory('GameManager', [
    'GameData',
    'GridService',
    'Piece',
function (
    GameData,
    GridService,
    Piece
){
    var game = {
        currentPiece: null,
        score: 0
    };

    game.newGame = function newGame() {
        GridService.buildEmptyGameBoard();
    };

    game.setGameStart = function setGameStart() {
        GameData.gameStart = !GameData.gameStart;
        return this;
    };

    game.getGameSpeed = function getGameSpeed() {
        return GameData.speed;
    };

    game.setPause = function setPause() {
        GameData.gamePause = !GameData.gamePause;
        return this;
    };

    game.isPause = function isPause() {
        return GameData.gamePause;
    };

    game.isGameStart = function isGameStart() {
        return GameData.gameStart;
    };

    game.getScore = function getScore() {
        return game.score;
    };

    game.getCurrentPiece = function getCurrentPiece() {
        return game.currentPiece;
    };

    game.getCurrentPattern = function getCurrentPattern() {
        return game.currentPiece.getPattern();
    };

    game.getCurrentShape = function getCurrentShape() {
        return game.currentPiece.getShape();
    };

    game.rotatePiece = function rotatePiece() {
        return game.currentPiece.rotatePiece();
    };

    game.getPositionX = function getPositionX() {
        return game.currentPiece.getPositionX();
    };

    game.getPositionY = function getPositionY() {
        return game.currentPiece.getPositionY();
    };

    game.moveCurrentPiece = function moveCurrentPiece() {
        var speedY = game.getPositionY() + 1;
        game.currentPiece.updatePosition({
            y: speedY
        }, function(){
            game.insertPiece();
            GridService.checkAndClearFilledRow(function() {
                game.score += 100;
            });
        });
    };

    game.insertPiece = function insertPiece() {
        GridService.insertPiece(game.currentPiece);
        game.currentPiece.destroy();
        game.currentPiece = null;
        game.createNewPiece();
    };

    game.createNewPiece = function createNewPiece() {
        game.currentPiece = new Piece({
            x: 4,
            y: 0
        });
    };

    game.movePieceInLevel = function movePieceInLevel(direction) {
        var velocity = (direction === 'left') ? -1 : 1;
            speedX = game.getPositionX() + velocity;
        game.currentPiece.updatePosition({
            x: speedX
        });
    };

    game.move = function move(key) {
        switch(key) {
            case 'up': game.rotatePiece();
                break;
            case 'left': game.movePieceInLevel('left');
                break;
            case 'right': game.movePieceInLevel('right');
                break;
            case 'down': game.moveCurrentPiece();
                break;
            case 'space':
                break;
            case 'p':
            case 'esc': game.setPause();
                break;
            default:
                break;
        }
    };

    return game;
}]);<|endoftext|>


<commit_before>require('express-hijackresponse');
require('bufferjs');

module.exports = function (options) {
    if (typeof options.options === undefined) {
        // Default options for autoprefixer. See https://github.com/ai/autoprefixer#browsers
        options.options = [
            '> 1%',
            'last 2 versions',
            'Firefox ESR',
            'Opera 12.1'
        ];
    }
    if (typeof options.options === 'string') {
        options.options = options.options.split(/,\s*/);
    }
    if (!Array.isArray(options.options)) {
        throw new Error('express-autoprefixer: options must be provided as string or list');
    }

    var autoprefixer = options.autoprefixer || require('autoprefixer');

    return function (req, res, next) {
        // Prevent If-None-Match revalidation with the downstream middleware with ETags that aren't suffixed with "-autoprefixer":
        var ifNoneMatch = req.headers['if-none-match'];
        if (ifNoneMatch) {
            var validIfNoneMatchTokens = ifNoneMatch.split(" ").filter(function (etag) {
                return /-autoprefixer\"$/.test(etag);
            });
            if (validIfNoneMatchTokens.length > 0) {
                req.headers['if-none-match'] = validIfNoneMatchTokens.join(" ");
            } else {
                delete req.headers['if-none-match'];
            }
        }
        delete req.headers['if-modified-since']; // Prevent false positive conditional GETs after enabling autoprefixer
        res.hijack(function (err, res) {
            var contentType = res.getHeader('Content-Type'),
            matchContentType = contentType && contentType.match(/^text\/css(?:;\s*charset=([a-z0-9\-]+))?$/i);
            // The mime module doesn't support less yet, so we fall back:
            if (matchContentType) {
                var chunks = [];
                res.on('error', function () {
                    res.unhijack();
                    next();
                }).on('data', function (chunk) {
                    chunks.push(chunk);
                }).on('end', function () {
                    if (!chunks.length) {
                        return res.send(res.statusCode);
                    }
                    var cssText = Buffer.concat(chunks).toString('utf-8'); // No other charsets are really relevant, right?

                    cssText = autoprefixer.apply(null, options.options).process(cssText).css;

                    res.setHeader('Content-Type', 'text/css');
                    res.setHeader('Content-Length', Buffer.byteLength(cssText));
                    res.end(cssText);
                });
            } else {
                res.unhijack(true);
            }
        });
        next();
    };
};
<commit_msg>fix defaulting of options<commit_after>require('express-hijackresponse');
require('bufferjs');

module.exports = function (options) {
    if (typeof options.options === 'undefined') {
        // Default options for autoprefixer. See https://github.com/ai/autoprefixer#browsers
        options.options = [
            '> 1%',
            'last 2 versions',
            'Firefox ESR',
            'Opera 12.1'
        ];
    }
    if (typeof options.options === 'string') {
        options.options = options.options.split(/,\s*/);
    }
    if (!Array.isArray(options.options)) {
        throw new Error('express-autoprefixer: options must be provided as string or list');
    }

    var autoprefixer = options.autoprefixer || require('autoprefixer');

    return function (req, res, next) {
        // Prevent If-None-Match revalidation with the downstream middleware with ETags that aren't suffixed with "-autoprefixer":
        var ifNoneMatch = req.headers['if-none-match'];
        if (ifNoneMatch) {
            var validIfNoneMatchTokens = ifNoneMatch.split(" ").filter(function (etag) {
                return /-autoprefixer\"$/.test(etag);
            });
            if (validIfNoneMatchTokens.length > 0) {
                req.headers['if-none-match'] = validIfNoneMatchTokens.join(" ");
            } else {
                delete req.headers['if-none-match'];
            }
        }
        delete req.headers['if-modified-since']; // Prevent false positive conditional GETs after enabling autoprefixer
        res.hijack(function (err, res) {
            var contentType = res.getHeader('Content-Type'),
            matchContentType = contentType && contentType.match(/^text\/css(?:;\s*charset=([a-z0-9\-]+))?$/i);
            // The mime module doesn't support less yet, so we fall back:
            if (matchContentType) {
                var chunks = [];
                res.on('error', function () {
                    res.unhijack();
                    next();
                }).on('data', function (chunk) {
                    chunks.push(chunk);
                }).on('end', function () {
                    if (!chunks.length) {
                        return res.send(res.statusCode);
                    }
                    var cssText = Buffer.concat(chunks).toString('utf-8'); // No other charsets are really relevant, right?

                    cssText = autoprefixer.apply(null, options.options).process(cssText).css;

                    res.setHeader('Content-Type', 'text/css');
                    res.setHeader('Content-Length', Buffer.byteLength(cssText));
                    res.end(cssText);
                });
            } else {
                res.unhijack(true);
            }
        });
        next();
    };
};
<|endoftext|>


<commit_before>/*jshint esnext: true */
var request = require('request'),
  _url = require('url'),
  async = require('async');

/**
 * Sends a HTTP request to a specified URL with optional proxy, query strings, and handlers.
 * Convenient handling of request error and unexpected status code.
 * GET redirection is handled by default by request module.
 * Non-GET redirection is handled by params followAllRedirects: true.
 *
 * @param {String} method: http method
 * @param {String} url: URL without query string
 * @param {Object} opts: optional
 *   - proxy: proxy server URL with format http://user:pass@host:port
 *   - noProxyHosts: an array of host names which will ignore any proxy settings, defaults to: localhost, 127.0.0.1
 *   - queryStrings: object containing URL query strings with format { name: value }
 *   - handlers: response handlers with format { statuscode: function(result, cb) }
 *   - headers: object containing http headers, exact map to mikeal/request headers opt
 *   - body, form, json, multipart: request payload, exact map to mikeal/request module body, form, json, multipart opts
 *   - retry: request retry configuration, false for disabled, true for sensible defaults, otherwise
 *            { statusCodes: [ 503 ], scale: 0.5, delay: 1000, maxRetries: 10 }
 *   - timeout: request timeout in milliseconds, default to 30000 milliseconds
 *   - requestOpts: mikeal/request module opts, these opts will override any params set by http#req
 * @param {Function} cb: standard cb(err, result) callback
 */
function req(method, url, opts, cb) {
  opts.handlers = opts.handlers || {};
  opts.retry = opts.retry || false;

  const TIMEOUT = 30000;
  // init default settings with follow redirections on all methods, and 30 seconds timeout
  var params = {
      url: url,
      followAllRedirects: true,
      rejectUnauthorized: false,
      timeout: opts.timeout || TIMEOUT
    },
    envProxy = proxy(url);

  // set proxy setting based on environment variable
  if (!_proxyIgnored(url, opts)) {
    if (opts.proxy) {
      params.proxy = opts.proxy;
    } else if (envProxy) {
      params.proxy = envProxy;
    }
  }

  // just a more readable opt name for query strings
  if (opts.queryStrings) {
    params.qs = opts.queryStrings;
  }

  // headers and payload handling
  ['headers', 'body', 'form', 'json', 'multipart'].forEach(function (opt) {
    if (opts[opt]) {
      params[opt] = opts[opt];
    }
  });

  // override defaults with mikeal/request-specific opts
  if (opts.requestOpts) {
    Object.keys(opts.requestOpts).forEach(function (opt) {
      params[opt] = opts.requestOpts[opt];
    });
  }

  // check for any wildcard match (e.g. 201 matches 2xx)
  function _wildcardMatch(statusCode) {
    var match;
    Object.keys(opts.handlers).forEach(function (handlerStatusCode) {
      var regex = new RegExp(handlerStatusCode.replace(/x/g, '.'));
      if (!match && statusCode.toString().match(regex)) {
        match = handlerStatusCode;
      }
    });
    return match;
  }

  function _requestMethod(method) {
    var requestMethod = method.toLowerCase();
    if (requestMethod === 'delete') {
      requestMethod = 'del';
    }
    return requestMethod;
  }

  _execRequest(opts, _requestMethod(method), params, function (err, result) {
    if (err) {
      cb(err);
    } else {
      var wildcardMatch = _wildcardMatch(result.statusCode);
      if (opts.handlers[result.statusCode]) {
        opts.handlers[result.statusCode](result, cb);
      } else if (wildcardMatch) {
        opts.handlers[wildcardMatch](result, cb);
      } else {
        cb(new Error('Unexpected status code: ' + result.statusCode + '\nResponse body:\n' + result.body));
      }
    }
  });
}

function _execRequest(opts, method, params, cb) {
  var defaults = { statusCodes: [ 408, 502, 503, 504 ], scale: 0.5, delay: 500, maxRetries: 10 },
    retry = opts.retry === true ? defaults : opts.retry,
    retryCount = 0,
    scaleFactor = retry.scale || 0.5,
    currentDelay = retry.delay || 500,
    hasValidResult = false,
    lastErr = null,
    lastResult = null,
    retryLimitHit = false;
  retry.maxRetries = retry.maxRetries >= 0 ? retry.maxRetries : NaN;
  retry.statusCodes = retry.statusCodes || [];

  function _retryableStatusCodeMatch(statusCode) {
    var matches = false;
    if (retry) {
      (retry.statusCodes || []).forEach(function (aWildStatusCodeAppears) {
        var regex = new RegExp(aWildStatusCodeAppears.toString().replace(/x/g, '.'));
        matches = matches || statusCode.toString().match(regex);
      });
    }
    return matches;
  }

  async.whilst(
    function doesNotHaveValidResultOrRetryLimitHit() {
      retryLimitHit = !(retryCount < retry.maxRetries);
      return !hasValidResult && (!retry || (retry && !retryLimitHit));
    },
    function retryRequest(cb) {
      request[method](params, function (err, result) {
        result = result || {};
        result._retry = { retryCount: retryCount };
        lastErr = err;
        lastResult = result;

        var hasRetryStatus = _retryableStatusCodeMatch(result.statusCode),
          isLastRetry = !(retryCount + 1 < retry.maxRetries);

        if (hasRetryStatus && isLastRetry) {
          retryCount++;
          cb();
        } else if (hasRetryStatus) {
          retryCount++;
          setTimeout(cb, currentDelay);
          currentDelay += currentDelay * scaleFactor;
        } else {
          hasValidResult = true;
          cb();
        }
      });
    },
    function done(err) {
      if (lastResult) lastResult._retry.retryLimitHit = retryLimitHit;
      cb(lastErr, lastResult);
    }
  );
}

/**
 * Determines proxy value based on URL and process environment variable (http_proxy, https_proxy).
 * This allows library clients to control which proxy to use by setting environment variable.
 * - if url starts with http, use http_proxy when available
 * - if url starts with https, use https_proxy when available, otherwise fallback to http_proxy
 * - if url does not have protocol, assume http protocol
 * - if url is not specified, http_proxy takes precedence over https_proxy
 *
 * @param {String} url: URL used to determine which proxy environment variable to use
 * @param {Object} opts: optional
 *   - noProxyHosts: an array of host names which will ignore any proxy settings, defaults to: localhost, 127.0.0.1
 */
function proxy(url, opts) {
  opts = opts || {};

  var _proxy;

  if (!url) {
    _proxy = process.env.http_proxy || process.env.HTTP_PROXY || process.env.https_proxy || process.env.HTTPS_PROXY;
  } else if (!_proxyIgnored(url, opts)) {
    if (!url.match(/^https?:\/\//)) {
      url += 'http://' + url;
    }

    if (url.match(/^https:\/\//)) {
      _proxy = process.env.https_proxy || process.env.HTTPS_PROXY || process.env.http_proxy || process.env.HTTP_PROXY;
    } else {
      _proxy = process.env.http_proxy || process.env.HTTP_PROXY;
    }
  }

  return _proxy;
}

function _proxyIgnored(url, opts) {
  const NO_PROXY_HOSTS = ['localhost', '127.0.0.1'];
  return (opts.noProxyHosts || NO_PROXY_HOSTS).indexOf(_url.parse(url).hostname) !== -1;
}

exports.request = req;
exports.proxy = proxy;
<commit_msg>Clean up lint violations.<commit_after>/*jshint esnext: true */
var request = require('request'),
  _url = require('url'),
  async = require('async');

/**
 * Sends a HTTP request to a specified URL with optional proxy, query strings, and handlers.
 * Convenient handling of request error and unexpected status code.
 * GET redirection is handled by default by request module.
 * Non-GET redirection is handled by params followAllRedirects: true.
 *
 * @param {String} method: http method
 * @param {String} url: URL without query string
 * @param {Object} opts: optional
 *   - proxy: proxy server URL with format http://user:pass@host:port
 *   - noProxyHosts: an array of host names which will ignore any proxy settings, defaults to: localhost, 127.0.0.1
 *   - queryStrings: object containing URL query strings with format { name: value }
 *   - handlers: response handlers with format { statuscode: function(result, cb) }
 *   - headers: object containing http headers, exact map to mikeal/request headers opt
 *   - body, form, json, multipart: request payload, exact map to mikeal/request module body, form, json, multipart opts
 *   - retry: request retry configuration, false for disabled, true for sensible defaults, otherwise
 *            { statusCodes: [ 503 ], scale: 0.5, delay: 1000, maxRetries: 10 }
 *   - timeout: request timeout in milliseconds, default to 30000 milliseconds
 *   - requestOpts: mikeal/request module opts, these opts will override any params set by http#req
 * @param {Function} cb: standard cb(err, result) callback
 */
function req(method, url, opts, cb) {
  opts.handlers = opts.handlers || {};
  opts.retry = opts.retry || false;

  const TIMEOUT = 30000;
  // init default settings with follow redirections on all methods, and 30 seconds timeout
  var params = {
      url: url,
      followAllRedirects: true,
      rejectUnauthorized: false,
      timeout: opts.timeout || TIMEOUT
    },
    envProxy = proxy(url);

  // set proxy setting based on environment variable
  if (!_proxyIgnored(url, opts)) {
    if (opts.proxy) {
      params.proxy = opts.proxy;
    } else if (envProxy) {
      params.proxy = envProxy;
    }
  }

  // just a more readable opt name for query strings
  if (opts.queryStrings) {
    params.qs = opts.queryStrings;
  }

  // headers and payload handling
  ['headers', 'body', 'form', 'json', 'multipart'].forEach(function (opt) {
    if (opts[opt]) {
      params[opt] = opts[opt];
    }
  });

  // override defaults with mikeal/request-specific opts
  if (opts.requestOpts) {
    Object.keys(opts.requestOpts).forEach(function (opt) {
      params[opt] = opts.requestOpts[opt];
    });
  }

  // check for any wildcard match (e.g. 201 matches 2xx)
  function _wildcardMatch(statusCode) {
    var match;
    Object.keys(opts.handlers).forEach(function (handlerStatusCode) {
      var regex = new RegExp(handlerStatusCode.replace(/x/g, '.'));
      if (!match && statusCode.toString().match(regex)) {
        match = handlerStatusCode;
      }
    });
    return match;
  }

  function _requestMethod(method) {
    var requestMethod = method.toLowerCase();
    if (requestMethod === 'delete') {
      requestMethod = 'del';
    }
    return requestMethod;
  }

  _execRequest(opts, _requestMethod(method), params, function (err, result) {
    if (err) {
      cb(err);
    } else {
      var wildcardMatch = _wildcardMatch(result.statusCode);
      if (opts.handlers[result.statusCode]) {
        opts.handlers[result.statusCode](result, cb);
      } else if (wildcardMatch) {
        opts.handlers[wildcardMatch](result, cb);
      } else {
        cb(new Error('Unexpected status code: ' + result.statusCode + '\nResponse body:\n' + result.body));
      }
    }
  });
}

function _execRequest(opts, method, params, cb) {
  var defaults = { statusCodes: [ 408, 502, 503, 504 ], scale: 0.5, delay: 500, maxRetries: 10 },
    retry = opts.retry === true ? defaults : opts.retry,
    retryCount = 0,
    scaleFactor = retry.scale || 0.5,
    currentDelay = retry.delay || 500,
    hasValidResult = false,
    lastErr = null,
    lastResult = null,
    retryLimitHit = false;
  retry.maxRetries = retry.maxRetries >= 0 ? retry.maxRetries : NaN;
  retry.statusCodes = retry.statusCodes || [];

  function _retryableStatusCodeMatch(statusCode) {
    var matches = false;
    if (retry) {
      (retry.statusCodes || []).forEach(function (aWildStatusCodeAppears) {
        var regex = new RegExp(aWildStatusCodeAppears.toString().replace(/x/g, '.'));
        matches = matches || statusCode.toString().match(regex);
      });
    }
    return matches;
  }

  async.whilst(
    function doesNotHaveValidResultOrRetryLimitHit() {
      retryLimitHit = retryCount >= retry.maxRetries;
      return !hasValidResult && (!retry || (retry && !retryLimitHit));
    },
    function retryRequest(cb) {
      request[method](params, function (err, result) {
        result = result || {};
        result._retry = { retryCount: retryCount };
        lastErr = err;
        lastResult = result;

        var hasRetryStatus = _retryableStatusCodeMatch(result.statusCode),
          isLastRetry = retryCount + 1 >= retry.maxRetries;

        if (hasRetryStatus && isLastRetry) {
          retryCount++;
          cb();
        } else if (hasRetryStatus) {
          retryCount++;
          setTimeout(cb, currentDelay);
          currentDelay += currentDelay * scaleFactor;
        } else {
          hasValidResult = true;
          cb();
        }
      });
    },
    function done(err) {
      if (lastResult) lastResult._retry.retryLimitHit = retryLimitHit;
      cb(lastErr, lastResult);
    }
  );
}

/**
 * Determines proxy value based on URL and process environment variable (http_proxy, https_proxy).
 * This allows library clients to control which proxy to use by setting environment variable.
 * - if url starts with http, use http_proxy when available
 * - if url starts with https, use https_proxy when available, otherwise fallback to http_proxy
 * - if url does not have protocol, assume http protocol
 * - if url is not specified, http_proxy takes precedence over https_proxy
 *
 * @param {String} url: URL used to determine which proxy environment variable to use
 * @param {Object} opts: optional
 *   - noProxyHosts: an array of host names which will ignore any proxy settings, defaults to: localhost, 127.0.0.1
 */
function proxy(url, opts) {
  opts = opts || {};

  var _proxy;

  if (!url) {
    _proxy = process.env.http_proxy || process.env.HTTP_PROXY || process.env.https_proxy || process.env.HTTPS_PROXY;
  } else if (!_proxyIgnored(url, opts)) {
    if (!url.match(/^https?:\/\//)) {
      url += 'http://' + url;
    }

    if (url.match(/^https:\/\//)) {
      _proxy = process.env.https_proxy || process.env.HTTPS_PROXY || process.env.http_proxy || process.env.HTTP_PROXY;
    } else {
      _proxy = process.env.http_proxy || process.env.HTTP_PROXY;
    }
  }

  return _proxy;
}

function _proxyIgnored(url, opts) {
  const NO_PROXY_HOSTS = ['localhost', '127.0.0.1'];
  return (opts.noProxyHosts || NO_PROXY_HOSTS).indexOf(_url.parse(url).hostname) !== -1;
}

exports.request = req;
exports.proxy = proxy;
<|endoftext|>


<commit_before>import React from 'react';
import {List, ListItem} from 'material-ui/List';
import Divider from 'material-ui/Divider';
import Paper from 'material-ui/Paper';
import PeopleOutlineIcon from 'material-ui/svg-icons/social/people-outline';
import PeopleIcon from 'material-ui/svg-icons/social/people';
import EventIcon from 'material-ui/svg-icons/action/event';
import PlaceIcon from 'material-ui/svg-icons/maps/place';
import DirectionIcon from 'material-ui/svg-icons/maps/directions';
import IconButton from 'material-ui/IconButton';
import Avatar from 'material-ui/Avatar';
import math from 'mathjs';
import $ from 'jquery';

const getEtherIcon = () =>(
  <Avatar src={require('../images/ethereum.ico')} size={26} backgroundColor="white" />
)

const styles = {
  paperLeft:{
    flex: 2,
    height: '100%',
    textAlign: 'left',
    padding: 10
  },
  list:{
    float:'right', color: 'grey', merginHight:1
  },
  innerDiv:{
    paddingTop:1, paddingBottom:1, paddingRight:1
  }
};

class ConferenceDetail extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      etherscan_url:null
    };
  }

  componentDidMount(){
    // Initialize
    this.props.eventEmitter.on('detail', detail => {
      this.setState(detail);
    })

    this.props.eventEmitter.on('network', network => {
      this.setState({
        etherscan_url: network.etherscan_url
      });
    })

    // If the app failed to get detail from contract (meaning either connecting
    // to wrong network or the contract id does not match to the one deployed),
    // it will show instruction page.
    setTimeout(function(){
      if(typeof(this.state.name) == 'undefined'){
        this.props.eventEmitter.emit('instruction');
      }
    }.bind(this), 5000)
    // Listen to watcher event.
    this.serverRequest = $.get('https://www.cryptocompare.com/api/data/price?fsym=ETH&tsyms=GBP', function (result) {
      debugger;
      this.setState({
        rate: result.Data[0].Price / 20
      });
    }.bind(this));
  }

  toEther(value){
    if(value){
      return math.round(this.props.web3.fromWei(value, "ether").toNumber(), 3).toString();
    }
  }

  toNumber(value){
    if(value) return value.toNumber();
  }

  getNameContent(name, contractAddress){
    if(name){
      if (this.state.etherscan_url) {
        return (

            {name} (<a target='_blank' href={ `${this.state.etherscan_url}/address/${contractAddress}` }>{contractAddress.slice(0,5)}...)

        )
      }else{
        return (

            {name} ({contractAddress.slice(0,5)}...)

        )
      }
    }else{
      return (

          The contract {contractAddress.slice(0,10)}... not available

      )
    }
  }

  getDateContent(name){
    if(name){
      var d = new Date();
      var curr_date = d.getDate();
      var curr_month = d.getMonth() + 1; //Months are zero based
      var curr_year = d.getFullYear();
      var date = `${curr_date}-${curr_month}-${curr_year}`

      return (
        {name}
      )
    }else{
      return (
        No info available
      )
    }
  }

  getDepositContent(deposit, rate){
    if(deposit){
      return (
        {this.toEther(deposit)} (£{rate})
      )
    }else{
      return (
        No info available
      )
    }
  }

  render() {
    let attendancyStatus;
    if (this.state.ended) {
      attendancyStatus =
Attended{this.toNumber(this.state.attended)}

    }else{
      attendancyStatus =
Going (spots left){this.toNumber(this.state.registered)}({this.toNumber(this.state.limitOfParticipants) - this.toNumber(this.state.registered)})

    }

    return (
      <Paper zDepth={1} style={styles.paperLeft}>

Event Info

        <List>
          <ListItem innerDivStyle={styles.innerDiv} insetChildren={true} disabled={true}
            primaryText={

Name{this.getNameContent(this.state.name, this.props.contractAddress)}

            }
          />
          <ListItem innerDivStyle={styles.innerDiv} leftIcon={<EventIcon />} disabled={true}
            primaryText={

Date{this.getDateContent(this.state.date)}

            }
          />
          <ListItem innerDivStyle={styles.innerDiv} leftIcon={<PlaceIcon />} disabled={true}
            primaryText={

Location

                  {this.state.location_text}

            }
          />
          <ListItem innerDivStyle={styles.innerDiv} leftIcon={<DirectionIcon />} disabled={true}
            primaryText={

Description

            }
          />
          <ListItem innerDivStyle={styles.innerDiv} leftIcon={getEtherIcon()} disabled={true}
            primaryText={

Deposit{this.getDepositContent(this.state.deposit, this.state.rate)}

            }
          />
        <Divider />
          <ListItem innerDivStyle={styles.innerDiv} leftIcon={getEtherIcon()} disabled={true}
          primaryText={

Pot{this.toEther(this.state.totalBalance)}

          }
          />
          <ListItem innerDivStyle={styles.innerDiv} leftIcon={<PeopleIcon />} disabled={true}
          primaryText={attendancyStatus}
          />
        </List>
      </Paper>
    );
  }
}

export default ConferenceDetail;
<commit_msg>Switch API to coinmarketcap<commit_after>import React from 'react';
import {List, ListItem} from 'material-ui/List';
import Divider from 'material-ui/Divider';
import Paper from 'material-ui/Paper';
import PeopleOutlineIcon from 'material-ui/svg-icons/social/people-outline';
import PeopleIcon from 'material-ui/svg-icons/social/people';
import EventIcon from 'material-ui/svg-icons/action/event';
import PlaceIcon from 'material-ui/svg-icons/maps/place';
import DirectionIcon from 'material-ui/svg-icons/maps/directions';
import IconButton from 'material-ui/IconButton';
import Avatar from 'material-ui/Avatar';
import math from 'mathjs';
import $ from 'jquery';

const getEtherIcon = () =>(
  <Avatar src={require('../images/ethereum.ico')} size={26} backgroundColor="white" />
)

const styles = {
  paperLeft:{
    flex: 2,
    height: '100%',
    textAlign: 'left',
    padding: 10
  },
  list:{
    float:'right', color: 'grey', merginHight:1
  },
  innerDiv:{
    paddingTop:1, paddingBottom:1, paddingRight:1
  }
};

class ConferenceDetail extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      etherscan_url:null
    };
  }

  componentDidMount(){
    // Initialize
    this.props.eventEmitter.on('detail', detail => {
      this.setState(detail);
    })

    this.props.eventEmitter.on('network', network => {
      this.setState({
        etherscan_url: network.etherscan_url
      });
    })

    // If the app failed to get detail from contract (meaning either connecting
    // to wrong network or the contract id does not match to the one deployed),
    // it will show instruction page.
    setTimeout(function(){
      if(typeof(this.state.name) == 'undefined'){
        this.props.eventEmitter.emit('instruction');
      }
    }.bind(this), 5000)
    // Listen to watcher event.
    this.serverRequest = $.get('https://coinmarketcap-nexuist.rhcloud.com/api/eth', function (result) {
      this.setState({
        rate: math.round((result.price.gbp / 20), 2).toString()
      });
    }.bind(this));
  }

  toEther(value){
    if(value){
      return math.round(this.props.web3.fromWei(value, "ether").toNumber(), 3).toString();
    }
  }

  toNumber(value){
    if(value) return value.toNumber();
  }

  getNameContent(name, contractAddress){
    if(name){
      if (this.state.etherscan_url) {
        return (

            {name} (<a target='_blank' href={ `${this.state.etherscan_url}/address/${contractAddress}` }>{contractAddress.slice(0,5)}...)

        )
      }else{
        return (

            {name} ({contractAddress.slice(0,5)}...)

        )
      }
    }else{
      return (

          The contract {contractAddress.slice(0,10)}... not available

      )
    }
  }

  getDateContent(name){
    if(name){
      var d = new Date();
      var curr_date = d.getDate();
      var curr_month = d.getMonth() + 1; //Months are zero based
      var curr_year = d.getFullYear();
      var date = `${curr_date}-${curr_month}-${curr_year}`

      return (
        {name}
      )
    }else{
      return (
        No info available
      )
    }
  }

  getDepositContent(deposit, rate){
    if(deposit){
      return (
        {this.toEther(deposit)} (£{rate})
      )
    }else{
      return (
        No info available
      )
    }
  }

  render() {
    let attendancyStatus;
    if (this.state.ended) {
      attendancyStatus =
Attended{this.toNumber(this.state.attended)}

    }else{
      attendancyStatus =
Going (spots left){this.toNumber(this.state.registered)}({this.toNumber(this.state.limitOfParticipants) - this.toNumber(this.state.registered)})

    }

    return (
      <Paper zDepth={1} style={styles.paperLeft}>

Event Info

        <List>
          <ListItem innerDivStyle={styles.innerDiv} insetChildren={true} disabled={true}
            primaryText={

Name{this.getNameContent(this.state.name, this.props.contractAddress)}

            }
          />
          <ListItem innerDivStyle={styles.innerDiv} leftIcon={<EventIcon />} disabled={true}
            primaryText={

Date{this.getDateContent(this.state.date)}

            }
          />
          <ListItem innerDivStyle={styles.innerDiv} leftIcon={<PlaceIcon />} disabled={true}
            primaryText={

Location

                  {this.state.location_text}

            }
          />
          <ListItem innerDivStyle={styles.innerDiv} leftIcon={<DirectionIcon />} disabled={true}
            primaryText={

Description

            }
          />
          <ListItem innerDivStyle={styles.innerDiv} leftIcon={getEtherIcon()} disabled={true}
            primaryText={

Deposit{this.getDepositContent(this.state.deposit, this.state.rate)}

            }
          />
        <Divider />
          <ListItem innerDivStyle={styles.innerDiv} leftIcon={getEtherIcon()} disabled={true}
          primaryText={

Pot{this.toEther(this.state.totalBalance)}

          }
          />
          <ListItem innerDivStyle={styles.innerDiv} leftIcon={<PeopleIcon />} disabled={true}
          primaryText={attendancyStatus}
          />
        </List>
      </Paper>
    );
  }
}

export default ConferenceDetail;
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import Error from '../components/Error';
import withIntl from '../lib/withIntl';
import Expenses from '../components/Expenses';
import { graphql } from 'react-apollo'
import gql from 'graphql-tag'

class ExpensesWithData extends React.Component {

  static propTypes = {
    collective: PropTypes.object,
    limit: PropTypes.number,
    editable: PropTypes.bool,
    includeHostedCollectives: PropTypes.bool,
    LoggedInUser: PropTypes.object
  }

  constructor(props) {
    super(props);
  }

  render() {
    const {
      data,
      LoggedInUser,
      collective,
      editable,
      includeHostedCollectives
    } = this.props;

    if (data.error) {
      console.error("graphql error>>>", data.error.message);
      return (<Error message="GraphQL error" />)
    }

    const expenses = data.allExpenses;

    return (

        <Expenses
          collective={collective}
          expenses={expenses}
          refetch={data.refetch}
          editable={editable}
          fetchMore={data.fetchMore}
          LoggedInUser={LoggedInUser}
          includeHostedCollectives={includeHostedCollectives}
          />

    );
  }

}

const getExpensesQuery = gql`
query Expenses($CollectiveId: Int!, $status: String, $limit: Int, $offset: Int, $includeHostedCollectives: Boolean) {
  allExpenses(CollectiveId: $CollectiveId, status: $status, limit: $limit, offset: $offset, includeHostedCollectives: $includeHostedCollectives) {
    id
    description
    status
    createdAt
    incurredAt
    category
    amount
    currency
    payoutMethod
    privateMessage
    attachment
    collective {
      id
      slug
      currency
      name
      host {
        id
        slug
      }
      stats {
        id
        balance
      }
    }
    fromCollective {
      id
      type
      name
      slug
      image
    }
    user {
      id
      paypalEmail
    }
  }
}
`;

const EXPENSES_PER_PAGE = 10;
export const addExpensesData = graphql(getExpensesQuery, {
  options(props) {
    return {
      variables: {
        CollectiveId: props.collective.id,
        offset: 0,
        limit: props.limit || EXPENSES_PER_PAGE * 2,
        includeHostedCollectives: props.includeHostedCollectives || false
      }
    }
  },
  props: ({ data }) => ({
    data,
    fetchMore: () => {
      return data.fetchMore({
        variables: {
          offset: data.allExpenses.length,
          limit: EXPENSES_PER_PAGE
        },
        updateQuery: (previousResult, { fetchMoreResult }) => {
          if (!fetchMoreResult) {
            return previousResult
          }
          return Object.assign({}, previousResult, {
            // Append the new posts results to the old one
            allExpenses: [...previousResult.allExpenses, ...fetchMoreResult.allExpenses]
          })
        }
      })
    }
  })
});

export default addExpensesData(withIntl(ExpensesWithData));<commit_msg>fix expenses load more<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import Error from '../components/Error';
import withIntl from '../lib/withIntl';
import Expenses from '../components/Expenses';
import { graphql } from 'react-apollo'
import gql from 'graphql-tag'

class ExpensesWithData extends React.Component {

  static propTypes = {
    collective: PropTypes.object,
    limit: PropTypes.number,
    editable: PropTypes.bool,
    includeHostedCollectives: PropTypes.bool,
    LoggedInUser: PropTypes.object
  }

  constructor(props) {
    super(props);
  }

  render() {
    const {
      data,
      LoggedInUser,
      collective,
      editable,
      includeHostedCollectives
    } = this.props;

    if (data.error) {
      console.error("graphql error>>>", data.error.message);
      return (<Error message="GraphQL error" />)
    }

    const expenses = data.allExpenses;

    return (

        <Expenses
          collective={collective}
          expenses={expenses}
          refetch={data.refetch}
          editable={editable}
          fetchMore={this.props.fetchMore}
          LoggedInUser={LoggedInUser}
          includeHostedCollectives={includeHostedCollectives}
          />

    );
  }

}

const getExpensesQuery = gql`
query Expenses($CollectiveId: Int!, $status: String, $limit: Int, $offset: Int, $includeHostedCollectives: Boolean) {
  allExpenses(CollectiveId: $CollectiveId, status: $status, limit: $limit, offset: $offset, includeHostedCollectives: $includeHostedCollectives) {
    id
    description
    status
    createdAt
    incurredAt
    category
    amount
    currency
    payoutMethod
    privateMessage
    attachment
    collective {
      id
      slug
      currency
      name
      host {
        id
        slug
      }
      stats {
        id
        balance
      }
    }
    fromCollective {
      id
      type
      name
      slug
      image
    }
    user {
      id
      paypalEmail
    }
  }
}
`;

const EXPENSES_PER_PAGE = 10;
export const addExpensesData = graphql(getExpensesQuery, {
  options(props) {
    return {
      variables: {
        CollectiveId: props.collective.id,
        offset: 0,
        limit: props.limit || EXPENSES_PER_PAGE * 2,
        includeHostedCollectives: props.includeHostedCollectives || false
      }
    }
  },
  props: ({ data }) => ({
    data,
    fetchMore: () => {
      return data.fetchMore({
        variables: {
          offset: data.allExpenses.length,
          limit: EXPENSES_PER_PAGE
        },
        updateQuery: (previousResult, { fetchMoreResult }) => {
          if (!fetchMoreResult) {
            return previousResult
          }
          return Object.assign({}, previousResult, {
            // Append the new posts results to the old one
            allExpenses: [...previousResult.allExpenses, ...fetchMoreResult.allExpenses]
          })
        }
      })
    }
  })
});

export default addExpensesData(withIntl(ExpensesWithData));<|endoftext|>