<commit_before><commit_msg>add matrix operations<commit_after>class MatrixOperations {
  /**
   * getWeightsSum.
   * @memberof MatrixOperations
   * @method getWeightsSum
   * @static
   * @param {number[]} array
   * @returns {number}
   */

  static getWeightsSum(array) {
    let sum = 0;
    let i;
    for (i = 0; i < array.length; i += 1) {
      sum += array[i];
    }
    return sum;
  }

  /**
   * getCriterionSum.
   * @memberof MatrixOperations
   * @method getCriterionSum
   * @static
   * @param {number[][]} array
   * @param {number} j
   * @returns {number}
   */

  static getCriterionSum(array, j) {
    let sum = 0;
    let i;
    for (i = 0; i < array[0].length; i += 1) {
      sum += array[i][j];
    }
    return sum;
  }

  /**
   * getNormalizedWeigths.
   * @memberof MatrixOperations
   * @method getNormalizedWeigths
   * @static
   * @param {number[]} array
   * @returns {number[]}
   */

  static getNormalizedWeigths(array) {
    const arrayNW = [];
    const sum = this.getWeightsSum(array);
    let i;
    for (i = 0; i < array.length; i += 1) {
      arrayNW[i] = array[i] / sum;
    }
    return arrayNW;
  }

  /**
   * getColumnSum.
   * @memberof MatrixOperations
   * @method getColumnSum
   * @static
   * @param {number[][]} array
   * @returns {number[]}
   */

  static getColumnSum(array) {
    const arrayC = [];
    let i;
    let j;
    for (j = 0; j < array[0].length; j += 1) {
      for (i = 0; i < array.length; i += 1) {
        arrayC[j] += array[i][j];
      }
    }
    return arrayC;
  }

  /**
   * getRowSum.
   * @memberof MatrixOperations
   * @method getRowSum
   * @static
   * @param {number[][]} array
   * @returns {number[]}
   */

  static getRowSum(array) {
    const arrayR = [];
    let i;
    let j;
    for (i = 0; i < array.length; i += 1) {
      for (j = 0; j < array[0].length; j += 1) {
        arrayR[i] += array[i][j];
      }
    }
    return arrayR;
  }

  /**
   * getNormalizedPerformanceMatrix.
   * @memberof MatrixOperations
   * @method getNormalizedPerformanceMatrix
   * @static
   * @param {number[][]} array
   * @returns {number[][]}
   */

  static getNormalizedPerformanceMatrix(array) {
    const arrayNPM = Array(array.length).fill(Array(array[0].length));
    const a = this.getColumnSum(array);
    let i;
    let j;
    for (j = 0; j < array[0].length; j += 1) {
      for (i = 0; i < array.length; i += 1) {
        arrayNPM[i][j] = array[i][j] / a[j];
      }
    }
    return arrayNPM;
  }

  /**
   * getMaxValueInColumn.
   * @memberof MatrixOperations
   * @method getMaxValueInColumn
   * @static
   * @param {number[][]} array
   * @returns {number[]}
   */

  static getMaxValueInColumn(array) {
    const arrayMax = [];
    let i;
    let j;
    for (j = 0; j < array[0].length; j += 1) {
      let max = array[0][j];
      for (i = 0; i < array.length; i += 1) {
        if (array[i][j] >= max) {
          max = array[i][j];
          arrayMax[j] = array[i][j];
        }
      }
    }
    return arrayMax;
  }

  /**
   * getMaxValueInColumnJ.
   * @memberof MatrixOperations
   * @method getMaxValueInColumnJ
   * @static
   * @param {number[][]} array
   * @param {number} j
   * @returns {number}
   */

  static getMaxValueInColumnJ(array, j) {
    let max = -100001;
    let i;
    for (i = 0; i < array.length; i += 1) {
      if (array[i][j] >= max) {
        max = array[i][j];
      }
    }
    return max;
  }

  /**
   * getMinValueInColumn.
   * @memberof MatrixOperations
   * @method getMinValueInColumn
   * @static
   * @param {number[][]} array
   * @returns {number[]}
   */

  static getMinValueInColumn(array) {
    const arrayMin = [];
    let i;
    let j;
    for (j = 0; j < array[0].length; j += 1) {
      let min = array[0][j];
      for (i = 0; i < array.length; i += 1) {
        if (array[i][j] <= min) {
          min = array[i][j];
          arrayMin[j] = array[i][j];
        }
      }
    }
    return arrayMin;
  }

  /**
   * getMinValueInColumnJ.
   * @memberof MatrixOperations
   * @method getMinValueInColumnJ
   * @static
   * @param {number[][]} array
   * @param {number} j
   * @returns {number}
   */

  static getMinValueInColumnJ(array, j) {
    let min = 100001;
    let i;
    for (i = 0; i < array.length; i += 1) {
      if (array[i][j] <= min) {
        min = array[i][j];
      }
    }
    return min;
  }

  /**
   * getMaxValueInRowSorting.
   * @memberof MatrixOperations
   * @method getMaxValueInRowSorting
   * @static
   * @param {number[]} array
   * @returns {number}
   */

  static getMaxValueInRowSorting(array) {
    array.sort((a, b) => a - b);
    const max = array[array.length - 1];
    return max;
  }

  /**
   * getMaxValueInRowNonSorting.
   * @memberof MatrixOperations
   * @method getMaxValueInRowNonSorting
   * @static
   * @param {number[]} array
   * @returns {number}
   */

  static getMaxValueInRowNonSorting(array) {
    let max = -100001;
    let i;
    if (array.length === 1) {
      max = array[0];
    }
    for (i = 0; i < array.length; i += 1) {
      if (max < array[i]) {
        max = array[i];
      }
    }
    return max;
  }

  /**
   * getMinValueInRowNonSorting.
   * @memberof MatrixOperations
   * @method getMinValueInRowNonSorting
   * @static
   * @param {number[]} array
   * @returns {number}
   */

  static getMinValueInRowNonSorting(array) {
    let min = 100001;
    let i;
    for (i = 0; i < array.length; i += 1) {
      if (min > array[i]) {
        min = array[i];
      }
    }
    return min;
  }

  /**
   * getDelta.
   * @memberof MatrixOperations
   * @method getDelta
   * @static
   * @param {number[][]} array
   * @returns {number[]}
   */

  static getDelta(array) {
    const arrayDelta = [];
    const a = this.getMaxValueInColumn(array);
    const b = this.getMinValueInColumn(array);
    let i;
    for (i = 0; i < array[0].length; i += 1) {
      arrayDelta[i] = a[i] - b[i];
    }
    return arrayDelta;
  }

  /**
   * getElementCountZero.
   * @memberof MatrixOperations
   * @method getElementCountZero
   * @static
   * @param {number[]} array
   * @returns {number}
   */

  static getElementCountZero(array) {
    let elementcount = 0;
    let i;
    for (i = 0; i < array.length; i += 1) {
      if (array[i] === 0) {
        elementcount += 1;
      }
    }
    return elementcount;
  }

  /**
   * get2DElementCountSpecificValue.
   * @memberof MatrixOperations
   * @method get2DElementCountSpecificValue
   * @static
   * @param {number[][]} array
   * @param {number} b
   * @returns {number}
   */

  static get2DElementCountSpecificValue(array, b) {
    let elementcount = 0;
    let i;
    let j;
    for (i = 0; i < array.length; i += 1) {
      for (j = 0; j < array[0].length; j += 1) {
        if (array[i][j] === b) {
          elementcount += 1;
        }
      }
    }
    return elementcount;
  }

  /**
   * get2DElementCountSpecificValue.
   * @memberof MatrixOperations
   * @method get2DElementCountSpecificValue
   * @static
   * @param {number[][]} array
   * @returns {number[][]}
   */

  static getTransposed2DMatrix(array) {
    const arrayT2D = Array(array[0].length).fill(Array(array.length));
    let i;
    let j;
    for (i = 0; i < array.length; i += 1) {
      for (j = 0; j < array[0].length; j += 1) {
        arrayT2D[j][i] = array[i][j];
      }
    }
    return arrayT2D;
  }

  /**
   * get2DMatrixSum.
   * @memberof MatrixOperations
   * @method get2DMatrixSum
   * @static
   * @param {number[][]} array1
   * @param {number[][]} array2
   * @returns {number[][]}
   */

  static get2DMatrixSum(array1, array2) {
    const arrayS2D = Array(array1.length).fill(Array(array1[0].length));
    let i;
    let j;
    for (i = 0; i < array1.length; i += 1) {
      for (j = 0; j < array1[0].length; j += 1) {
        arrayS2D[i][j] = array1[i][j] + array2[i][j];
      }
    }
    return arrayS2D;
  }

  /**
   * get2DMatrixTotalSum.
   * @memberof MatrixOperations
   * @method get2DMatrixTotalSum
   * @static
   * @param {number[][]} array
   * @returns {number}
   */

  static get2DMatrixTotalSum(array) {
    let total = 0;
    let i;
    let j;
    for (i = 0; i < array.length; i += 1) {
      for (j = 0; j < array[0].length; j += 1) {
        total += array[i][j];
      }
    }
    return total;
  }

  /**
   * get2DDirectMatrixMult.
   * @memberof MatrixOperations
   * @method get2DDirectMatrixMult
   * @static
   * @param {number[][]} array1
   * @param {number[][]} array2
   * @returns {number[][]}
   */

  static get2DDirectMatrixMult(array1, array2) {
    const arrayM2D = Array(array1.length).fill(Array(array1.length));
    let i;
    let j;
    for (i = 0; i < array1.length; i += 1) {
      for (j = 0; j < array1[0].length; j += 1) {
        arrayM2D[i][j] = array1[i][j] * array2[i][j];
      }
    }
    return arrayM2D;
  }

  /**
   * get2DRemoveRow.
   * @memberof MatrixOperations
   * @method get2DRemoveRow
   * @static
   * @param {number[][]} array1
   * @param {number} row
   * @returns {number[][]}
   */

  static get2DRemoveRow(array1, row) {
    const arrayRD = Array(array1.length - 1).fill(Array(array1[0].length));
    let p = 0;
    let i;
    let j;
    for (i = 0; i < array1.length; i += 1) {
      if (i !== row) {
        let q = 0;
        for (j = 0; j < array1[0].length; j += 1) {
          arrayRD[p][q] = array1[i][j];
          q += 1;
        }
        p += 1;
      }
    }
    return arrayRD;
  }

  /**
   * get2DSearchString.
   * @memberof MatrixOperations
   * @method get2DSearchString
   * @static
   * @param {string} R
   * @param {string} C
   * @param {string[][]} array
   * @returns {string}
   */

  static get2DSearchString(R, C, array) {
    let value = 'Not Found!';
    let i;
    let j;
    for (i = 1; i < array.length; i += 1) {
      for (j = 1; j < array[0].length; j += 1) {
        if (array[i][0].equals(R) && array[0][j].equals(C)) {
          value = array[i][j];
          break;
        }
      }
    }
    return value;
  }

  /**
   * get2DSearchStringUpper.
   * @memberof MatrixOperations
   * @method get2DSearchStringUpper
   * @static
   * @param {string} R
   * @param {string} C
   * @param {string[][]} array
   * @returns {string}
   */

  static get2DSearchStringUpper(R, C, array) {
    let value = 'Not Found!';
    let i;
    let j;
    for (i = 1; i < array.length; i += 1) {
      for (j = i + 1; j < array[0].length; j += 1) {
        if (array[i][0].equals(R) && array[0][j].equals(C)) {
          value = array[i][j];
          break;
        }
      }
    }
    return value;
  }

  /**
   * get2DRemoveColumn.
   * @memberof MatrixOperations
   * @method get2DRemoveColumn
   * @static
   * @param {number[][]} array1
   * @param {number} column
   * @returns {number[][]}
   */

  static get2DRemoveColumn(array1, column) {
    const arrayRD = Array(array1.length).fill(Array(array1[0].length - 1));
    let p = 0;
    let i;
    let j;
    for (i = 0; i < array1.length; i += 1) {
      let q = 0;
      for (j = 0; j < array1[0].length; j += 1) {
        if (j !== column) {
          arrayRD[p][q] = array1[i][j];
          q += 1;
        }
      }
      p += 1;
    }
    return arrayRD;
  }

  /**
   * get2DRemoveColumnString.
   * @memberof MatrixOperations
   * @method get2DRemoveColumnString
   * @static
   * @param {number[][]} array1
   * @param {number} column
   * @returns {number[][]}
   */

  static get2DRemoveColumnString(array1, column) {
    const arrayRD = Array(array1.length).fill(Array(array1[0].length - 1));
    let p = 0;
    let i;
    let j;
    for (i = 0; i < array1.length; i += 1) {
      let q = 0;
      for (j = 0; j < array1[0].length; j += 1) {
        if (j !== column) {
          arrayRD[p][q] = array1[i][j];
          q += 1;
        }
      }
      p += 1;
    }
    return arrayRD;
  }

  /**
   * get2DRemoveRowString.
   * @memberof MatrixOperations
   * @method get2DRemoveRowString
   * @static
   * @param {string[][]} array1
   * @param {number} row
   * @returns {string[][]}
   */

  static get2DRemoveRowString(array1, row) {
    const arrayRD = Array(array1.length - 1).fill(Array(array1[0].length));
    let p = 0;
    let i;
    let j;
    for (i = 0; i < array1.length; i += 1) {
      if (i !== row) {
        let q = 0;
        for (j = 0; j < array1[0].length; j += 1) {
          arrayRD[p][q] = array1[i][j];
          q += 1;
        }
        p += 1;
      }
    }
    return arrayRD;
  }
}

export { MatrixOperations as default };
<|endoftext|>


<commit_before>/**
 * Created by lundfall on 01/09/16.
 */

import {limit}                      from 'arva-js/utils/Limiter.js';

import ImageSurface                 from 'famous/surfaces/ImageSurface.js';
import AnimationController          from 'famous-flex/AnimationController.js';

import {View}                       from '../../core/View.js';
import {Utils}                      from './Utils.js';

import EventEmitter                 from 'eventemitter3';

/**
 * Used by the view to keep track of sizes. Emits events to communicate with the view to do certain actions
 */
export class SizeResolver extends EventEmitter {

    constructor() {
        super();
        this._resolvedSizesCache = new Map();
        this._sizeIsFinalFor = new Map();
        this._trueSizedSurfaceInfo = new Map();
    }

    /**
     * Determines the decorated size. If there is true sizing involved, then it will not return the resolved true size.
     * Instead, this can be accessed through getResolvedSize()
     * @param {Renderable} renderable. The renderable for which we need the size
     * @param {Renderable} renderableCounterpart. The renderable counter-part (e.g. AnimationController, RenderNode, or ContainerSurface).
     * @param {Object} context. The context, with a specified size. The size can be set to NaN in order to return NaN
     * @param {Array} specifiedSize. The size to use which is specified as a decorator
     * @returns {*}
     */
    settleDecoratedSize(renderable, renderableCounterpart, context, specifiedSize = [undefined, undefined]) {
        let size = [];
        let cacheResolvedSize = [];
        for (let dimension = 0; dimension < 2; dimension++) {
            size[dimension] = this.resolveSingleSize(specifiedSize[dimension], context.size, dimension);
            if (this.isValueTrueSized(size[dimension])) {
                cacheResolvedSize[dimension] = this._resolveSingleTrueSizedRenderable(renderable, size, dimension, renderableCounterpart);
                if (Utils.renderableIsSurface(renderable)) {
                    size[dimension] = true;
                } else {
                    size[dimension] = cacheResolvedSize[dimension];
                }
            } else {
                this._sizeIsFinalFor.set(renderable, true);
                size[dimension] = size[dimension] === undefined ? (context.size[dimension] || size[dimension]) : size[dimension];
                cacheResolvedSize[dimension] = size[dimension];
            }
        }

        this._resolvedSizesCache.set(renderable, [cacheResolvedSize[0], cacheResolvedSize[1]]);

        return (size[0] !== null && size[1] !== null) ? size : null;
    }

    /**
     * Resolves a single dimension (i.e. x or y) size of a renderable.
     * @param {Number|Boolean|Object|Undefined|Function} renderableSize Renderable's single dimension size.
     * @param {Array.Number} contextSize The context size
     * @param {Number} dimension The dimension of the size that is being evaluated (e.g. 1 or 0)
     * @returns {Number} The resulting size
     * @private
     */
    resolveSingleSize(renderableSize, contextSize, dimension) {
        switch (typeof renderableSize) {
            case 'function':
                return this.resolveSingleSize(renderableSize(...contextSize), contextSize, dimension);
            case 'number':
                /* If 0 < renderableSize < 1, we interpret renderableSize as a fraction of the contextSize */
                return renderableSize < 1 && renderableSize > 0 ? renderableSize * Math.max(contextSize[dimension], 0) : renderableSize;
            default:
                /* renderableSize can be true/false, undefined, or 'auto' for example. */
                return renderableSize;
        }
    }

    /**
     * Resolves a true size to an actual size of a truesized renderable. size[dim] must be negative or true.
     * @param {Renderable} renderable the renderable
     * @param {Array} size the size as specified
     * @param dim the dimensions e.g. 0,1 that should be processed
     * @param {Renderable} renderableCounterpart. The renderable counter-part (e.g. AnimationController, RenderNode, or ContainerSurface).
     * @returns {Number} size[dim] will be returned with a non-truesized value
     * @private
     */
    _resolveSingleTrueSizedRenderable(renderable, size, dim, renderableCounterpart) {
        if (size[dim] === -1) {
            Utils.warn('-1 detected as set size. If you want a true sized element to take ' +
                'up a proportion of your view, please define a function doing so by ' +
                'using the context size');
        }
        /* If there is an AnimationController without content, display 0 size */
        if (renderableCounterpart instanceof AnimationController && !renderableCounterpart._showingRenderable) {
            return 0;
        }
        /* True sized element. This has been specified as ~100 where 100 is the initial size
         * applying this operator again (e.g. ~~100) gives us the value 100 back
         * */
        if (Utils.renderableIsComposite(renderable)) {
            let twoDimensionalSize = renderable.getSize();
            if (!twoDimensionalSize) {
                return this._specifyUndeterminedSingleHeight(renderable, size, dim);
            } else {
                let renderableIsView = renderable instanceof View;
                /* If the renderable isn't displaying, we must simply consider it final.
                TODO: There might be better ways to reason about non-displaying renderables  */
                let sizeConsideredFinal = !(renderableIsView && renderable.layout.isDisplaying()) ||
                    ((renderableIsView && (renderable._initialised && !renderable.containsUncalculatedSurfaces())) || !renderableIsView);
                if (size[dim] === true && twoDimensionalSize[dim] === undefined && sizeConsideredFinal) {
                    Utils.warn(`True sized renderable '${renderable.constructor.name}' is taking up the entire context size.`);
                    return twoDimensionalSize[dim];
                } else {
                    let approximatedSize = size[dim] === true ? twoDimensionalSize[dim] : ~size[dim];
                    let resultingSize = twoDimensionalSize[dim] !== undefined ? twoDimensionalSize[dim] : approximatedSize;
                    if (renderableIsView) {
                        resultingSize = sizeConsideredFinal ? resultingSize : approximatedSize;
                    }
                    this._sizeIsFinalFor.set(renderable, sizeConsideredFinal);
                    return resultingSize;
                }
            }
        } else if (Utils.renderableIsSurface(renderable)) {
            let trueSizedSurfaceInfo = this._trueSizedSurfaceInfo.get(renderable) || {};
            if (trueSizedSurfaceInfo.calculateOnNext) {
                trueSizedSurfaceInfo.calculateOnNext = false;
                this._tryCalculateTrueSizedSurface(renderable);
            }
            let {isUncalculated} = trueSizedSurfaceInfo;
            this._sizeIsFinalFor.set(renderable, !isUncalculated);
            if (isUncalculated === false) {
                return trueSizedSurfaceInfo.size[dim];
            } else {
                if (size[dim] === true) {
                    let defaultSize = 5;
                    Utils.warn(`No initial size set for renderable '${renderable.constructor.name}', will default to ${defaultSize}px`);
                    size[dim] = ~5;
                }
                if (isUncalculated !== true) {
                    /* Seems like the surface isn't properly configured, let's get that going */
                    trueSizedSurfaceInfo = this.configureTrueSizedSurface(renderable);
                }
                trueSizedSurfaceInfo.trueSizedDimensions[dim] = true;
                renderable.size[dim] = true;
                /* Need to set the size in order to get resize notifications */
                return ~size[dim];
            }
        } else {
            this._sizeIsFinalFor.set(renderable, true);
            return this._specifyUndeterminedSingleHeight(renderable, size, dim);
        }
    }

    /**
     * Determines whether the size is considered final or not, and may affect whether the rendering will take place or
     * not
     * @param {Renderable} renderable
     * @returns {Boolean} sizeIsFinal
     */
    isSizeFinal(renderable) {
        let consideredFinal = this._sizeIsFinalFor.get(renderable);
        /* Return true if nothing is known, to be sure not to make false negatives */
        if(consideredFinal === undefined){
            return true;
        }
        return consideredFinal;
    }
    /**
     * Determines if the value is true sized
     * @param {*} value
     * @returns {boolean} True if the value is true sized
     * @private
     */
    isValueTrueSized(value) {
        return value < 0 || value === true
    }

    _specifyUndeterminedSingleHeight(renderable, size, dim) {
        let resultingSize = size[dim] < 0 ? ~size[dim] : 5;
        Utils.warn(`Cannot determine size of ${renderable.constructor.name}, falling back to default size or ${resultingSize}px. If the renderable is using legacy declaration this.renderables = ... this isn't supported for true sizing.`);
        return resultingSize;
    }

    containsUncalculatedSurfaces() {
        for (let [surface, {isUncalculated}] of this._trueSizedSurfaceInfo) {
            if (isUncalculated) {
                return true;
            }
        }
        return false;
    }

    /**
     * Calculates a surface size, if possible
     * @param renderable
     * @private
     */
    _tryCalculateTrueSizedSurface(renderable) {
        let renderableHtmlElement = renderable._element;
        let trueSizedInfo = this._trueSizedSurfaceInfo.get(renderable);
        let {trueSizedDimensions} = trueSizedInfo;

        /* HTML treats white space as nothing at all, so we need to be sure that "  " == "" */
        let trimmedContent = (renderable.getContent() && renderable.getContent().trim) ? renderable.getContent().trim() : renderable.getContent();

        if (renderableHtmlElement && ((renderableHtmlElement.offsetWidth && renderableHtmlElement.offsetHeight) || (!trimmedContent && !(renderable instanceof ImageSurface))) && renderableHtmlElement.innerHTML === trimmedContent &&
            (!renderableHtmlElement.style.width || !trueSizedDimensions[0]) && (!renderableHtmlElement.style.height || !trueSizedDimensions[1])) {
            let newSize;

            newSize = [renderableHtmlElement.offsetWidth, renderableHtmlElement.offsetHeight];

            let oldSize = trueSizedInfo.size;
            let sizeChange = false;
            if (oldSize) {
                for (let i = 0; i < 2; i++) {
                    if (trueSizedDimensions[i] && oldSize[i] !== newSize[i]) {
                        sizeChange = true;
                    }
                }
            } else {
                sizeChange = true;
            }

            if (sizeChange) {
                trueSizedInfo.size = newSize;
                trueSizedInfo.isUncalculated = false;
            }
            this.requestRecursiveReflow();
        } else {
            this.requestReflow();
            this.requestLayoutControllerReflow();
        }
    }

    //Todo listen for these in the view
    requestRecursiveReflow() {
        this.emit('reflowRecursively');
    }

    requestReflow() {
        this.emit('reflow');
    }

    requestLayoutControllerReflow() {
        this.emit('layoutControllerReflow');
    }

    /**
     * Sets up a true sized surface
     * @param renderable
     * @returns {{isUncalculated: boolean, trueSizedDimensions: boolean[], name: *}} an entry in this._trueSizedSurfaceInfo
     * @private
     */
    configureTrueSizedSurface(renderable) {
        let trueSizedSurfaceInfo = {isUncalculated: true, trueSizedDimensions: [false, false]};

        /* We assume both dimensions not to be truesized, they are set in this._resolveDecoratedSize */
        this._trueSizedSurfaceInfo.set(renderable, trueSizedSurfaceInfo);
        /* Need to set the size in order to get resize notifications */
        renderable.size = [undefined, undefined];

        renderable.on('resize', () => {
            this._tryCalculateTrueSizedSurface(renderable);
        });
        renderable.on('deploy', () => {
            if (!this._trueSizedSurfaceInfo.get(renderable).isUncalculated) {
                this._tryCalculateTrueSizedSurface(renderable);
            }
        });

        return trueSizedSurfaceInfo;
    }

    /**
     * Gets the size used when displaying a renderable on the screen the last time the calculation was done.
     * @param {Renderable/Name} renderableOrName The renderable or the name of the renderable of which you need the size
     */
    getResolvedSize(renderable) {
        return this._resolvedSizesCache.get(renderable);
    }

    doTrueSizedBookkeeping() {
        for (let [surface] of this._trueSizedSurfaceInfo) {
            /* Encourage the surfaces to check if they have been resized, which could trigger the resize event */
            surface._trueSizeCheck = true;
        }
    }

    getSurfaceTrueSizedInfo(surface) {
        return this._trueSizedSurfaceInfo.get(surface);
    }
}<commit_msg>Fixed bug for surfaces not being calculated when the content ends with whitespace<commit_after>/**
 * Created by lundfall on 01/09/16.
 */

import {limit}                      from 'arva-js/utils/Limiter.js';

import ImageSurface                 from 'famous/surfaces/ImageSurface.js';
import AnimationController          from 'famous-flex/AnimationController.js';

import {View}                       from '../../core/View.js';
import {Utils}                      from './Utils.js';

import EventEmitter                 from 'eventemitter3';

/**
 * Used by the view to keep track of sizes. Emits events to communicate with the view to do certain actions
 */
export class SizeResolver extends EventEmitter {

    constructor() {
        super();
        this._resolvedSizesCache = new Map();
        this._sizeIsFinalFor = new Map();
        this._trueSizedSurfaceInfo = new Map();
    }

    /**
     * Determines the decorated size. If there is true sizing involved, then it will not return the resolved true size.
     * Instead, this can be accessed through getResolvedSize()
     * @param {Renderable} renderable. The renderable for which we need the size
     * @param {Renderable} renderableCounterpart. The renderable counter-part (e.g. AnimationController, RenderNode, or ContainerSurface).
     * @param {Object} context. The context, with a specified size. The size can be set to NaN in order to return NaN
     * @param {Array} specifiedSize. The size to use which is specified as a decorator
     * @returns {*}
     */
    settleDecoratedSize(renderable, renderableCounterpart, context, specifiedSize = [undefined, undefined]) {
        let size = [];
        let cacheResolvedSize = [];
        for (let dimension = 0; dimension < 2; dimension++) {
            size[dimension] = this.resolveSingleSize(specifiedSize[dimension], context.size, dimension);
            if (this.isValueTrueSized(size[dimension])) {
                cacheResolvedSize[dimension] = this._resolveSingleTrueSizedRenderable(renderable, size, dimension, renderableCounterpart);
                if (Utils.renderableIsSurface(renderable)) {
                    size[dimension] = true;
                } else {
                    size[dimension] = cacheResolvedSize[dimension];
                }
            } else {
                this._sizeIsFinalFor.set(renderable, true);
                size[dimension] = size[dimension] === undefined ? (context.size[dimension] || size[dimension]) : size[dimension];
                cacheResolvedSize[dimension] = size[dimension];
            }
        }

        this._resolvedSizesCache.set(renderable, [cacheResolvedSize[0], cacheResolvedSize[1]]);

        return (size[0] !== null && size[1] !== null) ? size : null;
    }

    /**
     * Resolves a single dimension (i.e. x or y) size of a renderable.
     * @param {Number|Boolean|Object|Undefined|Function} renderableSize Renderable's single dimension size.
     * @param {Array.Number} contextSize The context size
     * @param {Number} dimension The dimension of the size that is being evaluated (e.g. 1 or 0)
     * @returns {Number} The resulting size
     * @private
     */
    resolveSingleSize(renderableSize, contextSize, dimension) {
        switch (typeof renderableSize) {
            case 'function':
                return this.resolveSingleSize(renderableSize(...contextSize), contextSize, dimension);
            case 'number':
                /* If 0 < renderableSize < 1, we interpret renderableSize as a fraction of the contextSize */
                return renderableSize < 1 && renderableSize > 0 ? renderableSize * Math.max(contextSize[dimension], 0) : renderableSize;
            default:
                /* renderableSize can be true/false, undefined, or 'auto' for example. */
                return renderableSize;
        }
    }

    /**
     * Resolves a true size to an actual size of a truesized renderable. size[dim] must be negative or true.
     * @param {Renderable} renderable the renderable
     * @param {Array} size the size as specified
     * @param dim the dimensions e.g. 0,1 that should be processed
     * @param {Renderable} renderableCounterpart. The renderable counter-part (e.g. AnimationController, RenderNode, or ContainerSurface).
     * @returns {Number} size[dim] will be returned with a non-truesized value
     * @private
     */
    _resolveSingleTrueSizedRenderable(renderable, size, dim, renderableCounterpart) {
        if (size[dim] === -1) {
            Utils.warn('-1 detected as set size. If you want a true sized element to take ' +
                'up a proportion of your view, please define a function doing so by ' +
                'using the context size');
        }
        /* If there is an AnimationController without content, display 0 size */
        if (renderableCounterpart instanceof AnimationController && !renderableCounterpart._showingRenderable) {
            return 0;
        }
        /* True sized element. This has been specified as ~100 where 100 is the initial size
         * applying this operator again (e.g. ~~100) gives us the value 100 back
         * */
        if (Utils.renderableIsComposite(renderable)) {
            let twoDimensionalSize = renderable.getSize();
            if (!twoDimensionalSize) {
                return this._specifyUndeterminedSingleHeight(renderable, size, dim);
            } else {
                let renderableIsView = renderable instanceof View;
                /* If the renderable isn't displaying, we must simply consider it final.
                TODO: There might be better ways to reason about non-displaying renderables  */
                let sizeConsideredFinal = !(renderableIsView && renderable.layout.isDisplaying()) ||
                    ((renderableIsView && (renderable._initialised && !renderable.containsUncalculatedSurfaces())) || !renderableIsView);
                if (size[dim] === true && twoDimensionalSize[dim] === undefined && sizeConsideredFinal) {
                    Utils.warn(`True sized renderable '${renderable.constructor.name}' is taking up the entire context size.`);
                    return twoDimensionalSize[dim];
                } else {
                    let approximatedSize = size[dim] === true ? twoDimensionalSize[dim] : ~size[dim];
                    let resultingSize = twoDimensionalSize[dim] !== undefined ? twoDimensionalSize[dim] : approximatedSize;
                    if (renderableIsView) {
                        resultingSize = sizeConsideredFinal ? resultingSize : approximatedSize;
                    }
                    this._sizeIsFinalFor.set(renderable, sizeConsideredFinal);
                    return resultingSize;
                }
            }
        } else if (Utils.renderableIsSurface(renderable)) {
            let trueSizedSurfaceInfo = this._trueSizedSurfaceInfo.get(renderable) || {};
            if (trueSizedSurfaceInfo.calculateOnNext) {
                trueSizedSurfaceInfo.calculateOnNext = false;
                this._tryCalculateTrueSizedSurface(renderable);
            }
            let {isUncalculated} = trueSizedSurfaceInfo;
            this._sizeIsFinalFor.set(renderable, !isUncalculated);
            if (isUncalculated === false) {
                return trueSizedSurfaceInfo.size[dim];
            } else {
                if (size[dim] === true) {
                    let defaultSize = 5;
                    Utils.warn(`No initial size set for renderable '${renderable.constructor.name}', will default to ${defaultSize}px`);
                    size[dim] = ~5;
                }
                if (isUncalculated !== true) {
                    /* Seems like the surface isn't properly configured, let's get that going */
                    trueSizedSurfaceInfo = this.configureTrueSizedSurface(renderable);
                }
                trueSizedSurfaceInfo.trueSizedDimensions[dim] = true;
                renderable.size[dim] = true;
                /* Need to set the size in order to get resize notifications */
                return ~size[dim];
            }
        } else {
            this._sizeIsFinalFor.set(renderable, true);
            return this._specifyUndeterminedSingleHeight(renderable, size, dim);
        }
    }

    /**
     * Determines whether the size is considered final or not, and may affect whether the rendering will take place or
     * not
     * @param {Renderable} renderable
     * @returns {Boolean} sizeIsFinal
     */
    isSizeFinal(renderable) {
        let consideredFinal = this._sizeIsFinalFor.get(renderable);
        /* Return true if nothing is known, to be sure not to make false negatives */
        if(consideredFinal === undefined){
            return true;
        }
        return consideredFinal;
    }
    /**
     * Determines if the value is true sized
     * @param {*} value
     * @returns {boolean} True if the value is true sized
     * @private
     */
    isValueTrueSized(value) {
        return value < 0 || value === true
    }

    _specifyUndeterminedSingleHeight(renderable, size, dim) {
        let resultingSize = size[dim] < 0 ? ~size[dim] : 5;
        Utils.warn(`Cannot determine size of ${renderable.constructor.name}, falling back to default size or ${resultingSize}px. If the renderable is using legacy declaration this.renderables = ... this isn't supported for true sizing.`);
        return resultingSize;
    }

    containsUncalculatedSurfaces() {
        for (let [surface, {isUncalculated}] of this._trueSizedSurfaceInfo) {
            if (isUncalculated) {
                return true;
            }
        }
        return false;
    }

    /**
     * Calculates a surface size, if possible
     * @param renderable
     * @private
     */
    _tryCalculateTrueSizedSurface(renderable) {
        let renderableHtmlElement = renderable._element;
        let trueSizedInfo = this._trueSizedSurfaceInfo.get(renderable);
        let { trueSizedDimensions } = trueSizedInfo;

        /* HTML treats white space as nothing at all, so we need to be sure that "  " == "" */
        let trimmedContent = (renderable.getContent() && renderable.getContent().trim) ? renderable.getContent().trim() : renderable.getContent();
        let trimmedHtmlContent =  renderableHtmlElement.innerHTML.trim ? renderableHtmlElement.innerHTML.trim() : renderableHtmlElement.innerHTML;

        if (renderableHtmlElement && ((renderableHtmlElement.offsetWidth && renderableHtmlElement.offsetHeight) || (!trimmedContent && !(renderable instanceof ImageSurface))) && trimmedHtmlContent === trimmedContent &&
            (!renderableHtmlElement.style.width || !trueSizedDimensions[0]) && (!renderableHtmlElement.style.height || !trueSizedDimensions[1])) {
            let newSize;

            newSize = [renderableHtmlElement.offsetWidth, renderableHtmlElement.offsetHeight];

            let oldSize = trueSizedInfo.size;
            let sizeChange = false;
            if (oldSize) {
                for (let i = 0; i < 2; i++) {
                    if (trueSizedDimensions[i] && oldSize[i] !== newSize[i]) {
                        sizeChange = true;
                    }
                }
            } else {
                sizeChange = true;
            }

            if (sizeChange) {
                trueSizedInfo.size = newSize;
                trueSizedInfo.isUncalculated = false;
            }
            this.requestRecursiveReflow();
        } else {
            this.requestReflow();
            this.requestLayoutControllerReflow();
        }
    }

    //Todo listen for these in the view
    requestRecursiveReflow() {
        this.emit('reflowRecursively');
    }

    requestReflow() {
        this.emit('reflow');
    }

    requestLayoutControllerReflow() {
        this.emit('layoutControllerReflow');
    }

    /**
     * Sets up a true sized surface
     * @param renderable
     * @returns {{isUncalculated: boolean, trueSizedDimensions: boolean[], name: *}} an entry in this._trueSizedSurfaceInfo
     * @private
     */
    configureTrueSizedSurface(renderable) {
        let trueSizedSurfaceInfo = {isUncalculated: true, trueSizedDimensions: [false, false]};

        /* We assume both dimensions not to be truesized, they are set in this._resolveDecoratedSize */
        this._trueSizedSurfaceInfo.set(renderable, trueSizedSurfaceInfo);
        /* Need to set the size in order to get resize notifications */
        renderable.size = [undefined, undefined];

        renderable.on('resize', () => {
            this._tryCalculateTrueSizedSurface(renderable);
        });
        renderable.on('deploy', () => {
            if (!this._trueSizedSurfaceInfo.get(renderable).isUncalculated) {
                this._tryCalculateTrueSizedSurface(renderable);
            }
        });

        return trueSizedSurfaceInfo;
    }

    /**
     * Gets the size used when displaying a renderable on the screen the last time the calculation was done.
     * @param {Renderable/Name} renderableOrName The renderable or the name of the renderable of which you need the size
     */
    getResolvedSize(renderable) {
        return this._resolvedSizesCache.get(renderable);
    }

    doTrueSizedBookkeeping() {
        for (let [surface] of this._trueSizedSurfaceInfo) {
            /* Encourage the surfaces to check if they have been resized, which could trigger the resize event */
            surface._trueSizeCheck = true;
        }
    }

    getSurfaceTrueSizedInfo(surface) {
        return this._trueSizedSurfaceInfo.get(surface);
    }
}<|endoftext|>


<commit_before>/** Codepage conversion module
 */
var _ = require('lodash')

module.exports = {
  fromBuffer: function(buffer, encoding) {
    var decoder = from[String(encoding).toLowerCase()]
    if (!decoder)
      throw new Error("Unsupported encoding: " + encoding)

    return decoder(buffer)
  },

  fromString: function(string, encoding) {
    var encoder = to[String(encoding).toLowerCase()]
    if (!encoder)
      throw new Error("Unsupported encoding: " + encoding)

    return encoder(string)
  }
}

var from = {
  "iso-8859-1": function(buffer) {
    var result = ""
    _.each(buffer, function(byte) {
      result += String.fromCharCode(byte)
    })
    return result
  },

  "utf-16le": function(buffer) { return buffer.toString('utf16le') },

  "utf-8": function(buffer) { return buffer.toString('utf8') }
}

var to = {

}
<commit_msg>Better encoding error message and fixed wrong encoding string<commit_after>/** Codepage conversion module
 */
var _ = require('lodash')

module.exports = {
  fromBuffer: function(buffer, encoding) {
    encoding = String(encoding).toLowerCase()
    var decoder = from[encoding]
    if (!decoder)
      throw new Error("Unsupported encoding: '" + encoding + "'")

    return decoder(buffer)
  },

  fromString: function(string, encoding) {
    encoding = String(encoding).toLowerCase()
    var encoder = to[encoding]
    if (!encoder)
      throw new Error("Unsupported encoding: '" + encoding + "'")

    return encoder(string)
  }
}

var from = {
  "iso-8895-1": function(buffer) {
    var result = ""
    _.each(buffer, function(byte) {
      result += String.fromCharCode(byte)
    })
    return result
  },

  "utf-16le": function(buffer) { return buffer.toString('utf16le') },

  "utf-8": function(buffer) { return buffer.toString('utf8') }
}

var to = {

}
<|endoftext|>


<commit_before>var createMemo = info => {
  var {x, y, val} = info;

  var newDiv = document.createElement('div');
  var newTextarea = document.createElement('textarea');
  var newHoldbar = document.createElement('div');
  var newBtn = document.createElement('a');
  var newBtnText = document.createTextNode('X');

  // div
  newDiv.classList.add('pageMemo');
  newDiv.dataset['pagememoId'] = document.querySelectorAll('.pageMemo').length; // start from 0
  newDiv.style.position = 'absolute';
  newDiv.style.top = parseInt(y) + 'px';
  newDiv.style.zIndex = 9999;
  newDiv.style.left = parseInt(x) + 'px';

  newTextarea.addEventListener('focus', () => {
    newDiv.style.opacity = '1';
  });
  newTextarea.addEventListener('focusout', () => {
    newDiv.style.opacity = '0.2';
  });

  // textarea
  newTextarea.rows = "7";
  if (val) newTextarea.value = val;
  var memoStyles = {
    'background': 'lightyellow',
    'color':      '#555',
    'outline':    'none',
    'border':     '1px solid #999',
    'padding':    '2em 1em 1em',
    'boxShadow':  '1px 1px 5px rgba(0,0,0,0.2)'
  };
  for( var style in memoStyles) {
    newTextarea.style[style] = memoStyles[style];
  }
  var sendData = () => {
    browser.runtime.sendMessage({
      behavior: 'save_memo',
      url: location.href,
      memo_id: newTextarea.parentNode.dataset['pagememoId'],
      val: newTextarea.value,
      position: {
        x: newDiv.style.left,
        y: newDiv.style.top,
        width: newDiv.style.width
      }
    });
  };

  var ta_counter = 0;
  newTextarea.addEventListener('focusout', sendData);
  newTextarea.addEventListener('keypress', function(){
    ta_counter += 1;
    if (ta_counter % 10 != 0) return;
    sendData();
  });

  // holdbar
  var moving = false;
  var toggleMoving = () => {
    moving = !moving;
    if (moving) {
      newDiv.style.opacity = '1';
      newHoldbar.style.cursor = 'grabbing';
      newTextarea.style.cursor = 'grabbing';

      $width = newDiv.offsetWidth / 2;

      document.addEventListener('mousemove', e => {
        if (moving) {
          var x = e.clientX - $width;
          var y = e.clientY - document.querySelector('body').getBoundingClientRect().y;

          newDiv.style.left = x+'px';
          newDiv.style.top = y+'px';
          newDiv.style.right = undefined;
        };
      });
    }
    else {
      newHoldbar.style.cursor = 'grab';
      newTextarea.style.cursor = 'auto';
      sendData();
    }
  }

  newHoldbar.addEventListener('click', toggleMoving);
  newHoldbar.addEventListener('mouseover', () => {
    var hintSpan = document.createElement('SPAN');
    var newBtnText = document.createTextNode(browser.i18n.getMessage("moveHint"));
    hintSpan.appendChild(newBtnText);
    hintSpan.style.color = 'rgba(0,0,0,0.3)';
    newHoldbar.appendChild(hintSpan);
  });
  newHoldbar.addEventListener('mouseout', () => {
    newHoldbar.textContent = '';
  });

  var holdbarStyles = {
    'cursor': 'grab',
    'position': 'absolute',
    'top': '0',
    'left': '0',
    'width': '100%',
    'height': '18px',
    'textAlign': 'center',
    'background': 'transparent linear-gradient(rgba(0, 0, 0, 0.1), transparent) repeat scroll 0% 0%'
  };
  for( var style in holdbarStyles) {
    newHoldbar.style[style] = holdbarStyles[style];
  }

  // btn
  newBtn.addEventListener('click', () => {
    newBtn.parentNode.remove();
    browser.runtime.sendMessage({
      behavior: 'del_memo',
      url: location.href,
      memo_id: newBtn.parentNode.dataset['pagememoId']
    });
  });
  var btnStyles = {
    'color': '#343434',
    'cursor': 'pointer',
    'float': 'right',
    'right': '0',
    'position': 'absolute',
    'padding': '3px 5px',
    'textDecoration': 'none'
  };
  for( var style in btnStyles) {
    newBtn.style[style] = btnStyles[style];
  }
  newBtn.addEventListener('mouseover', () => {
    newBtn.style.color = '#aaa';
  });
  newBtn.addEventListener('mouseout', () => {
    newBtn.style.color = '#343434';
  });

  newBtn.appendChild(newBtnText);
  newDiv.appendChild(newHoldbar);
  newDiv.appendChild(newBtn);
  newDiv.appendChild(newTextarea);
  document.body.appendChild(newDiv);

  newTextarea.focus();
};

document.addEventListener('contextmenu', e => {
  browser.runtime.sendMessage({
    behavior: 'record_mouse_position',
    x: e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft,
    pageWidth: document.body.clientWidth
  }).then( res => {
    createMemo({
      x: res.x,
      y: e.clientY + document.body.scrollTop + document.documentElement.scrollTop
    });
  });
});

browser.runtime.sendMessage({
  behavior: 'init',
  url: location.href
}).then( memos => {
  if (memos) {
    for (var key in memos) {
      var memo = memos[key];
      createMemo({
        x: memo.position.x,
        y: memo.position.y,
        val: memo.val
      });
    }
  }
});

browser.runtime.onMessage.addListener( (msg, sender, sendRes) => {
  var all_notes = Array.from(document.querySelectorAll('.pageMemo'));
  all_notes.forEach( note => {
    if (msg.behavior == 'show-all') {
      note.style.display = 'block';
    }
    else if (msg.behavior == 'hide-all') {
      note.style.display = 'none';
    }
  });
});
<commit_msg>make memo id unique<commit_after>var createMemo = info => {
  var {x, y, val} = info;

  var newDiv = document.createElement('div');
  var newTextarea = document.createElement('textarea');
  var newHoldbar = document.createElement('div');
  var newBtn = document.createElement('a');
  var newBtnText = document.createTextNode('X');

  // div
  newDiv.classList.add('pageMemo');
  newDiv.dataset['pagememoId'] = key || window.crypto.getRandomValues(new Uint16Array(1)); // start from 0
  newDiv.style.position = 'absolute';
  newDiv.style.top = parseInt(y) + 'px';
  newDiv.style.zIndex = 9999;
  newDiv.style.left = parseInt(x) + 'px';

  newTextarea.addEventListener('focus', () => {
    newDiv.style.opacity = '1';
  });
  newTextarea.addEventListener('focusout', () => {
    newDiv.style.opacity = '0.2';
  });

  // textarea
  newTextarea.rows = "7";
  if (val) newTextarea.value = val;
  var memoStyles = {
    'background': 'lightyellow',
    'color':      '#555',
    'outline':    'none',
    'border':     '1px solid #999',
    'padding':    '2em 1em 1em',
    'boxShadow':  '1px 1px 5px rgba(0,0,0,0.2)'
  };
  for( var style in memoStyles) {
    newTextarea.style[style] = memoStyles[style];
  }
  var sendData = () => {
    browser.runtime.sendMessage({
      behavior: 'save_memo',
      url: location.href,
      memo_id: newTextarea.parentNode.dataset['pagememoId'],
      val: newTextarea.value,
      position: {
        x: newDiv.style.left,
        y: newDiv.style.top,
        width: newDiv.style.width
      }
    });
  };

  var ta_counter = 0;
  newTextarea.addEventListener('focusout', sendData);
  newTextarea.addEventListener('keypress', function(){
    ta_counter += 1;
    if (ta_counter % 10 != 0) return;
    sendData();
  });

  // holdbar
  var moving = false;
  var toggleMoving = () => {
    moving = !moving;
    if (moving) {
      newDiv.style.opacity = '1';
      newHoldbar.style.cursor = 'grabbing';
      newTextarea.style.cursor = 'grabbing';

      $width = newDiv.offsetWidth / 2;

      document.addEventListener('mousemove', e => {
        if (moving) {
          var x = e.clientX - $width;
          var y = e.clientY - document.querySelector('body').getBoundingClientRect().y;

          newDiv.style.left = x+'px';
          newDiv.style.top = y+'px';
          newDiv.style.right = undefined;
        };
      });
    }
    else {
      newHoldbar.style.cursor = 'grab';
      newTextarea.style.cursor = 'auto';
      sendData();
    }
  }

  newHoldbar.addEventListener('click', toggleMoving);
  newHoldbar.addEventListener('mouseover', () => {
    var hintSpan = document.createElement('SPAN');
    var newBtnText = document.createTextNode(browser.i18n.getMessage("moveHint"));
    hintSpan.appendChild(newBtnText);
    hintSpan.style.color = 'rgba(0,0,0,0.3)';
    newHoldbar.appendChild(hintSpan);
  });
  newHoldbar.addEventListener('mouseout', () => {
    newHoldbar.textContent = '';
  });

  var holdbarStyles = {
    'cursor': 'grab',
    'position': 'absolute',
    'top': '0',
    'left': '0',
    'width': '100%',
    'height': '18px',
    'textAlign': 'center',
    'background': 'transparent linear-gradient(rgba(0, 0, 0, 0.1), transparent) repeat scroll 0% 0%'
  };
  for( var style in holdbarStyles) {
    newHoldbar.style[style] = holdbarStyles[style];
  }

  // btn
  newBtn.addEventListener('click', () => {
    newBtn.parentNode.remove();
    browser.runtime.sendMessage({
      behavior: 'del_memo',
      url: location.href,
      memo_id: newBtn.parentNode.dataset['pagememoId']
    });
  });
  var btnStyles = {
    'color': '#343434',
    'cursor': 'pointer',
    'float': 'right',
    'right': '0',
    'position': 'absolute',
    'padding': '3px 5px',
    'textDecoration': 'none'
  };
  for( var style in btnStyles) {
    newBtn.style[style] = btnStyles[style];
  }
  newBtn.addEventListener('mouseover', () => {
    newBtn.style.color = '#aaa';
  });
  newBtn.addEventListener('mouseout', () => {
    newBtn.style.color = '#343434';
  });

  newBtn.appendChild(newBtnText);
  newDiv.appendChild(newHoldbar);
  newDiv.appendChild(newBtn);
  newDiv.appendChild(newTextarea);
  document.body.appendChild(newDiv);

  newTextarea.focus();
};

document.addEventListener('contextmenu', e => {
  browser.runtime.sendMessage({
    behavior: 'record_mouse_position',
    x: e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft,
    pageWidth: document.body.clientWidth
  }).then( res => {
    createMemo({
      x: res.x,
      y: e.clientY + document.body.scrollTop + document.documentElement.scrollTop
    });
  });
});

browser.runtime.sendMessage({
  behavior: 'init',
  url: location.href
}).then( memos => {
  if (memos) {
    for (var key in memos) {
      var memo = memos[key];
      createMemo({
        x: memo.position.x,
        y: memo.position.y,
        val: memo.val,
        key: key
      });
    }
  }
});

browser.runtime.onMessage.addListener( (msg, sender, sendRes) => {
  var all_notes = Array.from(document.querySelectorAll('.pageMemo'));
  all_notes.forEach( note => {
    if (msg.behavior == 'show-all') {
      note.style.display = 'block';
    }
    else if (msg.behavior == 'hide-all') {
      note.style.display = 'none';
    }
  });
});
<|endoftext|>


<commit_before>'use strict';

/**
 * Load Test a URL, website or websocket.
 * (C) 2013 Alex Fernández.
 */

// requires
require('prototypes');
var Log = require('log');
var http = require('http');
var https = require('https');
var testing = require('testing');
var httpClient = require('./httpClient.js');
var websocket = require('./websocket.js');
var timing = require('./timing.js');

// globals
var log = new Log('info');

// constants
var SHOW_INTERVAL_MS = 5000;

// init
http.globalAgent.maxSockets = 1000;
https.globalAgent.maxSockets = 1000;

/**
 * Run a load test.
 * Options is an object which may have:
 *	- url: mandatory URL to access.
 *	- concurrency: how many concurrent clients to use.
 *	- maxRequests: how many requests to send
 *	- maxSeconds: how long to run the tests.
 *	- cookies: a string or an array of strings, each with name:value.
 *	- headers: a map with headers: {key1: value1, key2: value2}.
 *	- method: the method to use: POST, PUT. Default: GET, what else.
 *	- body: the contents to send along a POST or PUT request.
 *	- contentType: the MIME type to use for the body, default text/plain.
 *	- requestsPerSecond: how many requests per second to send.
 *	- agentKeepAlive: if true, then use connection keep-alive.
 *	- debug: show debug messages.
 *	- quiet: do not log any messages.
 *	- indexParam: string to replace with a unique index.
 *	- insecure: allow https using self-signed certs.
 * An optional callback will be called if/when the test finishes.
 */
exports.loadTest = function(options, callback)
{
	var constructor;
	if (!options.url)
	{
		log.error('Missing URL in options');
		return;
	}
	options.concurrency = options.concurrency || 1;
	if (options.requestsPerSecond)
	{
		options.requestsPerSecond = options.requestsPerSecond / options.concurrency;
	}
	if (options.debug)
	{
		log.level = Log.DEBUG;
	}
	if (!options.url.startsWith('http://') && !options.url.startsWith('https://') && !options.url.startsWith('ws://'))
	{
		log.error('Invalid URL %s, must be http://, https:// or ws://', options.url);
		return;
	}
	if (callback && !('quiet' in options))
	{
		options.quiet = true;
	}

	if (options.url.startsWith('ws:'))
	{
		if (options.requestsPerSecond)
		{
			log.error('"requestsPerSecond" not supported for WebSockets');
		}
	}

	var operation = new Operation(options, constructor, callback);
	operation.start();
	return operation;
};

/**
 * Used to keep track of individual load test Operation runs.
 *
 * @type {number}
 */
var operationInstanceIndex = 0;

/**
 * A load test operation.
 */
var Operation = function(options, Constructor, callback)
{
	// self-reference
	var self = this;

	// attributes
	self.running = true;
	self.latency = null;
	var clients = {};
	var requests = 0;
	var showTimer;
	var stopTimeout;

	self.instanceIndex = operationInstanceIndex++;

	/**
	 * Start the operation.
	 */
	self.start = function()
	{
		self.latency = new timing.Latency(options);
		startClients();
		if (options.maxSeconds)
		{
			stopTimeout = setTimeout(self.stop, options.maxSeconds * 1000);
		}
		showTimer = new timing.HighResolutionTimer(SHOW_INTERVAL_MS, self.latency.showPartial);
	};

	/**
	 * Call after each operation has finished.
	 */
	self.callback = function(error, result, next)
	{
		requests += 1;
		if (options.maxRequests)
		{
			if (requests == options.maxRequests)
			{
				self.stop();
			}
			if (requests > options.maxRequests)
			{
				log.debug('Should have no more running clients');
			}
		}

		if (self.running && next)
		{
			next();
		}

		if (options.statusCallback) {
			options.statusCallback(self.latency.getResults(), result, error);
		}
	};

	/**
	 * Start a number of measuring clients.
	 */
	function startClients()
	{
		var url = options.url;
		for (var index = 0; index < options.concurrency; index++)
		{
			if (options.indexParam)
			{
				options.url = url.replaceAll(options.indexParam, index);
			}
			var constructor = httpClient.create;
			if (options.url.startsWith('ws:'))// TODO: || options.url.startsWith('wss:'))
			{
				constructor = websocket.create;
			}
			var client = constructor(self, options);
			clients[index] = client;
			if (!options.requestsPerSecond)
			{
				client.start();
			}
			else
			{
				// start each client at a random moment in one second
				var offset = Math.floor(Math.random() * 1000);
				setTimeout(client.start, offset);
			}
		}
	}

	/**
	 * Stop clients.
	 */
	self.stop = function()
	{
		if (showTimer)
		{
			showTimer.stop();
		}
		if (stopTimeout)
		{
			clearTimeout(stopTimeout);
		}
		self.running = false;

		Object.keys(clients).forEach(function(index) {
			clients[index].stop();
		});
		if (callback)
		{
			var result = self.latency.getResults();
			result.instanceIndex = this.instanceIndex;
			callback(null, result);
		}
		else
		{
			self.latency.show();
		}
	};
};

/**
 * A load test with max seconds.
 */
function testMaxSeconds(callback)
{
	var options = {
		url: 'http://localhost:7357/',
		maxSeconds: 0.1,
		concurrency: 1,
		quiet: true,
	};
	exports.loadTest(options, callback);
}

/**
 * A load test with max seconds.
 */
function testWSEcho(callback)
{
	var options = {
		url: 'ws://localhost:7357/',
		maxSeconds: 0.1,
		concurrency: 1,
		quiet: true,
	};
	exports.loadTest(options, callback);
}

/**
 * Run all tests.
 */
exports.test = function(callback)
{
	testing.run([testMaxSeconds, testWSEcho], callback);
};

// run tests if invoked directly
if (__filename == process.argv[1])
{
	exports.test(testing.show);
}

<commit_msg>Remove unused parameter.<commit_after>'use strict';

/**
 * Load Test a URL, website or websocket.
 * (C) 2013 Alex Fernández.
 */

// requires
require('prototypes');
var Log = require('log');
var http = require('http');
var https = require('https');
var testing = require('testing');
var httpClient = require('./httpClient.js');
var websocket = require('./websocket.js');
var timing = require('./timing.js');

// globals
var log = new Log('info');

// constants
var SHOW_INTERVAL_MS = 5000;

// init
http.globalAgent.maxSockets = 1000;
https.globalAgent.maxSockets = 1000;

/**
 * Run a load test.
 * Options is an object which may have:
 *	- url: mandatory URL to access.
 *	- concurrency: how many concurrent clients to use.
 *	- maxRequests: how many requests to send
 *	- maxSeconds: how long to run the tests.
 *	- cookies: a string or an array of strings, each with name:value.
 *	- headers: a map with headers: {key1: value1, key2: value2}.
 *	- method: the method to use: POST, PUT. Default: GET, what else.
 *	- body: the contents to send along a POST or PUT request.
 *	- contentType: the MIME type to use for the body, default text/plain.
 *	- requestsPerSecond: how many requests per second to send.
 *	- agentKeepAlive: if true, then use connection keep-alive.
 *	- debug: show debug messages.
 *	- quiet: do not log any messages.
 *	- indexParam: string to replace with a unique index.
 *	- insecure: allow https using self-signed certs.
 * An optional callback will be called if/when the test finishes.
 */
exports.loadTest = function(options, callback)
{
	if (!options.url)
	{
		log.error('Missing URL in options');
		return;
	}
	options.concurrency = options.concurrency || 1;
	if (options.requestsPerSecond)
	{
		options.requestsPerSecond = options.requestsPerSecond / options.concurrency;
	}
	if (options.debug)
	{
		log.level = Log.DEBUG;
	}
	if (!options.url.startsWith('http://') && !options.url.startsWith('https://') && !options.url.startsWith('ws://'))
	{
		log.error('Invalid URL %s, must be http://, https:// or ws://', options.url);
		return;
	}
	if (callback && !('quiet' in options))
	{
		options.quiet = true;
	}

	if (options.url.startsWith('ws:'))
	{
		if (options.requestsPerSecond)
		{
			log.error('"requestsPerSecond" not supported for WebSockets');
		}
	}

	var operation = new Operation(options, callback);
	operation.start();
	return operation;
};

/**
 * Used to keep track of individual load test Operation runs.
 *
 * @type {number}
 */
var operationInstanceIndex = 0;

/**
 * A load test operation.
 */
var Operation = function(options, callback)
{
	// self-reference
	var self = this;

	// attributes
	self.running = true;
	self.latency = null;
	var clients = {};
	var requests = 0;
	var showTimer;
	var stopTimeout;

	self.instanceIndex = operationInstanceIndex++;

	/**
	 * Start the operation.
	 */
	self.start = function()
	{
		self.latency = new timing.Latency(options);
		startClients();
		if (options.maxSeconds)
		{
			stopTimeout = setTimeout(self.stop, options.maxSeconds * 1000);
		}
		showTimer = new timing.HighResolutionTimer(SHOW_INTERVAL_MS, self.latency.showPartial);
	};

	/**
	 * Call after each operation has finished.
	 */
	self.callback = function(error, result, next)
	{
		requests += 1;
		if (options.maxRequests)
		{
			if (requests == options.maxRequests)
			{
				self.stop();
			}
			if (requests > options.maxRequests)
			{
				log.debug('Should have no more running clients');
			}
		}

		if (self.running && next)
		{
			next();
		}

		if (options.statusCallback) {
			options.statusCallback(self.latency.getResults(), result, error);
		}
	};

	/**
	 * Start a number of measuring clients.
	 */
	function startClients()
	{
		var url = options.url;
		for (var index = 0; index < options.concurrency; index++)
		{
			if (options.indexParam)
			{
				options.url = url.replaceAll(options.indexParam, index);
			}
			var constructor = httpClient.create;
			if (options.url.startsWith('ws:'))// TODO: || options.url.startsWith('wss:'))
			{
				constructor = websocket.create;
			}
			var client = constructor(self, options);
			clients[index] = client;
			if (!options.requestsPerSecond)
			{
				client.start();
			}
			else
			{
				// start each client at a random moment in one second
				var offset = Math.floor(Math.random() * 1000);
				setTimeout(client.start, offset);
			}
		}
	}

	/**
	 * Stop clients.
	 */
	self.stop = function()
	{
		if (showTimer)
		{
			showTimer.stop();
		}
		if (stopTimeout)
		{
			clearTimeout(stopTimeout);
		}
		self.running = false;

		Object.keys(clients).forEach(function(index) {
			clients[index].stop();
		});
		if (callback)
		{
			var result = self.latency.getResults();
			result.instanceIndex = this.instanceIndex;
			callback(null, result);
		}
		else
		{
			self.latency.show();
		}
	};
};

/**
 * A load test with max seconds.
 */
function testMaxSeconds(callback)
{
	var options = {
		url: 'http://localhost:7357/',
		maxSeconds: 0.1,
		concurrency: 1,
		quiet: true,
	};
	exports.loadTest(options, callback);
}

/**
 * A load test with max seconds.
 */
function testWSEcho(callback)
{
	var options = {
		url: 'ws://localhost:7357/',
		maxSeconds: 0.1,
		concurrency: 1,
		quiet: true,
	};
	exports.loadTest(options, callback);
}

/**
 * Run all tests.
 */
exports.test = function(callback)
{
	testing.run([testMaxSeconds, testWSEcho], callback);
};

// run tests if invoked directly
if (__filename == process.argv[1])
{
	exports.test(testing.show);
}

<|endoftext|>


<commit_before>/*
 * loglevel - https://github.com/pimterry/loglevel
 *
 * Copyright (c) 2013 Tim Perry
 * Licensed under the MIT license.
 */

;(function (undefined) {
    var undefinedType = "undefined";

    (function (name, definition) {
        if (typeof module !== 'undefined') {
            module.exports = definition();
        } else if (typeof define === 'function' && typeof define.amd === 'object') {
            define(definition);
        } else {
            this[name] = definition();
        }
    }('log', function () {
        var self = {};
        var noop = function() {};

        function realMethod(methodName) {
            if (typeof console === undefinedType) {
                return noop;
            } else if (console[methodName] === undefined) {
                if (console.log !== undefined) {
                    return boundToConsole(console, 'log');
                } else {
                    return noop;
                }
            } else {
                return boundToConsole(console, methodName);
            }
        }

        function boundToConsole(console, methodName) {
            var method = console[methodName];
            if (method.bind === undefined) {
                if (Function.prototype.bind === undefined) {
                    return functionBindingWrapper(method, console);
                } else {
                    try {
                        return Function.prototype.bind.call(console[methodName], console);
                    } catch (e) {
                        // In IE8 + Modernizr, the bind shim will reject the above, so we fall back to wrapping
                        return functionBindingWrapper(method, console);
                    }
                }
            } else {
                return console[methodName].bind(console);
            }
        }

        function functionBindingWrapper(f, context) {
            return function() {
                Function.prototype.apply.apply(f, [context, arguments]);
            };
        }

        var logMethods = [
            "trace",
            "debug",
            "info",
            "warn",
            "error"
        ];

        function replaceLoggingMethods(methodFactory) {
            for (var ii = 0; ii < logMethods.length; ii++) {
                self[logMethods[ii]] = methodFactory(logMethods[ii]);
            }
        }

        function cookiesAvailable() {
            return (typeof window !== undefinedType &&
                    window.document !== undefined &&
                    window.document.cookie !== undefined);
        }

        function localStorageAvailable() {
            try {
                return (typeof window !== undefinedType &&
                        window.localStorage !== undefined);
            } catch (e) {
                return false;
            }
        }

        function persistLevelIfPossible(levelNum) {
            var localStorageFail = false,
                levelName;

            for (var key in self.levels) {
                if (self.levels.hasOwnProperty(key) && self.levels[key] === levelNum) {
                    levelName = key;
                    break;
                }
            }

            if (localStorageAvailable()) {
                /*
                 * Setting localStorage can create a DOM 22 Exception if running in Private mode
                 * in Safari, so even if it is available we need to catch any errors when trying
                 * to write to it
                 */
                try {
                    window.localStorage['loglevel'] = levelName;
                } catch (e) {
                    localStorageFail = true;
                }
            } else {
                localStorageFail = true;
            }

            if (localStorageFail && cookiesAvailable()) {
                window.document.cookie = "loglevel=" + levelName + ";";
            }
        }

        var cookieRegex = /loglevel=([^;]+)/;

        function loadPersistedLevel() {
            var storedLevel;

            if (localStorageAvailable()) {
                storedLevel = window.localStorage['loglevel'];
            }

            if (storedLevel === undefined && cookiesAvailable()) {
                var cookieMatch = cookieRegex.exec(window.document.cookie) || [];
                storedLevel = cookieMatch[1];
            }

            if (self.levels[storedLevel] === undefined) {
                storedLevel = "WARN";
            }

            self.setLevel(self.levels[storedLevel]);
        }

        /*
         *
         * Public API
         *
         */

        self.levels = { "TRACE": 0, "DEBUG": 1, "INFO": 2, "WARN": 3,
            "ERROR": 4, "SILENT": 5};

        self.setLevel = function (level) {
            if (typeof level === "number" && level >= 0 && level <= self.levels.SILENT) {
                persistLevelIfPossible(level);

                if (level === self.levels.SILENT) {
                    replaceLoggingMethods(function () {
                        return noop;
                    });
                    return;
                } else if (typeof console === undefinedType) {
                    replaceLoggingMethods(function (methodName) {
                        return function () {
                            if (typeof console !== undefinedType) {
                                self.setLevel(level);
                                self[methodName].apply(self, arguments);
                            }
                        };
                    });
                    return "No console available for logging";
                } else {
                    replaceLoggingMethods(function (methodName) {
                        if (level <= self.levels[methodName.toUpperCase()]) {
                            return realMethod(methodName);
                        } else {
                            return noop;
                        }
                    });
                }
            } else if (typeof level === "string" && self.levels[level.toUpperCase()] !== undefined) {
                self.setLevel(self.levels[level.toUpperCase()]);
            } else {
                throw "log.setLevel() called with invalid level: " + level;
            }
        };

        self.enableAll = function() {
            self.setLevel(self.levels.TRACE);
        };

        self.disableAll = function() {
            self.setLevel(self.levels.SILENT);
        };

        loadPersistedLevel();
        return self;
    }));
})();
<commit_msg>Fixed a bug where if localstorage exists but is disabled in the browser which causes window.localstorage to be null it throws an error.<commit_after>/*
 * loglevel - https://github.com/pimterry/loglevel
 *
 * Copyright (c) 2013 Tim Perry
 * Licensed under the MIT license.
 */

;(function (undefined) {
    var undefinedType = "undefined";

    (function (name, definition) {
        if (typeof module !== 'undefined') {
            module.exports = definition();
        } else if (typeof define === 'function' && typeof define.amd === 'object') {
            define(definition);
        } else {
            this[name] = definition();
        }
    }('log', function () {
        var self = {};
        var noop = function() {};

        function realMethod(methodName) {
            if (typeof console === undefinedType) {
                return noop;
            } else if (console[methodName] === undefined) {
                if (console.log !== undefined) {
                    return boundToConsole(console, 'log');
                } else {
                    return noop;
                }
            } else {
                return boundToConsole(console, methodName);
            }
        }

        function boundToConsole(console, methodName) {
            var method = console[methodName];
            if (method.bind === undefined) {
                if (Function.prototype.bind === undefined) {
                    return functionBindingWrapper(method, console);
                } else {
                    try {
                        return Function.prototype.bind.call(console[methodName], console);
                    } catch (e) {
                        // In IE8 + Modernizr, the bind shim will reject the above, so we fall back to wrapping
                        return functionBindingWrapper(method, console);
                    }
                }
            } else {
                return console[methodName].bind(console);
            }
        }

        function functionBindingWrapper(f, context) {
            return function() {
                Function.prototype.apply.apply(f, [context, arguments]);
            };
        }

        var logMethods = [
            "trace",
            "debug",
            "info",
            "warn",
            "error"
        ];

        function replaceLoggingMethods(methodFactory) {
            for (var ii = 0; ii < logMethods.length; ii++) {
                self[logMethods[ii]] = methodFactory(logMethods[ii]);
            }
        }

        function cookiesAvailable() {
            return (typeof window !== undefinedType &&
                    window.document !== undefined &&
                    window.document.cookie !== undefined);
        }

        function localStorageAvailable() {
            try {
                return (typeof window !== undefinedType &&
                        window.localStorage !== undefined &&
                        window.localStorage !== null);
            } catch (e) {
                return false;
            }
        }

        function persistLevelIfPossible(levelNum) {
            var localStorageFail = false,
                levelName;

            for (var key in self.levels) {
                if (self.levels.hasOwnProperty(key) && self.levels[key] === levelNum) {
                    levelName = key;
                    break;
                }
            }

            if (localStorageAvailable()) {
                /*
                 * Setting localStorage can create a DOM 22 Exception if running in Private mode
                 * in Safari, so even if it is available we need to catch any errors when trying
                 * to write to it
                 */
                try {
                    window.localStorage['loglevel'] = levelName;
                } catch (e) {
                    localStorageFail = true;
                }
            } else {
                localStorageFail = true;
            }

            if (localStorageFail && cookiesAvailable()) {
                window.document.cookie = "loglevel=" + levelName + ";";
            }
        }

        var cookieRegex = /loglevel=([^;]+)/;

        function loadPersistedLevel() {
            var storedLevel;

            if (localStorageAvailable()) {
                storedLevel = window.localStorage['loglevel'];
            }

            if (storedLevel === undefined && cookiesAvailable()) {
                var cookieMatch = cookieRegex.exec(window.document.cookie) || [];
                storedLevel = cookieMatch[1];
            }

            if (self.levels[storedLevel] === undefined) {
                storedLevel = "WARN";
            }

            self.setLevel(self.levels[storedLevel]);
        }

        /*
         *
         * Public API
         *
         */

        self.levels = { "TRACE": 0, "DEBUG": 1, "INFO": 2, "WARN": 3,
            "ERROR": 4, "SILENT": 5};

        self.setLevel = function (level) {
            if (typeof level === "number" && level >= 0 && level <= self.levels.SILENT) {
                persistLevelIfPossible(level);

                if (level === self.levels.SILENT) {
                    replaceLoggingMethods(function () {
                        return noop;
                    });
                    return;
                } else if (typeof console === undefinedType) {
                    replaceLoggingMethods(function (methodName) {
                        return function () {
                            if (typeof console !== undefinedType) {
                                self.setLevel(level);
                                self[methodName].apply(self, arguments);
                            }
                        };
                    });
                    return "No console available for logging";
                } else {
                    replaceLoggingMethods(function (methodName) {
                        if (level <= self.levels[methodName.toUpperCase()]) {
                            return realMethod(methodName);
                        } else {
                            return noop;
                        }
                    });
                }
            } else if (typeof level === "string" && self.levels[level.toUpperCase()] !== undefined) {
                self.setLevel(self.levels[level.toUpperCase()]);
            } else {
                throw "log.setLevel() called with invalid level: " + level;
            }
        };

        self.enableAll = function() {
            self.setLevel(self.levels.TRACE);
        };

        self.disableAll = function() {
            self.setLevel(self.levels.SILENT);
        };

        loadPersistedLevel();
        return self;
    }));
})();
<|endoftext|>


<commit_before>// import os from 'os';
// export default ((os.platform() === 'win32') ?
//     require('./freemarker') :
//     require('./fastftl')).default;
export default require('./fastftl').default;<commit_msg>Release v0.8.0-beta.2<commit_after>import os from 'os';
export default ((os.platform() === 'win32') ?
    require('./freemarker') :
    require('./fastftl')).default;
// export default require('./fastftl').default;<|endoftext|>


<commit_before>/*
 * Licensed to Paul Querna under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Paul Querna licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var graylog = require('./graylog');

function LoggerProxy(modulename) {
  this.modulename =  modulename;
  this.loglevel = -1;
}

/* Based on the Log levels available in Apache HTTP Server. */
exports.EMERG = 0;    /* system is unusable */
exports.ALERT = 1;    /* action must be taken immediately */
exports.CRIT = 2;     /* critical conditions */
exports.ERR = 3;      /* error conditions */
exports.WARNING = 4;  /* warning conditions */
exports.NOTICE = 5;   /* normal but significant condition */
exports.INFO = 6;     /* informational */
exports.DEBUG = 7;    /* debug-level messages */
exports.TRACE1 = 8;   /* trace-level 1 messages */
exports.TRACE2 = 9;   /* trace-level 2 messages */
exports.TRACE3 = 10;  /* trace-level 3 messages */
exports.TRACE4 = 11;  /* trace-level 4 messages */
exports.TRACE5 = 12;  /* trace-level 5 messages */
exports.TRACE6 = 13;  /* trace-level 6 messages */
exports.TRACE7 = 14;  /* trace-level 7 messages */
exports.TRACE8 = 15;  /* trace-level 8 messages */

var log_levels = ["EMERG",
                  "ALERT",
                  "CRIT",
                  "ERR",
                  "WARNING",
                  "NOTICE",
                  "INFO",
                  "DEBUG",
                  "TRACE1",
                  "TRACE2",
                  "TRACE3",
                  "TRACE4",
                  "TRACE5",
                  "TRACE6",
                  "TRACE7",
                  "TRACE8"];

var log_aliases = {"WARN": "WARNING",
                   "ERROR": "ERR",
                   "DBG": "DEBUG",
                   "MSG": "INFO",
                   "TRACE": "TRACE1"};

var known_sinks = {};
var known_loggers = [];
var known_routes = [];
var rewriters = [];

function applyRewrites(modulename, level, msg, extra) {
  var i;
  for (i = 0; i < rewriters.length; i++) {
    extra = rewriters[i](modulename, level, msg, extra);
  }
  return extra;
}

function buildLogMethod(modulename, level, callback) {
  if (level >= exports.TRACE1) {
    return function (msg, extra) {
      if (!extra) {
        extra = {};
      }
      extra['full_message'] = new Error('Backtrace').stack;
      extra = applyRewrites(modulename, level, msg, extra);
      callback(modulename, level, msg, extra)
    }
  }
  else {
    return function (msg, extra) {
      if (!extra) {
        extra = {};
      }
      extra = applyRewrites(modulename, level, msg, extra);
      callback(modulename, level, msg, extra)
    }
  }
}

function applyFormatString(msg, extra) {
  function replaceFunction(str, p1) {
    if (extra.hasOwnProperty(p1)) {
      return extra[p1];
    }

    return p1;
  }
  var regex = new RegExp(/\$\{(.*?)\}/g);
  msg = msg.replace(regex, replaceFunction);
  return msg;
}

function buildFormattedLogMethod(modulename, level, callback) {
  if (level >= exports.TRACE1) {
    return function (msg, extra) {
      if (!extra) {
        extra = {};
      }
      extra['full_message'] = new Error('Backtrace').stack;
      extra = applyRewrites(modulename, level, msg, extra);
      msg = applyFormatString(msg, extra);
      callback(modulename, level, msg, extra)
    }
  }
  else {
    return function (msg, extra) {
      if (!extra) {
        extra = {};
      }
      extra = applyRewrites(modulename, level, msg, extra);
      msg = applyFormatString(msg, extra);
      callback(modulename, level, msg, extra)
    }
  }
}

function nullLogger() {
  /* Intentionally blank. */
}

function applyRoute(route, logger, modulename) {
  logger.loglevel = route.loglevel;
  for(var i=0; i<log_levels.length; i++) {
    var level = log_levels[i];
    var v = exports[level];
    var llstr = level.toLowerCase();

    if (v <= route.loglevel) {
      logger[llstr] = buildLogMethod(modulename, v, route.callback);
      logger[llstr + 'f'] = buildFormattedLogMethod(modulename, v, route.callback);
    }
    else {
      logger[llstr] = nullLogger;
      logger[llstr + 'f'] = nullLogger;
    }
  }

  for (var key in log_aliases) {
    if (log_aliases.hasOwnProperty(key)) {
      logger[key.toLowerCase()] = logger[log_aliases[key].toLowerCase()];
      logger[key.toLowerCase() + 'f'] = logger[log_aliases[key].toLowerCase() + 'f'];
    }
  }
}

function routeMatch(a, b) {
  var as = a.split('.');
  var bs = b.split('.');
  var i = 0;

  while(true) {
    if (as.length < i || bs.length < i) {
      break;
    }
    if (as[i] == bs[i]) {
      if (as.length == i) {
        return true;
      }
      i++;
      continue;
    }

    if (as[i] == "*") {
      return true;
    }

    break;
  }
  return false;
}

function applyRoutes(logger) {
  for(var i=0; i < known_routes.length; i++) {
    var r = known_routes[i];
    if (r.route == "__root__") {
      applyRoute(r, logger, logger.modulename);
    }
    else if (routeMatch(r.route, logger.modulename)) {
      applyRoute(r, logger, logger.modulename);
    }
  }
}

exports.local = function(modulename) {
  var logger = new LoggerProxy(modulename);
  applyRoutes(logger);
  known_loggers.push(logger);
  return logger;
};

exports.registerSink = function(sinkname, callback) {
  known_sinks[sinkname] = callback;
};

exports.route = function(match, loglevel, sinkname) {

  if (!(loglevel >= exports.EMERG && loglevel <= exports.TRACE8)) {
    throw new Error("Invalid Log level: " + loglevel);
  }

  /* TODO: Maybe it is okay to route before we have a sink loaded (?) */
  if (known_sinks[sinkname] === undefined) {
    throw new Error("Invalid Sink: " + sinkname);
  }

  known_routes.push({route: match, loglevel: loglevel, callback: known_sinks[sinkname]});

  for(var i=0; i<known_loggers.length; i++) {
    var logger = known_loggers[i];
    applyRoutes(logger);
  }
};

exports.addRewriter = function(func) {
  rewriters.push(func);
};

exports.clearRewriter = function(func) {
  rewriters.pop(func);
};

(function() {
  /* Default Sinks */

  /* This is just here for initial dev work, REMOVE ME */
  exports.registerSink("console", function(modulename, level, message, obj) {
    if (obj && Object.keys(obj).length !== 0) {
      /* TODO: improve */
      var fm = obj['full_message'] ? "\n  " + obj['full_message'] : "";
      obj['full_message'] = undefined;
      console.log(modulename +": "+ message + " " + JSON.stringify(obj) + fm);
    }
    else {
      console.log(modulename +": "+ message);
    }
  });

  exports.registerSink("graylog2-stderr", function(modulename, level, message, obj) {
    /* Outputs a GLEF-style JSON to stderr */
    var str = graylog.logstr(modulename, level, message, obj);
    process.stderr.write(str + "\n");
  });

  /* Default loggers */
  exports.route("__root__", exports.INFO, "console");
})();
<commit_msg>fix(console-sink): Include a timestamp when using the console sink.<commit_after>/*
 * Licensed to Paul Querna under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Paul Querna licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var graylog = require('./graylog');

function LoggerProxy(modulename) {
  this.modulename =  modulename;
  this.loglevel = -1;
}

/* Based on the Log levels available in Apache HTTP Server. */
exports.EMERG = 0;    /* system is unusable */
exports.ALERT = 1;    /* action must be taken immediately */
exports.CRIT = 2;     /* critical conditions */
exports.ERR = 3;      /* error conditions */
exports.WARNING = 4;  /* warning conditions */
exports.NOTICE = 5;   /* normal but significant condition */
exports.INFO = 6;     /* informational */
exports.DEBUG = 7;    /* debug-level messages */
exports.TRACE1 = 8;   /* trace-level 1 messages */
exports.TRACE2 = 9;   /* trace-level 2 messages */
exports.TRACE3 = 10;  /* trace-level 3 messages */
exports.TRACE4 = 11;  /* trace-level 4 messages */
exports.TRACE5 = 12;  /* trace-level 5 messages */
exports.TRACE6 = 13;  /* trace-level 6 messages */
exports.TRACE7 = 14;  /* trace-level 7 messages */
exports.TRACE8 = 15;  /* trace-level 8 messages */

var log_levels = ["EMERG",
                  "ALERT",
                  "CRIT",
                  "ERR",
                  "WARNING",
                  "NOTICE",
                  "INFO",
                  "DEBUG",
                  "TRACE1",
                  "TRACE2",
                  "TRACE3",
                  "TRACE4",
                  "TRACE5",
                  "TRACE6",
                  "TRACE7",
                  "TRACE8"];

var log_aliases = {"WARN": "WARNING",
                   "ERROR": "ERR",
                   "DBG": "DEBUG",
                   "MSG": "INFO",
                   "TRACE": "TRACE1"};

var known_sinks = {};
var known_loggers = [];
var known_routes = [];
var rewriters = [];

function applyRewrites(modulename, level, msg, extra) {
  var i;
  for (i = 0; i < rewriters.length; i++) {
    extra = rewriters[i](modulename, level, msg, extra);
  }
  return extra;
}

function buildLogMethod(modulename, level, callback) {
  if (level >= exports.TRACE1) {
    return function (msg, extra) {
      if (!extra) {
        extra = {};
      }
      extra['full_message'] = new Error('Backtrace').stack;
      extra = applyRewrites(modulename, level, msg, extra);
      callback(modulename, level, msg, extra)
    }
  }
  else {
    return function (msg, extra) {
      if (!extra) {
        extra = {};
      }
      extra = applyRewrites(modulename, level, msg, extra);
      callback(modulename, level, msg, extra)
    }
  }
}

function applyFormatString(msg, extra) {
  function replaceFunction(str, p1) {
    if (extra.hasOwnProperty(p1)) {
      return extra[p1];
    }

    return p1;
  }
  var regex = new RegExp(/\$\{(.*?)\}/g);
  msg = msg.replace(regex, replaceFunction);
  return msg;
}

function buildFormattedLogMethod(modulename, level, callback) {
  if (level >= exports.TRACE1) {
    return function (msg, extra) {
      if (!extra) {
        extra = {};
      }
      extra['full_message'] = new Error('Backtrace').stack;
      extra = applyRewrites(modulename, level, msg, extra);
      msg = applyFormatString(msg, extra);
      callback(modulename, level, msg, extra)
    }
  }
  else {
    return function (msg, extra) {
      if (!extra) {
        extra = {};
      }
      extra = applyRewrites(modulename, level, msg, extra);
      msg = applyFormatString(msg, extra);
      callback(modulename, level, msg, extra)
    }
  }
}

function nullLogger() {
  /* Intentionally blank. */
}

function applyRoute(route, logger, modulename) {
  logger.loglevel = route.loglevel;
  for(var i=0; i<log_levels.length; i++) {
    var level = log_levels[i];
    var v = exports[level];
    var llstr = level.toLowerCase();

    if (v <= route.loglevel) {
      logger[llstr] = buildLogMethod(modulename, v, route.callback);
      logger[llstr + 'f'] = buildFormattedLogMethod(modulename, v, route.callback);
    }
    else {
      logger[llstr] = nullLogger;
      logger[llstr + 'f'] = nullLogger;
    }
  }

  for (var key in log_aliases) {
    if (log_aliases.hasOwnProperty(key)) {
      logger[key.toLowerCase()] = logger[log_aliases[key].toLowerCase()];
      logger[key.toLowerCase() + 'f'] = logger[log_aliases[key].toLowerCase() + 'f'];
    }
  }
}

function routeMatch(a, b) {
  var as = a.split('.');
  var bs = b.split('.');
  var i = 0;

  while(true) {
    if (as.length < i || bs.length < i) {
      break;
    }
    if (as[i] == bs[i]) {
      if (as.length == i) {
        return true;
      }
      i++;
      continue;
    }

    if (as[i] == "*") {
      return true;
    }

    break;
  }
  return false;
}

function applyRoutes(logger) {
  for(var i=0; i < known_routes.length; i++) {
    var r = known_routes[i];
    if (r.route == "__root__") {
      applyRoute(r, logger, logger.modulename);
    }
    else if (routeMatch(r.route, logger.modulename)) {
      applyRoute(r, logger, logger.modulename);
    }
  }
}

exports.local = function(modulename) {
  var logger = new LoggerProxy(modulename);
  applyRoutes(logger);
  known_loggers.push(logger);
  return logger;
};

exports.registerSink = function(sinkname, callback) {
  known_sinks[sinkname] = callback;
};

exports.route = function(match, loglevel, sinkname) {

  if (!(loglevel >= exports.EMERG && loglevel <= exports.TRACE8)) {
    throw new Error("Invalid Log level: " + loglevel);
  }

  /* TODO: Maybe it is okay to route before we have a sink loaded (?) */
  if (known_sinks[sinkname] === undefined) {
    throw new Error("Invalid Sink: " + sinkname);
  }

  known_routes.push({route: match, loglevel: loglevel, callback: known_sinks[sinkname]});

  for(var i=0; i<known_loggers.length; i++) {
    var logger = known_loggers[i];
    applyRoutes(logger);
  }
};

exports.addRewriter = function(func) {
  rewriters.push(func);
};

exports.clearRewriter = function(func) {
  rewriters.pop(func);
};

(function() {
  /* Default Sinks */

  /* This is just here for initial dev work, REMOVE ME */
  exports.registerSink("console", function(modulename, level, message, obj) {
    var timestamp = (new Date().getTime()) / 1000;

    if (obj && Object.keys(obj).length !== 0) {
      /* TODO: improve */
      var fm = obj['full_message'] ? "\n  " + obj['full_message'] : "";
      obj['full_message'] = undefined;
      console.log(modulename + " [" + timestamp + "]" + ": "+ message + " " + JSON.stringify(obj) + fm);
    }
    else {
      console.log(modulename + " [" + timestamp + "]" + ": "+ message);
    }
  });

  exports.registerSink("graylog2-stderr", function(modulename, level, message, obj) {
    /* Outputs a GLEF-style JSON to stderr */
    var str = graylog.logstr(modulename, level, message, obj);
    process.stderr.write(str + "\n");
  });

  /* Default loggers */
  exports.route("__root__", exports.INFO, "console");
})();
<|endoftext|>


<commit_before>'use babel'

/* @flow */

import Path from 'path'
import FS from 'fs'
import isGlob from 'is-glob'
import {isMatch} from 'micromatch'
import type {Stats} from 'fs'

export const R_OK = 4
export const W_OK = 2
export const NormalizationRegExp = /\\/g
export const FindCache: Map<string, string> = new Map()

// TODO: Put these file system helpers to a node module

export function stat(path: string): Promise<Stats> {
  return new Promise(function(resolve, reject) {
    FS.lstat(path, function(error, stats) {
      if (error) {
        reject(error)
      } else resolve(stats)
    })
  })
}

export function readdir(path: string): Promise<Array<string>> {
  return new Promise(function(resolve, reject) {
    FS.readdir(path, function(error, entries) {
      if (error) {
        reject(error)
      } else resolve(entries)
    })
  })
}

export function read(path: string): Promise<string> {
  return new Promise(function(resolve, reject) {
    FS.readFile(path, function(error, contents) {
      if (error) {
        reject(error)
      } else resolve(contents.toString())
    })
  })
}

export function write(path: string, contents: string): Promise {
  return new Promise(function(resolve, reject) {
    FS.writeFile(path, contents, function(error) {
      if (error) {
        reject(error)
      } else resolve()
    })
  })
}

export function exists(path: string): Promise<boolean> {
  return new Promise(function(resolve) {
    FS.access(path, function(error) {
      resolve(error === null)
    })
  })
}

export async function find(rootDirectory: string, fileName: string): Promise<?string> {
  if (!await exists(rootDirectory)) {
    throw new Error(`Can not read directory ${rootDirectory}`)
  }

  const chunks = rootDirectory.split(Path.sep)
  while (chunks.length) {
    const filePath = Path.join(chunks.join(Path.sep), fileName)
    if (filePath === fileName) {
      break
    }
    if (await exists(filePath)) {
      return filePath
    }
    chunks.pop()
  }
  return null
}

export async function findCached(rootDirectory: string, fileName: string): Promise<?string> {
  const cacheKey = rootDirectory + ':' + fileName
  const cachedFilePath = FindCache.get(cacheKey)

  if (cachedFilePath) {
    if (await exists(cachedFilePath)) {
      return cachedFilePath
    }
    FindCache.delete(cacheKey)
  }
  const filePath = await find(rootDirectory, fileName)
  if (filePath) {
    FindCache.set(cacheKey, filePath)
  }
  return filePath
}

export function isExcluded(fileNames: Array<string> , ignored: Array<string>): boolean {
  return ignored.some(function(entry) {
    const entryIsGlob = isGlob(entry)
    for (const fileName of fileNames) {
      if (entryIsGlob ? isMatch(fileName, entry) : fileName === entry) {
        return true
      }
    }
    return false
  })
}

export function normalizePath(path: string): string {
  if (process.platform === 'win32') {
    return path.replace(NormalizationRegExp, '/')
  }
  return path
}

export function asyncReduce<TItem, TValue>(items: Array<TItem>, initialValue: TValue, callback:((item: TItem, value: TValue) => Promise<TValue>)): Promise<TValue> {
  return items.reduce(function(promise, item) {
    return promise.then(function(previousResult) {
      return callback(item, previousResult)
    })
  }, new Promise(function(resolve) {
    resolve(initialValue)
  }))
}
<commit_msg>:new: Add mkdirp try on write fail<commit_after>'use babel'

/* @flow */

import Path from 'path'
import FS from 'fs'
import isGlob from 'is-glob'
import {isMatch} from 'micromatch'
import type {Stats} from 'fs'
import mkdirp from 'mkdirp'

export const R_OK = 4
export const W_OK = 2
export const NormalizationRegExp = /\\/g
export const FindCache: Map<string, string> = new Map()

// TODO: Put these file system helpers to a node module

export function stat(path: string): Promise<Stats> {
  return new Promise(function(resolve, reject) {
    FS.lstat(path, function(error, stats) {
      if (error) {
        reject(error)
      } else resolve(stats)
    })
  })
}

export function readdir(path: string): Promise<Array<string>> {
  return new Promise(function(resolve, reject) {
    FS.readdir(path, function(error, entries) {
      if (error) {
        reject(error)
      } else resolve(entries)
    })
  })
}

export function read(path: string): Promise<string> {
  return new Promise(function(resolve, reject) {
    FS.readFile(path, function(error, contents) {
      if (error) {
        reject(error)
      } else resolve(contents.toString())
    })
  })
}

export function write(path: string, contents: string): Promise {
  return new Promise(function writeFile(resolve, reject, retry = true) {
    FS.writeFile(path, contents, function(error) {
      if (error) {
        if (error.code === 'ENOENT' && retry) {
          mkdirp(Path.dirname(path), function(error) {
            if (error) {
              reject(error)
            } else writeFile(resolve, reject, false)
          })
        } else reject(error)
      } else resolve()
    })
  })
}

export function exists(path: string): Promise<boolean> {
  return new Promise(function(resolve) {
    FS.access(path, function(error) {
      resolve(error === null)
    })
  })
}

export async function find(rootDirectory: string, fileName: string): Promise<?string> {
  if (!await exists(rootDirectory)) {
    throw new Error(`Can not read directory ${rootDirectory}`)
  }

  const chunks = rootDirectory.split(Path.sep)
  while (chunks.length) {
    const filePath = Path.join(chunks.join(Path.sep), fileName)
    if (filePath === fileName) {
      break
    }
    if (await exists(filePath)) {
      return filePath
    }
    chunks.pop()
  }
  return null
}

export async function findCached(rootDirectory: string, fileName: string): Promise<?string> {
  const cacheKey = rootDirectory + ':' + fileName
  const cachedFilePath = FindCache.get(cacheKey)

  if (cachedFilePath) {
    if (await exists(cachedFilePath)) {
      return cachedFilePath
    }
    FindCache.delete(cacheKey)
  }
  const filePath = await find(rootDirectory, fileName)
  if (filePath) {
    FindCache.set(cacheKey, filePath)
  }
  return filePath
}

export function isExcluded(fileNames: Array<string> , ignored: Array<string>): boolean {
  return ignored.some(function(entry) {
    const entryIsGlob = isGlob(entry)
    for (const fileName of fileNames) {
      if (entryIsGlob ? isMatch(fileName, entry) : fileName === entry) {
        return true
      }
    }
    return false
  })
}

export function normalizePath(path: string): string {
  if (process.platform === 'win32') {
    return path.replace(NormalizationRegExp, '/')
  }
  return path
}

export function asyncReduce<TItem, TValue>(items: Array<TItem>, initialValue: TValue, callback:((item: TItem, value: TValue) => Promise<TValue>)): Promise<TValue> {
  return items.reduce(function(promise, item) {
    return promise.then(function(previousResult) {
      return callback(item, previousResult)
    })
  }, new Promise(function(resolve) {
    resolve(initialValue)
  }))
}
<|endoftext|>