<commit_before>import React, { cloneElement, isValidElement } from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';
import classNames from 'classnames';
import Text from './Text';
import { getPresentationAttributes, findAllByType } from '../util/ReactUtils';
import { isNumOrStr, isNumber, isPercent, getPercentValue, uniqueId,
  mathSign } from '../util/DataUtils';
import { polarToCartesian } from '../util/PolarUtils';

const cartesianViewBoxShape = PropTypes.shape({
  x: PropTypes.number,
  y: PropTypes.number,
  width: PropTypes.number,
  height: PropTypes.number,
});
const polarViewBoxShape = PropTypes.shape({
  cx: PropTypes.number,
  cy: PropTypes.number,
  innerRadius: PropTypes.number,
  outerRadius: PropTypes.number,
  startAngle: PropTypes.number,
  endAngle: PropTypes.number,
});

const propTypes = {
  viewBox: PropTypes.oneOfType([cartesianViewBoxShape, polarViewBoxShape]),
  formatter: PropTypes.func,
  value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
  offset: PropTypes.number,
  position: PropTypes.oneOf([
    'top', 'left', 'right', 'bottom', 'inside', 'outside',
    'insideLeft', 'insideRight', 'insideTop', 'insideBottom',
    'insideTopLeft', 'insideBottomLeft', 'insideTopRight', 'insideBottomRight',
    'insideStart', 'insideEnd', 'end', 'center',
  ]),
  children: PropTypes.oneOfType([
    PropTypes.arrayOf(PropTypes.node),
    PropTypes.node,
  ]),
  className: PropTypes.string,
  content: PropTypes.oneOfType([PropTypes.element, PropTypes.func]),
};

const defaultProps = {
  offset: 5,
};

const getLabel = (props) => {
  const { value, formatter } = props;
  const label = _.isNil(props.children) ? value : props.children;

  if (_.isFunction(formatter)) {
    return formatter(label);
  }

  return label;
};

const getDeltaAngle = (startAngle, endAngle) => {
  const sign = mathSign(endAngle - startAngle);
  const deltaAngle = Math.min(Math.abs(endAngle - startAngle), 360);

  return sign * deltaAngle;
};

const renderRadialLabel = (labelProps, label, attrs) => {
  const { position, viewBox, offset, className } = labelProps;
  const { cx, cy, innerRadius, outerRadius, startAngle, endAngle,
    clockWise } = viewBox;
  const radius = (innerRadius + outerRadius) / 2;
  const deltaAngle = getDeltaAngle(startAngle, endAngle);
  const sign = deltaAngle >= 0 ? 1 : -1;
  let labelAngle, direction;

  if (position === 'insideStart') {
    labelAngle = startAngle + sign * offset;
    direction = clockWise;
  } else if (position === 'insideEnd') {
    labelAngle = endAngle - sign * offset;
    direction = !clockWise;
  } else if (position === 'end') {
    labelAngle = endAngle + sign * offset;
    direction = clockWise;
  }

  direction = deltaAngle <= 0 ? direction : !direction;

  const startPoint = polarToCartesian(cx, cy, radius, labelAngle);
  const endPoint = polarToCartesian(cx, cy, radius, labelAngle + (direction ? 1 : -1) * 359);
  const path = `M${startPoint.x},${startPoint.y}
    A${radius},${radius},0,1,${direction ? 0 : 1},
    ${endPoint.x},${endPoint.y}`;
  const id = uniqueId('recharts-radial-line-');

  return (
    <text
      {...attrs}
      dominantBaseline="central"
      className={classNames('recharts-radial-bar-label', className)}
    >
      <defs><path id={id} d={path} /></defs>
      <textPath xlinkHref={`#${id}`}>{label}</textPath>
    </text>
  );
};

const getAttrsOfPolarLabel = (props) => {
  const { viewBox, offset, position } = props;
  const { cx, cy, innerRadius, outerRadius, startAngle, endAngle } = viewBox;
  const midAngle = (startAngle + endAngle) / 2;

  if (position === 'outside') {
    const { x, y } = polarToCartesian(cx, cy, outerRadius + offset, midAngle);

    return {
      x,
      y,
      textAnchor: x >= cx ? 'start' : 'end',
      verticalAnchor: 'middle',
    };
  }

  if (position === 'center') {
    return {
      x: cx,
      y: cy,
      textAnchor: 'middle',
      verticalAnchor: 'middle',
    };
  }

  const r = (innerRadius + outerRadius) / 2;
  const { x, y } = polarToCartesian(cx, cy, r, midAngle);

  return {
    x,
    y,
    textAnchor: 'middle',
    verticalAnchor: 'middle',
  };
};

const getAttrsOfCartesianLabel = (props) => {
  const { viewBox, offset, position } = props;
  const { x, y, width, height } = viewBox;
  const sign = height >= 0 ? 1 : -1;

  if (position === 'top') {
    return {
      x: x + width / 2,
      y: y - sign * offset,
      textAnchor: 'middle',
      verticalAnchor: 'end',
    };
  }

  if (position === 'bottom') {
    return {
      x: x + width / 2,
      y: y + height + sign * offset,
      textAnchor: 'middle',
      verticalAnchor: 'start',
    };
  }

  if (position === 'left') {
    return {
      x: x - offset,
      y: y + height / 2,
      textAnchor: 'end',
      verticalAnchor: 'middle',
    };
  }

  if (position === 'right') {
    return {
      x: x + width + offset,
      y: y + height / 2,
      textAnchor: 'start',
      verticalAnchor: 'middle',
    };
  }

  if (position === 'insideLeft') {
    return {
      x: x + offset,
      y: y + height / 2,
      textAnchor: 'start',
      verticalAnchor: 'middle',
    };
  }

  if (position === 'insideRight') {
    return {
      x: x + width - offset,
      y: y + height / 2,
      textAnchor: 'end',
      verticalAnchor: 'middle',
    };
  }

  if (position === 'insideTop') {
    return {
      x: x + width / 2,
      y: y + sign * offset,
      textAnchor: 'middle',
      verticalAnchor: 'start',
    };
  }

  if (position === 'insideBottom') {
    return {
      x: x + width / 2,
      y: y + height - sign * offset,
      textAnchor: 'middle',
      verticalAnchor: 'end',
    };
  }

  if (position === 'insideTopLeft') {
    return {
      x: x + offset,
      y: y + sign * offset,
      textAnchor: 'start',
      verticalAnchor: 'start',
    };
  }

  if (position === 'insideTopRight') {
    return {
      x: x + width - offset,
      y: y + sign * offset,
      textAnchor: 'end',
      verticalAnchor: 'start',
    };
  }

  if (position === 'insideBottomLeft') {
    return {
      x: x + offset,
      y: y + height - sign * offset,
      textAnchor: 'start',
      verticalAnchor: 'end',
    };
  }

  if (position === 'insideBottomRight') {
    return {
      x: x + width - offset,
      y: y + height - sign * offset,
      textAnchor: 'end',
      verticalAnchor: 'end',
    };
  }

  if (_.isObject(position) && (isNumber(position.x) || isPercent(position.x)) &&
    (isNumber(position.y) || isPercent(position.y))
  ) {
    return {
      x: x + getPercentValue(position.x, width),
      y: y + getPercentValue(position.y, height),
      textAnchor: 'end',
      verticalAnchor: 'end',
    };
  }

  return {
    x: x + width / 2,
    y: y + height / 2,
    textAnchor: 'middle',
    verticalAnchor: 'middle',
  };
};

const isPolar = viewBox => isNumber(viewBox.cx);

function Label(props) {
  const { viewBox, position, value, children, content, className = '' } = props;

  if (!viewBox || (_.isNil(value) && _.isNil(children) &&
    !isValidElement(content) && !_.isFunction(content))) { return null; }

  if (isValidElement(content)) { return cloneElement(content, props); }
  if (_.isFunction(content)) { return content(props); }

  const isPolarLabel = isPolar(viewBox);
  const label = getLabel(props);
  const attrs = getPresentationAttributes(props);

  if (isPolarLabel && (position === 'insideStart' ||
    position === 'insideEnd' || position === 'end')) {
    return renderRadialLabel(props, label, attrs);
  }

  const positionAttrs = isPolarLabel ?
    getAttrsOfPolarLabel(props) :
    getAttrsOfCartesianLabel(props);

  return (
    <Text
      className={classNames('recharts-label', className)}
      {...attrs}
      {...positionAttrs}
    >{label}</Text>
  );
}

Label.displayName = 'Label';
Label.defaultProps = defaultProps;
Label.propTypes = propTypes;

const parseViewBox = (props) => {
  const { cx, cy, angle, startAngle, endAngle, r, radius, innerRadius, outerRadius,
    x, y, top, left, width, height, clockWise } = props;

  if (isNumber(width) && isNumber(height)) {
    if (isNumber(x) && isNumber(y)) {
      return { x, y, width, height };
    } else if (isNumber(top) && isNumber(left)) {
      return { x: top, y: left, width, height };
    }
  }

  if (isNumber(x) && isNumber(y)) {
    return { x, y, width: 0, height: 0 };
  }

  if (isNumber(cx) && isNumber(cy)) {
    return {
      cx, cy,
      startAngle: startAngle || angle || 0,
      endAngle: endAngle || angle || 0,
      innerRadius: innerRadius || 0,
      outerRadius: outerRadius || radius || r || 0,
      clockWise,
    };
  }

  if (props.viewBox) {
    return props.viewBox;
  }

  return {};
};

const parseLabel = (label, viewBox) => {
  if (!label) { return null; }

  if (label === true) {
    return <Label key="label-implicit" viewBox={viewBox} />;
  }

  if (isNumOrStr(label)) {
    return <Label key="label-implicit" viewBox={viewBox} value={label} />;
  }

  if (isValidElement(label) || _.isFunction(label)) {
    return <Label key="label-implicit" content={label} viewBox={viewBox} />;
  }

  if (_.isObject(label)) {
    return <Label viewBox={viewBox} {...label} key="label-implicit" />;
  }

  return null;
};

const renderCallByParent = (parentProps, viewBox, ckeckPropsLabel = true) => {
  if (!parentProps || (!parentProps.children && (ckeckPropsLabel && !parentProps.label))) {
    return null;
  }
  const { children } = parentProps;
  const parentViewBox = parseViewBox(parentProps);

  const explicitChilren = findAllByType(children, Label).map((child, index) =>
    cloneElement(child, {
      viewBox: viewBox || parentViewBox,
      key: `label-${index}`,
    })
  );

  if (!ckeckPropsLabel) { return explicitChilren; }
  const implicitLabel = parseLabel(parentProps.label, viewBox || parentViewBox);

  return [implicitLabel, ...explicitChilren];
};

Label.parseViewBox = parseViewBox;
Label.renderCallByParent = renderCallByParent;

export default Label;
<commit_msg>fix: fix attributes order of <Label /><commit_after>import React, { cloneElement, isValidElement } from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';
import classNames from 'classnames';
import Text from './Text';
import { getPresentationAttributes, findAllByType } from '../util/ReactUtils';
import { isNumOrStr, isNumber, isPercent, getPercentValue, uniqueId,
  mathSign } from '../util/DataUtils';
import { polarToCartesian } from '../util/PolarUtils';

const cartesianViewBoxShape = PropTypes.shape({
  x: PropTypes.number,
  y: PropTypes.number,
  width: PropTypes.number,
  height: PropTypes.number,
});
const polarViewBoxShape = PropTypes.shape({
  cx: PropTypes.number,
  cy: PropTypes.number,
  innerRadius: PropTypes.number,
  outerRadius: PropTypes.number,
  startAngle: PropTypes.number,
  endAngle: PropTypes.number,
});

const propTypes = {
  viewBox: PropTypes.oneOfType([cartesianViewBoxShape, polarViewBoxShape]),
  formatter: PropTypes.func,
  value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
  offset: PropTypes.number,
  position: PropTypes.oneOf([
    'top', 'left', 'right', 'bottom', 'inside', 'outside',
    'insideLeft', 'insideRight', 'insideTop', 'insideBottom',
    'insideTopLeft', 'insideBottomLeft', 'insideTopRight', 'insideBottomRight',
    'insideStart', 'insideEnd', 'end', 'center',
  ]),
  children: PropTypes.oneOfType([
    PropTypes.arrayOf(PropTypes.node),
    PropTypes.node,
  ]),
  className: PropTypes.string,
  content: PropTypes.oneOfType([PropTypes.element, PropTypes.func]),
};

const defaultProps = {
  offset: 5,
};

const getLabel = (props) => {
  const { value, formatter } = props;
  const label = _.isNil(props.children) ? value : props.children;

  if (_.isFunction(formatter)) {
    return formatter(label);
  }

  return label;
};

const getDeltaAngle = (startAngle, endAngle) => {
  const sign = mathSign(endAngle - startAngle);
  const deltaAngle = Math.min(Math.abs(endAngle - startAngle), 360);

  return sign * deltaAngle;
};

const renderRadialLabel = (labelProps, label, attrs) => {
  const { position, viewBox, offset, className } = labelProps;
  const { cx, cy, innerRadius, outerRadius, startAngle, endAngle,
    clockWise } = viewBox;
  const radius = (innerRadius + outerRadius) / 2;
  const deltaAngle = getDeltaAngle(startAngle, endAngle);
  const sign = deltaAngle >= 0 ? 1 : -1;
  let labelAngle, direction;

  if (position === 'insideStart') {
    labelAngle = startAngle + sign * offset;
    direction = clockWise;
  } else if (position === 'insideEnd') {
    labelAngle = endAngle - sign * offset;
    direction = !clockWise;
  } else if (position === 'end') {
    labelAngle = endAngle + sign * offset;
    direction = clockWise;
  }

  direction = deltaAngle <= 0 ? direction : !direction;

  const startPoint = polarToCartesian(cx, cy, radius, labelAngle);
  const endPoint = polarToCartesian(cx, cy, radius, labelAngle + (direction ? 1 : -1) * 359);
  const path = `M${startPoint.x},${startPoint.y}
    A${radius},${radius},0,1,${direction ? 0 : 1},
    ${endPoint.x},${endPoint.y}`;
  const id = uniqueId('recharts-radial-line-');

  return (
    <text
      {...attrs}
      dominantBaseline="central"
      className={classNames('recharts-radial-bar-label', className)}
    >
      <defs><path id={id} d={path} /></defs>
      <textPath xlinkHref={`#${id}`}>{label}</textPath>
    </text>
  );
};

const getAttrsOfPolarLabel = (props) => {
  const { viewBox, offset, position } = props;
  const { cx, cy, innerRadius, outerRadius, startAngle, endAngle } = viewBox;
  const midAngle = (startAngle + endAngle) / 2;

  if (position === 'outside') {
    const { x, y } = polarToCartesian(cx, cy, outerRadius + offset, midAngle);

    return {
      x,
      y,
      textAnchor: x >= cx ? 'start' : 'end',
      verticalAnchor: 'middle',
    };
  }

  if (position === 'center') {
    return {
      x: cx,
      y: cy,
      textAnchor: 'middle',
      verticalAnchor: 'middle',
    };
  }

  const r = (innerRadius + outerRadius) / 2;
  const { x, y } = polarToCartesian(cx, cy, r, midAngle);

  return {
    x,
    y,
    textAnchor: 'middle',
    verticalAnchor: 'middle',
  };
};

const getAttrsOfCartesianLabel = (props) => {
  const { viewBox, offset, position } = props;
  const { x, y, width, height } = viewBox;
  const sign = height >= 0 ? 1 : -1;

  if (position === 'top') {
    return {
      x: x + width / 2,
      y: y - sign * offset,
      textAnchor: 'middle',
      verticalAnchor: 'end',
    };
  }

  if (position === 'bottom') {
    return {
      x: x + width / 2,
      y: y + height + sign * offset,
      textAnchor: 'middle',
      verticalAnchor: 'start',
    };
  }

  if (position === 'left') {
    return {
      x: x - offset,
      y: y + height / 2,
      textAnchor: 'end',
      verticalAnchor: 'middle',
    };
  }

  if (position === 'right') {
    return {
      x: x + width + offset,
      y: y + height / 2,
      textAnchor: 'start',
      verticalAnchor: 'middle',
    };
  }

  if (position === 'insideLeft') {
    return {
      x: x + offset,
      y: y + height / 2,
      textAnchor: 'start',
      verticalAnchor: 'middle',
    };
  }

  if (position === 'insideRight') {
    return {
      x: x + width - offset,
      y: y + height / 2,
      textAnchor: 'end',
      verticalAnchor: 'middle',
    };
  }

  if (position === 'insideTop') {
    return {
      x: x + width / 2,
      y: y + sign * offset,
      textAnchor: 'middle',
      verticalAnchor: 'start',
    };
  }

  if (position === 'insideBottom') {
    return {
      x: x + width / 2,
      y: y + height - sign * offset,
      textAnchor: 'middle',
      verticalAnchor: 'end',
    };
  }

  if (position === 'insideTopLeft') {
    return {
      x: x + offset,
      y: y + sign * offset,
      textAnchor: 'start',
      verticalAnchor: 'start',
    };
  }

  if (position === 'insideTopRight') {
    return {
      x: x + width - offset,
      y: y + sign * offset,
      textAnchor: 'end',
      verticalAnchor: 'start',
    };
  }

  if (position === 'insideBottomLeft') {
    return {
      x: x + offset,
      y: y + height - sign * offset,
      textAnchor: 'start',
      verticalAnchor: 'end',
    };
  }

  if (position === 'insideBottomRight') {
    return {
      x: x + width - offset,
      y: y + height - sign * offset,
      textAnchor: 'end',
      verticalAnchor: 'end',
    };
  }

  if (_.isObject(position) && (isNumber(position.x) || isPercent(position.x)) &&
    (isNumber(position.y) || isPercent(position.y))
  ) {
    return {
      x: x + getPercentValue(position.x, width),
      y: y + getPercentValue(position.y, height),
      textAnchor: 'end',
      verticalAnchor: 'end',
    };
  }

  return {
    x: x + width / 2,
    y: y + height / 2,
    textAnchor: 'middle',
    verticalAnchor: 'middle',
  };
};

const isPolar = viewBox => isNumber(viewBox.cx);

function Label(props) {
  const { viewBox, position, value, children, content, className = '' } = props;

  if (!viewBox || (_.isNil(value) && _.isNil(children) &&
    !isValidElement(content) && !_.isFunction(content))) { return null; }

  if (isValidElement(content)) { return cloneElement(content, props); }
  if (_.isFunction(content)) { return content(props); }

  const isPolarLabel = isPolar(viewBox);
  const label = getLabel(props);
  const attrs = getPresentationAttributes(props);

  if (isPolarLabel && (position === 'insideStart' ||
    position === 'insideEnd' || position === 'end')) {
    return renderRadialLabel(props, label, attrs);
  }

  const positionAttrs = isPolarLabel ?
    getAttrsOfPolarLabel(props) :
    getAttrsOfCartesianLabel(props);

  return (
    <Text
      className={classNames('recharts-label', className)}
      {...positionAttrs}
      {...attrs}
    >{label}</Text>
  );
}

Label.displayName = 'Label';
Label.defaultProps = defaultProps;
Label.propTypes = propTypes;

const parseViewBox = (props) => {
  const { cx, cy, angle, startAngle, endAngle, r, radius, innerRadius, outerRadius,
    x, y, top, left, width, height, clockWise } = props;

  if (isNumber(width) && isNumber(height)) {
    if (isNumber(x) && isNumber(y)) {
      return { x, y, width, height };
    } else if (isNumber(top) && isNumber(left)) {
      return { x: top, y: left, width, height };
    }
  }

  if (isNumber(x) && isNumber(y)) {
    return { x, y, width: 0, height: 0 };
  }

  if (isNumber(cx) && isNumber(cy)) {
    return {
      cx, cy,
      startAngle: startAngle || angle || 0,
      endAngle: endAngle || angle || 0,
      innerRadius: innerRadius || 0,
      outerRadius: outerRadius || radius || r || 0,
      clockWise,
    };
  }

  if (props.viewBox) {
    return props.viewBox;
  }

  return {};
};

const parseLabel = (label, viewBox) => {
  if (!label) { return null; }

  if (label === true) {
    return <Label key="label-implicit" viewBox={viewBox} />;
  }

  if (isNumOrStr(label)) {
    return <Label key="label-implicit" viewBox={viewBox} value={label} />;
  }

  if (isValidElement(label) || _.isFunction(label)) {
    return <Label key="label-implicit" content={label} viewBox={viewBox} />;
  }

  if (_.isObject(label)) {
    return <Label viewBox={viewBox} {...label} key="label-implicit" />;
  }

  return null;
};

const renderCallByParent = (parentProps, viewBox, ckeckPropsLabel = true) => {
  if (!parentProps || (!parentProps.children && (ckeckPropsLabel && !parentProps.label))) {
    return null;
  }
  const { children } = parentProps;
  const parentViewBox = parseViewBox(parentProps);

  const explicitChilren = findAllByType(children, Label).map((child, index) =>
    cloneElement(child, {
      viewBox: viewBox || parentViewBox,
      key: `label-${index}`,
    })
  );

  if (!ckeckPropsLabel) { return explicitChilren; }
  const implicitLabel = parseLabel(parentProps.label, viewBox || parentViewBox);

  return [implicitLabel, ...explicitChilren];
};

Label.parseViewBox = parseViewBox;
Label.renderCallByParent = renderCallByParent;

export default Label;
<|endoftext|>


<commit_before>var BaseTexture = require('./BaseTexture'),
    Texture = require('./Texture'),
    RenderTarget = require('../renderers/webgl/utils/RenderTarget'),
    CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'),
    math = require('../math'),
    CONST = require('../const');

/**
 * A RenderTexture is a special texture that allows any Pixi display object to be rendered to it.
 *
 * __Hint__: All DisplayObjects (i.e. Sprites) that render to a RenderTexture should be preloaded
 * otherwise black rectangles will be drawn instead.
 *
 * A RenderTexture takes a snapshot of any Display Object given to its render method. The position
 * and rotation of the given Display Objects is ignored. For example:
 *
 * ```js
 * var renderTexture = new PIXI.RenderTexture(800, 600);
 * var sprite = PIXI.Sprite.fromImage("spinObj_01.png");
 *
 * sprite.position.x = 800/2;
 * sprite.position.y = 600/2;
 * sprite.anchor.x = 0.5;
 * sprite.anchor.y = 0.5;
 *
 * renderTexture.render(sprite);
 * ```
 *
 * The Sprite in this case will be rendered to a position of 0,0. To render this sprite at its actual
 * position a Container should be used:
 *
 * ```js
 * var doc = new Container();
 *
 * doc.addChild(sprite);
 *
 * renderTexture.render(doc);  // Renders to center of renderTexture
 * ```
 *
 * @class
 * @extends Texture
 * @namespace PIXI
 * @param renderer {CanvasRenderer|WebGLRenderer} The renderer used for this RenderTexture
 * @param [width=100] {number} The width of the render texture
 * @param [height=100] {number} The height of the render texture
 * @param [scaleMode] {number} See {@link scaleModes} for possible values
 */
function RenderTexture(renderer, width, height, scaleMode)
{
    if (!renderer)
    {
        throw new Error('Unable to create RenderTexture, you must pass a renderer into the constructor.');
    }

    width = width || 100;
    height = height || 100;

    /**
     * The base texture object that this texture uses
     *
     * @member {BaseTexture}
     */
    var baseTexture = new BaseTexture();
    baseTexture.width = width;
    baseTexture.height = height;
    baseTexture.scaleMode = scaleMode || CONST.scaleModes.DEFAULT;
    baseTexture.hasLoaded = true;

    Texture.call(this,
        baseTexture,
        new math.Rectangle(0, 0, width, height)
    );

    /**
     * The with of the render texture
     *
     * @member {number}
     */
    this.width = width;

    /**
     * The height of the render texture
     *
     * @member {number}
     */
    this.height = height;

    /**
     * The framing rectangle of the render texture
     *
     * @member {Rectangle}
     */
    //this._frame = new math.Rectangle(0, 0, this.width, this.height);

    /**
     * This is the area of the BaseTexture image to actually copy to the Canvas / WebGL when rendering,
     * irrespective of the actual frame size or placement (which can be influenced by trimmed texture atlases)
     *
     * @member {Rectangle}
     */
    //this.crop = new math.Rectangle(0, 0, this.width, this.height);

    /**
     * Draw/render the given DisplayObject onto the texture.
     *
     * The displayObject and descendents are transformed during this operation.
     * If `restoreWorldTransform` is true then the transformations will be restored before the
     * method returns. Otherwise it is up to the calling code to correctly use or reset
     * the transformed display objects.
     *
     * The display object is always rendered with a worldAlpha value of 1.
     *
     * @method
     * @param displayObject {DisplayObject} The display object to render this texture on
     * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering.
     * @param [clear=false] {boolean} If true the texture will be cleared before the displayObject is drawn
     * @param [restoreWorldTransform=true] {boolean} If true the displayObject's worldTransform/worldAlpha and all children
     *  transformations will be restored. Not restoring this information will be a little faster.
     */
    this.render = null;

    /**
     * The renderer this RenderTexture uses. A RenderTexture can only belong to one renderer at the moment if its webGL.
     *
     * @member {CanvasRenderer|WebGLRenderer}
     */
    this.renderer = renderer;

    if (this.renderer.type === CONST.RENDERER_TYPE.WEBGL)
    {
        var gl = this.renderer.gl;

        this.textureBuffer = new RenderTarget(gl, this.width, this.height);//, this.baseTexture.scaleMode);
        this.baseTexture._glTextures[gl.id] =  this.textureBuffer.texture;

        this.render = this.renderWebGL;
        this.projection = new math.Point(this.width*0.5, -this.height*0.5);
    }
    else
    {

        this.render = this.renderCanvas;
        this.textureBuffer = new CanvasBuffer(this.width, this.height);
        this.baseTexture.source = this.textureBuffer.canvas;
    }

    /**
     * @member {boolean}
     */
    this.valid = true;

    this._updateUvs();
}

RenderTexture.prototype = Object.create(Texture.prototype);
RenderTexture.prototype.constructor = RenderTexture;
module.exports = RenderTexture;

/**
 * Resizes the RenderTexture.
 *
 * @param width {number} The width to resize to.
 * @param height {number} The height to resize to.
 * @param updateBase {boolean} Should the baseTexture.width and height values be resized as well?
 */
RenderTexture.prototype.resize = function (width, height, updateBase)
{
    if (width === this.width && height === this.height)
    {
        return;
    }

    this.valid = (width > 0 && height > 0);

    this.width = this._frame.width = this.crop.width = width;
    this.height =  this._frame.height = this.crop.height = height;

    if (updateBase)
    {
        this.baseTexture.width = this.width;
        this.baseTexture.height = this.height;
    }

    if (this.renderer.type === CONST.RENDERER_TYPE.WEBGL)
    {
        this.projection.x = this.width / 2;
        this.projection.y = -this.height / 2;
    }

    if (!this.valid)
    {
        return;
    }

    this.textureBuffer.resize(this.width, this.height);
};

/**
 * Clears the RenderTexture.
 *
 */
RenderTexture.prototype.clear = function ()
{
    if (!this.valid)
    {
        return;
    }

    if (this.renderer.type === CONST.RENDERER_TYPE.WEBGL)
    {
        this.renderer.gl.bindFramebuffer(this.renderer.gl.FRAMEBUFFER, this.textureBuffer.frameBuffer);
    }

    this.textureBuffer.clear();
};

/**
 * Internal method assigned to the `render` property if using a CanvasRenderer.
 *
 * @private
 * @param displayObject {DisplayObject} The display object to render this texture on
 * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering.
 * @param [clear=false] {boolean} If true the texture will be cleared before the displayObject is drawn
 * @param [restoreWorldTransform=true] {boolean} If true the displayObject's worldTransform/worldAlpha and all children
 *  transformations will be restored. Not restoring this information will be a little faster.
 */
RenderTexture.prototype.renderWebGL = function (displayObject, matrix, clear, restoreWorldTransform)
{
    if (!this.valid)
    {
        return;
    }

    if (typeof restoreWorldTransform === 'undefined')
    {
        restoreWorldTransform = true;
    }

    var tempAlpha,
        tempTransform;

    if (restoreWorldTransform)
    {
        tempAlpha = displayObject.worldAlpha;
        tempTransform = displayObject.worldTransform.toArray();
    }

    //TOOD replace position with matrix..

    //Lets create a nice matrix to apply to our display object. Frame buffers come in upside down so we need to flip the matrix
    var wt = displayObject.worldTransform;

    wt.identity();
 //   wt.translate(0, this.projection.y * 2);

    if (matrix)
    {
        wt.append(matrix);
    }

   // wt.scale(1,-1);

    // setWorld Alpha to ensure that the object is renderer at full opacity
    displayObject.worldAlpha = 1;

    // Time to update all the children of the displayObject with the new matrix..
    var children = displayObject.children;
    var i, j;

    for (i = 0, j = children.length; i < j; ++i)
    {
        children[i].updateTransform();
    }

    // time for the webGL fun stuff!
    var gl = this.renderer.gl;

    gl.viewport(0, 0, this.width, this.height);

    gl.bindFramebuffer(gl.FRAMEBUFFER, this.textureBuffer.frameBuffer );

    if (clear)
    {
        this.textureBuffer.clear();
    }

//    this.renderer.spriteRenderer.dirty = true;

    this.renderer.renderDisplayObject(displayObject, this.textureBuffer);//this.projection, this.textureBuffer.frameBuffer);

  //  this.renderer.spriteRenderer.dirty = true;

    if (restoreWorldTransform)
    {
        displayObject.worldAlpha = tempAlpha;
        displayObject.worldTransform.fromArray(tempTransform);

        for (i = 0, j = children.length; i < j; ++i)
        {
            children[i].updateTransform();
        }
    }
};

/**
 * Internal method assigned to the `render` property if using a CanvasRenderer.
 *
 * @private
 * @param displayObject {DisplayObject} The display object to render this texture on
 * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering.
 * @param [clear] {boolean} If true the texture will be cleared before the displayObject is drawn
 */
RenderTexture.prototype.renderCanvas = function (displayObject, matrix, clear)
{
    if (!this.valid)
    {
        return;
    }

    var wt = displayObject.worldTransform;

    wt.identity();

    if (matrix)
    {
        wt.append(matrix);
    }

    // setWorld Alpha to ensure that the object is renderer at full opacity
    displayObject.worldAlpha = 1;

    // Time to update all the children of the displayObject with the new matrix..
    var children = displayObject.children;
    var i, j;

    for (i = 0, j = children.length; i < j; ++i)
    {
        children[i].updateTransform();
    }

    if (clear)
    {
        this.textureBuffer.clear();
    }

    this.renderer.renderDisplayObject(displayObject, this.textureBuffer.context);

};

RenderTexture.prototype.destroy = function ()
{
    Texture.prototype.destroy.call(this, true);

    this.textureBuffer.destroy();

    this.renderer = null;
};

/**
 * Will return a HTML Image of the texture
 *
 * @return {Image}
 */
RenderTexture.prototype.getImage = function ()
{
    var image = new Image();
    image.src = this.getBase64();
    return image;
};

/**
 * Will return a a base64 encoded string of this texture. It works by calling RenderTexture.getCanvas and then running toDataURL on that.
 *
 * @return {string} A base64 encoded string of the texture.
 */
RenderTexture.prototype.getBase64 = function ()
{
    return this.getCanvas().toDataURL();
};

/**
 * Creates a Canvas element, renders this RenderTexture to it and then returns it.
 *
 * @return {HTMLCanvasElement} A Canvas element with the texture rendered on.
 */
RenderTexture.prototype.getCanvas = function ()
{
    if (this.renderer.type === CONST.RENDERER_TYPE.WEBGL)
    {
        var gl =  this.renderer.gl;
        var width = this.textureBuffer.width;
        var height = this.textureBuffer.height;

        var webGLPixels = new Uint8Array(4 * width * height);

        gl.bindFramebuffer(gl.FRAMEBUFFER, this.textureBuffer.frameBuffer);
        gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, webGLPixels);
        gl.bindFramebuffer(gl.FRAMEBUFFER, null);

        var tempCanvas = new CanvasBuffer(width, height);
        var canvasData = tempCanvas.context.getImageData(0, 0, width, height);
        canvasData.data.set(webGLPixels);

        tempCanvas.context.putImageData(canvasData, 0, 0);

        return tempCanvas.canvas;
    }
    else
    {
        return this.textureBuffer.canvas;
    }
};
<commit_msg>Upstream RenderTexture cleaning<commit_after>var BaseTexture = require('./BaseTexture'),
    Texture = require('./Texture'),
    RenderTarget = require('../renderers/webgl/utils/RenderTarget'),
    CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'),
    math = require('../math'),
    CONST = require('../const');

/**
 * A RenderTexture is a special texture that allows any Pixi display object to be rendered to it.
 *
 * __Hint__: All DisplayObjects (i.e. Sprites) that render to a RenderTexture should be preloaded
 * otherwise black rectangles will be drawn instead.
 *
 * A RenderTexture takes a snapshot of any Display Object given to its render method. The position
 * and rotation of the given Display Objects is ignored. For example:
 *
 * ```js
 * var renderTexture = new PIXI.RenderTexture(800, 600);
 * var sprite = PIXI.Sprite.fromImage("spinObj_01.png");
 *
 * sprite.position.x = 800/2;
 * sprite.position.y = 600/2;
 * sprite.anchor.x = 0.5;
 * sprite.anchor.y = 0.5;
 *
 * renderTexture.render(sprite);
 * ```
 *
 * The Sprite in this case will be rendered to a position of 0,0. To render this sprite at its actual
 * position a Container should be used:
 *
 * ```js
 * var doc = new Container();
 *
 * doc.addChild(sprite);
 *
 * renderTexture.render(doc);  // Renders to center of renderTexture
 * ```
 *
 * @class
 * @extends Texture
 * @namespace PIXI
 * @param renderer {CanvasRenderer|WebGLRenderer} The renderer used for this RenderTexture
 * @param [width=100] {number} The width of the render texture
 * @param [height=100] {number} The height of the render texture
 * @param [scaleMode] {number} See {@link scaleModes} for possible values
 */
function RenderTexture(renderer, width, height, scaleMode)
{
    if (!renderer)
    {
        throw new Error('Unable to create RenderTexture, you must pass a renderer into the constructor.');
    }

    width = width || 100;
    height = height || 100;

    /**
     * The base texture object that this texture uses
     *
     * @member {BaseTexture}
     */
    var baseTexture = new BaseTexture();
    baseTexture.width = width;
    baseTexture.height = height;
    baseTexture.scaleMode = scaleMode || CONST.scaleModes.DEFAULT;
    baseTexture.hasLoaded = true;

    Texture.call(this,
        baseTexture,
        new math.Rectangle(0, 0, width, height)
    );

    /**
     * The with of the render texture
     *
     * @member {number}
     */
    this.width = width;

    /**
     * The height of the render texture
     *
     * @member {number}
     */
    this.height = height;

    /**
     * The framing rectangle of the render texture
     *
     * @member {Rectangle}
     */
    //this._frame = new math.Rectangle(0, 0, this.width, this.height);

    /**
     * This is the area of the BaseTexture image to actually copy to the Canvas / WebGL when rendering,
     * irrespective of the actual frame size or placement (which can be influenced by trimmed texture atlases)
     *
     * @member {Rectangle}
     */
    //this.crop = new math.Rectangle(0, 0, this.width, this.height);

    /**
     * Draw/render the given DisplayObject onto the texture.
     *
     * The displayObject and descendents are transformed during this operation.
     * If `restoreWorldTransform` is true then the transformations will be restored before the
     * method returns. Otherwise it is up to the calling code to correctly use or reset
     * the transformed display objects.
     *
     * The display object is always rendered with a worldAlpha value of 1.
     *
     * @method
     * @param displayObject {DisplayObject} The display object to render this texture on
     * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering.
     * @param [clear=false] {boolean} If true the texture will be cleared before the displayObject is drawn
     * @param [restoreWorldTransform=true] {boolean} If true the displayObject's worldTransform/worldAlpha and all children
     *  transformations will be restored. Not restoring this information will be a little faster.
     */
    this.render = null;

    /**
     * The renderer this RenderTexture uses. A RenderTexture can only belong to one renderer at the moment if its webGL.
     *
     * @member {CanvasRenderer|WebGLRenderer}
     */
    this.renderer = renderer;

    if (this.renderer.type === CONST.RENDERER_TYPE.WEBGL)
    {
        var gl = this.renderer.gl;

        this.textureBuffer = new RenderTarget(gl, this.width, this.height);//, this.baseTexture.scaleMode);
        this.baseTexture._glTextures[gl.id] =  this.textureBuffer.texture;

        this.render = this.renderWebGL;
    }
    else
    {

        this.render = this.renderCanvas;
        this.textureBuffer = new CanvasBuffer(this.width, this.height);
        this.baseTexture.source = this.textureBuffer.canvas;
    }

    /**
     * @member {boolean}
     */
    this.valid = true;

    this._updateUvs();
}

RenderTexture.prototype = Object.create(Texture.prototype);
RenderTexture.prototype.constructor = RenderTexture;
module.exports = RenderTexture;

/**
 * Resizes the RenderTexture.
 *
 * @param width {number} The width to resize to.
 * @param height {number} The height to resize to.
 * @param updateBase {boolean} Should the baseTexture.width and height values be resized as well?
 */
RenderTexture.prototype.resize = function (width, height, updateBase)
{
    if (width === this.width && height === this.height)
    {
        return;
    }

    this.valid = (width > 0 && height > 0);

    this.width = this._frame.width = this.crop.width = width;
    this.height =  this._frame.height = this.crop.height = height;

    if (updateBase)
    {
        this.baseTexture.width = this.width;
        this.baseTexture.height = this.height;
    }

    if (this.renderer.type === CONST.RENDERER_TYPE.WEBGL)
    {
        this.projection.x = this.width / 2;
        this.projection.y = -this.height / 2;
    }

    if (!this.valid)
    {
        return;
    }

    this.textureBuffer.resize(this.width, this.height);
};

/**
 * Clears the RenderTexture.
 *
 */
RenderTexture.prototype.clear = function ()
{
    if (!this.valid)
    {
        return;
    }

    if (this.renderer.type === CONST.RENDERER_TYPE.WEBGL)
    {
        this.renderer.gl.bindFramebuffer(this.renderer.gl.FRAMEBUFFER, this.textureBuffer.frameBuffer);
    }

    this.textureBuffer.clear();
};

/**
 * Internal method assigned to the `render` property if using a CanvasRenderer.
 *
 * @private
 * @param displayObject {DisplayObject} The display object to render this texture on
 * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering.
 * @param [clear=false] {boolean} If true the texture will be cleared before the displayObject is drawn
 * @param [restoreWorldTransform=true] {boolean} If true the displayObject's worldTransform/worldAlpha and all children
 *  transformations will be restored. Not restoring this information will be a little faster.
 */
RenderTexture.prototype.renderWebGL = function (displayObject, matrix, clear, restoreWorldTransform)
{
    if (!this.valid)
    {
        return;
    }

    if (typeof restoreWorldTransform === 'undefined')
    {
        restoreWorldTransform = true;
    }

    var tempAlpha,
        tempTransform;

    if (restoreWorldTransform)
    {
        tempAlpha = displayObject.worldAlpha;
        tempTransform = displayObject.worldTransform.toArray();
    }

    //TOOD replace position with matrix..

    //Lets create a nice matrix to apply to our display object. Frame buffers come in upside down so we need to flip the matrix
    var wt = displayObject.worldTransform;

    wt.identity();

    if (matrix)
    {
        wt.append(matrix);
    }

    // setWorld Alpha to ensure that the object is renderer at full opacity
    displayObject.worldAlpha = 1;

    // Time to update all the children of the displayObject with the new matrix..
    var children = displayObject.children;
    var i, j;

    for (i = 0, j = children.length; i < j; ++i)
    {
        children[i].updateTransform();
    }

    if (clear)
    {
        this.textureBuffer.clear();
    }

    this.renderer.renderDisplayObject(displayObject, this.textureBuffer);

    if (restoreWorldTransform)
    {
        displayObject.worldAlpha = tempAlpha;
        displayObject.worldTransform.fromArray(tempTransform);

        for (i = 0, j = children.length; i < j; ++i)
        {
            children[i].updateTransform();
        }
    }
};

/**
 * Internal method assigned to the `render` property if using a CanvasRenderer.
 *
 * @private
 * @param displayObject {DisplayObject} The display object to render this texture on
 * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering.
 * @param [clear] {boolean} If true the texture will be cleared before the displayObject is drawn
 */
RenderTexture.prototype.renderCanvas = function (displayObject, matrix, clear)
{
    if (!this.valid)
    {
        return;
    }

    var wt = displayObject.worldTransform;

    wt.identity();

    if (matrix)
    {
        wt.append(matrix);
    }

    // setWorld Alpha to ensure that the object is renderer at full opacity
    displayObject.worldAlpha = 1;

    // Time to update all the children of the displayObject with the new matrix..
    var children = displayObject.children;
    var i, j;

    for (i = 0, j = children.length; i < j; ++i)
    {
        children[i].updateTransform();
    }

    if (clear)
    {
        this.textureBuffer.clear();
    }

    this.renderer.renderDisplayObject(displayObject, this.textureBuffer.context);

};

RenderTexture.prototype.destroy = function ()
{
    Texture.prototype.destroy.call(this, true);

    this.textureBuffer.destroy();

    this.renderer = null;
};

/**
 * Will return a HTML Image of the texture
 *
 * @return {Image}
 */
RenderTexture.prototype.getImage = function ()
{
    var image = new Image();
    image.src = this.getBase64();
    return image;
};

/**
 * Will return a a base64 encoded string of this texture. It works by calling RenderTexture.getCanvas and then running toDataURL on that.
 *
 * @return {string} A base64 encoded string of the texture.
 */
RenderTexture.prototype.getBase64 = function ()
{
    return this.getCanvas().toDataURL();
};

/**
 * Creates a Canvas element, renders this RenderTexture to it and then returns it.
 *
 * @return {HTMLCanvasElement} A Canvas element with the texture rendered on.
 */
RenderTexture.prototype.getCanvas = function ()
{
    if (this.renderer.type === CONST.RENDERER_TYPE.WEBGL)
    {
        var gl = this.renderer.gl;
        var width = this.textureBuffer.width;
        var height = this.textureBuffer.height;

        var webGLPixels = new Uint8Array(4 * width * height);

        gl.bindFramebuffer(gl.FRAMEBUFFER, this.textureBuffer.frameBuffer);
        gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, webGLPixels);
        gl.bindFramebuffer(gl.FRAMEBUFFER, null);

        var tempCanvas = new CanvasBuffer(width, height);
        var canvasData = tempCanvas.context.getImageData(0, 0, width, height);
        canvasData.data.set(webGLPixels);

        tempCanvas.context.putImageData(canvasData, 0, 0);

        return tempCanvas.canvas;
    }
    else
    {
        return this.textureBuffer.canvas;
    }
};
<|endoftext|>


<commit_before>//About dialog
;(function(){

var d,ta //DOM elements for the dialog and the textarea
D.abt=function(){
  if(!d){
    d=document.getElementById('abt')
    document.getElementById('abt_close').onclick=function(){d.hidden=1}
    document.getElementById('abt_copy').onclick=function(){D.el.clipboard.writeText(ta.value)}
    document.getElementById('abt_contact').onclick=
      function(x){if(x.target.nodeName==='A'&&/^http/.test(x.target.href)){D.openExternal(x.target.href);return!1}}
    ta=document.getElementById('abt_ta')
  }
  D.util.dlg(d)
  var v=D.versionInfo,ri=D.remoteIdentification||{},u='unknown',db=D.db||localStorage,repr=JSON.stringify
  var s='';for(var i=0;i<db.length;i++){var x=db.key(i);s+=(i?',\n':'')+'    '+repr(x)+':'+repr(db.getItem(x))}
  ta.value='IDE:'+
    '\n  Version: '   +(v.version          ||u)+
    '\n  Platform: '  +(navigator.platform ||u)+
    '\n  Date: '      +(v.date             ||u)+
    '\n  Git commit: '+(v.rev              ||u)+
    '\n  User agent: '+(navigator.userAgent||u)+
    '\n  Settings:{\n'+s+'\n  }\n'+
    '\nInterpreter:'  +
    '\n  Version: '   +(ri.version         ||u)+
    '\n  Platform: '  +(ri.platform        ||u)+
    '\n  Edition: '   +(ri.arch            ||u)+
    '\n  Date: '      +(ri.date            ||u)+'\n'
  ta.focus();ta.select()
}

}())
<commit_msg>focus Copy button in About by default<commit_after>//About dialog
;(function(){

var d,ta //DOM elements for the dialog and the textarea
D.abt=function(){
  if(!d){
    d=document.getElementById('abt')
    document.getElementById('abt_close').onclick=function(){d.hidden=1}
    document.getElementById('abt_copy').onclick=function(){D.el.clipboard.writeText(ta.value)}
    document.getElementById('abt_contact').onclick=
      function(x){if(x.target.nodeName==='A'&&/^http/.test(x.target.href)){D.openExternal(x.target.href);return!1}}
    ta=document.getElementById('abt_ta')
  }
  D.util.dlg(d)
  var v=D.versionInfo,ri=D.remoteIdentification||{},u='unknown',db=D.db||localStorage,repr=JSON.stringify
  var s='';for(var i=0;i<db.length;i++){var x=db.key(i);s+=(i?',\n':'')+'    '+repr(x)+':'+repr(db.getItem(x))}
  ta.value='IDE:'+
    '\n  Version: '   +(v.version          ||u)+
    '\n  Platform: '  +(navigator.platform ||u)+
    '\n  Date: '      +(v.date             ||u)+
    '\n  Git commit: '+(v.rev              ||u)+
    '\n  User agent: '+(navigator.userAgent||u)+
    '\n  Settings:{\n'+s+'\n  }\n'+
    '\nInterpreter:'  +
    '\n  Version: '   +(ri.version         ||u)+
    '\n  Platform: '  +(ri.platform        ||u)+
    '\n  Edition: '   +(ri.arch            ||u)+
    '\n  Date: '      +(ri.date            ||u)+'\n'
  ta.scrollTop=ta.selectionStart=ta.selectionEnd=0;document.getElementById('abt_copy').focus()
}

}())
<|endoftext|>


<commit_before>import FS from "fs";
import Path from "path";
import _ from "lodash-fp";
import { split } from "../helpers";

export const title = "Day 7: Some Assembly Required";

const operators = {
    "AND": (x, y) => x & y,
    "OR": (x, y) => x | y,
    "LSHIFT": (x, y) => x << y,
    "RSHIFT": (x, y) => x >> y,
    "NOT": (x) => ~x
};

function lookupValues(scope, values) {
    return values
        .match(/([A-Z]+)|([0-9]+)/gi)
        .map((x) => {
            const value = parseInt(x, 10);
            return (isNaN(value)) ? scope[x] : value;
        });
}

const maxValue = Math.pow(2, 16);

function wrapValue(value, max) {
   return ((value % max) + max) % max;
}

export function execute(baseScope, instruction) {
    const scope = _.clone(baseScope);
    const [operation, identifier] = _.map(_.trim, split("->", instruction));
    const constant = parseInt(operation, 10);

    // It's a simple value assignment.
    if (!isNaN(constant)) {
        scope[identifier] = wrapValue(parseInt(operation, 10), maxValue);

        return scope;
    }

    // Get the operator function.
    const pattern = new RegExp(`(${Object.keys(operators).join("|")})`, "g");
    const [name] = operation.match(pattern);
    const operator = operators[name];

    // Parse the values so we are working with constants.
    const values = lookupValues(scope, operation.replace(name, ""));

    // Pass the values to the operator and create / update the value in scope.
    scope[identifier] = wrapValue(operator(...values), maxValue);

    return scope;
}

export function run() {
    const inputPath = Path.join(__dirname, "input.txt");
    const input = FS.readFileSync(inputPath, "utf-8").trim().split("\n");

    console.log("In little Bobby's kit's instructions booklet, what signal is ultimately provided to wire a?");
}
<commit_msg>Now supports variable lookup assignment.<commit_after>import FS from "fs";
import Path from "path";
import _ from "lodash-fp";
import { split } from "../helpers";

export const title = "Day 7: Some Assembly Required";

const operators = {
    "AND": (x, y) => x & y,
    "OR": (x, y) => x | y,
    "LSHIFT": (x, y) => x << y,
    "RSHIFT": (x, y) => x >> y,
    "NOT": (x) => ~x
};

function lookupValues(scope, values) {
    return values
        .match(/([A-Z]+)|([0-9]+)/gi)
        .map((x) => {
            const value = parseInt(x, 10);
            return (isNaN(value)) ? scope[x] : value;
        });
}

const maxValue = Math.pow(2, 16);

function wrapValue(value, max) {
   return ((value % max) + max) % max;
}

export function execute(baseScope, instruction) {
    const scope = _.clone(baseScope);
    const [operation, identifier] = _.map(_.trim, split("->", instruction));
    const constant = parseInt(operation, 10);

    // Get the operator function.
    const pattern = new RegExp(`(${Object.keys(operators).join("|")})`, "g");
    const match = operation.match(pattern);

    // Here, 'operation' is either a constant or an identifier.
    if (!match) {
        scope[identifier] = wrapValue(lookupValues(scope, operation)[0], maxValue);

        return scope;
    }

    const [name] = match;
    const operator = operators[name];

    // Parse the values so we are working with constants.
    const values = lookupValues(scope, operation.replace(name, ""));

    // Pass the values to the operator and create / update the value in scope.
    scope[identifier] = wrapValue(operator(...values), maxValue);

    return scope;
}

export function run() {
    const inputPath = Path.join(__dirname, "input.txt");
    const input = FS.readFileSync(inputPath, "utf-8").trim().split("\n");
    let scope = {};

    // Build up the scope object through each instruction.
    input.forEach((x) => scope = execute(scope, x));

    console.log("In little Bobby's kit's instructions booklet, what signal is ultimately provided to wire a?", scope["a"]);
}
<|endoftext|>


<commit_before>import btod from "./btod";
import formatDefault from "./formatDefault";
import formatGroup from "./formatGroup";
import formatRounded from "./formatRounded";
import formatRoundedPercentage from "./formatRoundedPercentage";
import formatSystem from "./formatSystem";

// [[fill]align][sign][symbol][0][width][,][.precision][type]
var formatRe = /(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i;

var formatTypes = {
  "b": function(x) { return x.toString(2); },
  "c": function(x) { return String.fromCharCode(x); },
  "o": function(x) { return x.toString(8); },
  "x": function(x) { return x.toString(16); },
  "X": function(x) { return x.toString(16).toUpperCase(); },
  "g": function(x, p) { return x.toPrecision(p); },
  "e": function(x, p) { return x.toExponential(p); },
  "f": function(x, p) { return x.toFixed(p); },
  "%": function(x, p) { return (x * 100).toFixed(p); },
  "p": formatRoundedPercentage,
  "r": formatRounded,
  "s": formatSystem
};

function identity(x) {
  return x;
}

export default function(locale) {
  var group = locale.grouping && locale.thousands ? formatGroup(locale.grouping, locale.thousands) : identity,
      currency = locale.currency,
      decimal = locale.decimal;

  return function(specifier) {
    var match = formatRe.exec(specifier),
        fill = match[1] || " ",
        align = match[2] || ">",
        sign = match[3] || "-",
        symbol = match[4] || "",
        zero = match[5],
        width = +match[6],
        comma = match[7],
        precision = match[8],
        type = match[9] || "";

    // The "n" type is an alias for ",g".
    if (type === "n") comma = true, type = "g";

    // If zero fill is specified, padding goes after sign and before digits.
    if (zero || (fill === "0" && align === "=")) zero = fill = "0", align = "=";

    // Clamp the specified precision to the supported range.
    // For significant precision, it must be in [1, 21].
    // For fixed precision, it must be in [0, 20].
    if (precision) {
      precision = +precision.substring(1);
      precision = /[gprs]/.test(type)
          ? Math.max(1, Math.min(21, precision))
          : Math.max(0, Math.min(20, precision));
    }

    // Compute the fixed prefix and suffix.
    var prefix = symbol === "$" ? currency[0] : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
        suffix = symbol === "$" ? currency[1] : /[%p]/.test(type) ? "%" : "";

    // Is this an integer type? Can this type generate exponential notation?
    var integer = /[bcdoxX]/.test(type),
        maybeDecimal = !type || /[defgprs%]/.test(type),
        maybeExponent = !type || /[deg]/.test(type);

    type = formatTypes[type] || formatDefault;

    return function(value) {
      value = +value;

      // Return the empty string for floats formatted as ints.
      if (integer && (value % 1)) return "";

      // Convert negative to positive, and record the sign.
      // Note that -0 is not less than 0, but 1 / -0 is!
      var valueSign = value < 0 || 1 / value < 0 ? (value *= -1, "-")
          : sign === "-" ? ""
          : sign;

      // Perform the initial formatting.
      var before = value = type(value, precision),
          after = suffix;

      // Break the value into the integer “before” part that can be grouped,
      // and fractional and exponential “after” part that is not grouped.
      if (maybeDecimal) {
        var i = value.indexOf(".");
        if (i < 0) {
          if (maybeExponent) {
            var j = value.indexOf("e");
            if (j >= 0) {
              before = value.substring(0, j);
              after = value.substring(j) + suffix;
            }
          }
        } else {
          before = value.substring(0, i);
          after = decimal + value.substring(i + 1) + suffix;
        }
      }

      // If the fill character is not "0", grouping is applied before padding.
      if (comma && !zero) before = group(before, Infinity);

      // Compute the padding.
      var length = (comma && zero ? 0 : valueSign.length) + prefix.length + before.length + after.length,
          padding = length < width ? new Array(length = width - length + 1).join(fill) : "";

      // If the fill character is "0", grouping is applied after padding.
      if (comma && zero) before = group(padding + before, padding.length ? width - after.length : Infinity);

      // Reconstruct the final output based on the desired alignment.
      valueSign += prefix;
      value = before + after;
      return align === "<" ? valueSign + value + padding
          : align === ">" ? padding + valueSign + value
          : align === "^" ? padding.substring(0, length >>= 1) + valueSign + value + padding.substring(length)
          : valueSign + (zero && comma ? value : padding + value);
    };
  };
};
<commit_msg>Cleaner.<commit_after>import btod from "./btod";
import formatDefault from "./formatDefault";
import formatGroup from "./formatGroup";
import formatRounded from "./formatRounded";
import formatRoundedPercentage from "./formatRoundedPercentage";
import formatSystem from "./formatSystem";

// [[fill]align][sign][symbol][0][width][,][.precision][type]
var formatRe = /(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i;

var formatTypes = {
  "b": function(x) { return x.toString(2); },
  "c": function(x) { return String.fromCharCode(x); },
  "o": function(x) { return x.toString(8); },
  "x": function(x) { return x.toString(16); },
  "X": function(x) { return x.toString(16).toUpperCase(); },
  "g": function(x, p) { return x.toPrecision(p); },
  "e": function(x, p) { return x.toExponential(p); },
  "f": function(x, p) { return x.toFixed(p); },
  "%": function(x, p) { return (x * 100).toFixed(p); },
  "p": formatRoundedPercentage,
  "r": formatRounded,
  "s": formatSystem
};

function identity(x) {
  return x;
}

export default function(locale) {
  var group = locale.grouping && locale.thousands ? formatGroup(locale.grouping, locale.thousands) : identity,
      currency = locale.currency,
      decimal = locale.decimal;

  return function(specifier) {
    var match = formatRe.exec(specifier),
        fill = match[1] || " ",
        align = match[2] || ">",
        sign = match[3] || "-",
        symbol = match[4] || "",
        zero = match[5],
        width = +match[6],
        comma = match[7],
        precision = match[8],
        type = match[9] || "";

    // The "n" type is an alias for ",g".
    if (type === "n") comma = true, type = "g";

    // If zero fill is specified, padding goes after sign and before digits.
    if (zero || (fill === "0" && align === "=")) zero = fill = "0", align = "=";

    // Clamp the specified precision to the supported range.
    // For significant precision, it must be in [1, 21].
    // For fixed precision, it must be in [0, 20].
    if (precision) {
      precision = +precision.substring(1);
      precision = /[gprs]/.test(type)
          ? Math.max(1, Math.min(21, precision))
          : Math.max(0, Math.min(20, precision));
    }

    // Compute the fixed prefix and suffix.
    var prefix = symbol === "$" ? currency[0] : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
        suffix = symbol === "$" ? currency[1] : /[%p]/.test(type) ? "%" : "";

    // Is this an integer type?
    // Can this type generate exponential notation?
    // What format function should we use?
    var integer = /[bcdoxX]/.test(type),
        maybeDecimal = !type || /[defgprs%]/.test(type),
        maybeExponent = !type || /[deg]/.test(type),
        format = formatTypes[type] || formatDefault;

    return function(value) {
      value = +value;

      // Return the empty string for floats formatted as ints.
      if (integer && (value % 1)) return "";

      // Convert negative to positive, and record the sign.
      // Note that -0 is not less than 0, but 1 / -0 is!
      var valueSign = value < 0 || 1 / value < 0 ? (value *= -1, "-")
          : sign === "-" ? ""
          : sign;

      // Perform the initial formatting.
      var before = value = format(value, precision),
          after = suffix;

      // Break the value into the integer “before” part that can be grouped,
      // and fractional and exponential “after” part that is not grouped.
      if (maybeDecimal) {
        var i = value.indexOf(".");
        if (i < 0) {
          if (maybeExponent) {
            var j = value.indexOf("e");
            if (j >= 0) {
              before = value.substring(0, j);
              after = value.substring(j) + suffix;
            }
          }
        } else {
          before = value.substring(0, i);
          after = decimal + value.substring(i + 1) + suffix;
        }
      }

      // If the fill character is not "0", grouping is applied before padding.
      if (comma && !zero) before = group(before, Infinity);

      // Compute the padding.
      var length = (comma && zero ? 0 : valueSign.length) + prefix.length + before.length + after.length,
          padding = length < width ? new Array(length = width - length + 1).join(fill) : "";

      // If the fill character is "0", grouping is applied after padding.
      if (comma && zero) before = group(padding + before, padding.length ? width - after.length : Infinity), padding = "";

      // Reconstruct the final output based on the desired alignment.
      return align === "<" ? valueSign + prefix + before + after + padding
          : align === ">" ? padding + valueSign + prefix + before + after
          : align === "^" ? padding.substring(0, length >>= 1) + valueSign + prefix + before + after + padding.substring(length)
          : valueSign + prefix + padding + before + after;
    };
  };
};
<|endoftext|>


<commit_before>var Observable = require('../utils').Observable,
    bcrypt = require('bcrypt'),
    crypto = require('crypto');

module.exports = Observable.extend({
  constructor: function UserModel(store) {
    Observable.call(this);
    this.store = store;
  },
  load: function (id, fn) {
    this.store.getUser(id, fn);
  },
  loadByEmail: function (email, fn) {
    this.store.getUserByEmail(email, fn);
  },
  create: function (data, fn) {
    var hash = bcrypt.hash.bind(bcrypt, data.key),
        store = this.store;

    this.hash(data.key, function (err, hash) {
      if (err) {
        return fn(err);
      }
      data.key = hash;
      store.setUser(data, fn);
    });
  },
  updateEmail: function (id, email, fn) {
    this.store.updateUserEmail(id, email, fn);
  },
  updateKey: function (id, key, fn, upgrade) {
    var store = this.store;
    this.hash(key, function (err, hash) {
      if (err) {
        return fn(err);
      }

      // We're upgrading an old account.
      if (upgrade === true) {
        store.upgradeUserKey(id, hash, fn);
      } else {
        store.updateUserKey(id, hash, fn);
      }
    });
  },
  // Upgrades the user from a JSBin 2 account.
  upgradeKey: function (id, key, fn) {
    this.updateKey(id, key, fn, true);
  },
  getLatestBin: function (id, fn) {
    this.store.getLatestBinForUser(id, fn);
  },
  getBins: function (id, fn) {
    this.store.getBinsByUser(id, fn);
  },
  setBinOwner: function (id, bin, fn) {
    var params = {
      name: id,
      url: bin.url,
      revision: bin.revision,
      summary: bin.summary,
      html: !!bin.html,
      css: !!bin.css,
      javascript: !!bin.javascript
    };
    this.store.setBinOwner(params, fn);
  },
  touchLogin: function (id, fn) {
    this.store.touchLogin(id, fn);
  },
  touchOwners: function (id, bin, fn) {
    var params = {
      name: id,
      url: bin.url,
      revision: bin.revision
    };
    this.store.touchOwners(params, fn);
  },
  updateOwners: function (id, bin, fn) {
    var params = {
      name: id,
      url: bin.url,
      revision: bin.revision,
      summary: bin.summary,
      panel: bin.panel,
      panel_open: bin.panel_open
    };
    this.store.updateOwners(params, fn);
  },
  valid: function (key, encrypted, fn) {
    return bcrypt.compare(key, encrypted, fn);
  },
  hash: function (key, fn) {
    bcrypt.genSalt(function (err, salt) {
      if (err) {
        return fn(err);
      }
      bcrypt.hash(key, salt, fn);
    });
  },
  validOldKey: function (key, encrypted) {
    return encrypted === crypto.createHash('sha1').update(key).digest('hex');
  }
});
<commit_msg>Track user query times.<commit_after>var Observable = require('../utils').Observable,
    metrics = require('../metrics'),
    metric_prefix = 'timer.user.',
    bcrypt = require('bcrypt'),
    crypto = require('crypto');

module.exports = Observable.extend({
  constructor: function UserModel(store) {
    Observable.call(this);
    this.store = store;
  },
  load: function (id, fn) {
    this.store.getUser(id, fn);
  },
  loadByEmail: function (email, fn) {
    this.store.getUserByEmail(email, fn);
  },
  create: function (data, fn) {
    var hash = bcrypt.hash.bind(bcrypt, data.key),
        store = this.store;

    this.hash(data.key, function (err, hash) {
      if (err) {
        return fn(err);
      }
      data.key = hash;
      store.setUser(data, fn);
    });
  },
  updateEmail: function (id, email, fn) {
    this.store.updateUserEmail(id, email, fn);
  },
  updateKey: function (id, key, fn, upgrade) {
    var store = this.store;
    this.hash(key, function (err, hash) {
      if (err) {
        return fn(err);
      }

      // We're upgrading an old account.
      if (upgrade === true) {
        store.upgradeUserKey(id, hash, fn);
      } else {
        store.updateUserKey(id, hash, fn);
      }
    });
  },
  // Upgrades the user from a JSBin 2 account.
  upgradeKey: function (id, key, fn) {
    this.updateKey(id, key, fn, true);
  },
  getLatestBin: function (id, fn) {
    var timer = metrics.createTimer(metric_prefix + 'getLatestBin');
    var original = fn;
    fn = function () {
      timer.stop();
      original.apply(this, [].slice.call(arguments));
    };
    this.store.getLatestBinForUser(id, fn);
  },
  getBins: function (id, fn) {
    var timer = metrics.createTimer(metric_prefix + 'getBins');
    var original = fn;
    fn = function () {
      timer.stop();
      original.apply(this, [].slice.call(arguments));
    };
    this.store.getBinsByUser(id, fn);
  },
  setBinOwner: function (id, bin, fn) {
    var params = {
      name: id,
      url: bin.url,
      revision: bin.revision,
      summary: bin.summary,
      html: !!bin.html,
      css: !!bin.css,
      javascript: !!bin.javascript
    };
    var timer = metrics.createTimer(metric_prefix + 'setBinOwner');
    var original = fn;
    fn = function () {
      timer.stop();
      original.apply(this, [].slice.call(arguments));
    };
    this.store.setBinOwner(params, fn);
  },
  touchLogin: function (id, fn) {
    var timer = metrics.createTimer(metric_prefix + 'touchLogin');
    var original = fn;
    fn = function () {
      timer.stop();
      original.apply(this, [].slice.call(arguments));
    };
    this.store.touchLogin(id, fn);
  },
  touchOwners: function (id, bin, fn) {
    var params = {
      name: id,
      url: bin.url,
      revision: bin.revision
    };
    var timer = metrics.createTimer(metric_prefix + 'touchOwners');
    var original = fn;
    fn = function () {
      timer.stop();
      original.apply(this, [].slice.call(arguments));
    };
    this.store.touchOwners(params, fn);
  },
  updateOwners: function (id, bin, fn) {
    var params = {
      name: id,
      url: bin.url,
      revision: bin.revision,
      summary: bin.summary,
      panel: bin.panel,
      panel_open: bin.panel_open
    };
    var timer = metrics.createTimer(metric_prefix + 'updateOwners');
    var original = fn;
    fn = function () {
      timer.stop();
      original.apply(this, [].slice.call(arguments));
    };
    this.store.updateOwners(params, fn);
  },
  valid: function (key, encrypted, fn) {
    return bcrypt.compare(key, encrypted, fn);
  },
  hash: function (key, fn) {
    bcrypt.genSalt(function (err, salt) {
      if (err) {
        return fn(err);
      }
      bcrypt.hash(key, salt, fn);
    });
  },
  validOldKey: function (key, encrypted) {
    return encrypted === crypto.createHash('sha1').update(key).digest('hex');
  }
});
<|endoftext|>


<commit_before>/*!
 * Brica Project
 * Copyright(c) 2017-2017 Brian Ping
 */

'use strict';

/****************************************************************
 *  Dependency                                                  *
 ***************************************************************/
var TvSony = require('../plugin/tvSony');
var MiHome = require('../plugin/miHome');

var DeviceConf = require('../config/device.conf.js')
var RuntimeConf = require('../config/runtime.conf.js')

/****************************************************************
 *  Function Implementation                                     *
 ***************************************************************/
exports.prcsRoleAction = function (role, intent) {

  console.log(role + ' will ' + intent );

  var device = DeviceConf[role];

  if (device == undefined) {
    return new Error('Undefined role: ' + role);
  }

  console.log('Type: ' + device.type  );

  if (device.type == RuntimeConf.DeviceType.Televison.Type) {

    if (device.brand == RuntimeConf.DeviceType.Televison.BrandType.Sony) {
      TvSony(device.ip, device.token, function(tvDevice) {
        // Call a command
        tvDevice.exec(intent);
      });

    }
    else {
      return new Error('Invalid brand: ' + device.brand + ' of ' + device.type);
    }

  }
  else if ( device.type == RuntimeConf.DeviceType.MiHome.Type) {

    MiHome(role, device.ip, '0000', device.token, device.subType)
    .then (returnObj => {
            returnObj.exec(intent);
          })
    .catch(err => {
          console.error(this.name + " init error: " + err);
        });
    //var device = MiHome(role, device.ip, '0000', device.token, device.subType);

    //device.exec(intent);
  }
  else {
    return new Error('Invalid type: ' + device.type);
  }

  return;
}
<commit_msg>update mihome index<commit_after>/*!
 * Brica Project
 * Copyright(c) 2017-2017 Brian Ping
 */

'use strict';

/****************************************************************
 *  Dependency                                                  *
 ***************************************************************/
var TvSony = require('../plugin/tvSony');
var MiHome = require('../plugin/miHome');

var DeviceConf = require('../config/device.conf.js')
var RuntimeConf = require('../config/runtime.conf.js')

/****************************************************************
 *  Function Implementation                                     *
 ***************************************************************/
exports.prcsRoleAction = function (role, intent) {

  console.log(role + ' will ' + intent );

  var device = DeviceConf[role];

  if (device == undefined) {
    return new Error('Undefined role: ' + role);
  }

  console.log('Type: ' + device.type  );

  if (device.type == RuntimeConf.DeviceType.Televison.Type) {

    if (device.brand == RuntimeConf.DeviceType.Televison.BrandType.Sony) {
      TvSony(device.ip, device.token, function(tvDevice) {
        // Call a command
        tvDevice.exec(intent);
      });

    }
    else {
      return new Error('Invalid brand: ' + device.brand + ' of ' + device.type);
    }

  }
  else if ( device.type == RuntimeConf.DeviceType.MiHome.Type) {

    var tmp = new MiHome(role, device.ip, '0000', device.token, device.subType)
    .then (returnObj => {
            returnObj.exec(intent);
          })
    .catch(err => {
          console.error(this.name + " init error: " + err);
        });
    //var device = MiHome(role, device.ip, '0000', device.token, device.subType);

    //device.exec(intent);
  }
  else {
    return new Error('Invalid type: ' + device.type);
  }

  return;
}
<|endoftext|>


<commit_before>'use strict';

/**
 * Requirements
 * @ignore
 */
const Base = require('../Base.js').Base;
const chalk = require('chalk');
const minimatch = require('minimatch');
const fs = require('fs');

/**
 * @class
 * @memberOf utils
 * @extends {Base}
 */
class PerformanceMetricScope extends Base
{
    /**
     * @ignore
     */
    constructor(name, parent)
    {
        super();
        this._name = name || 'root';
        this._parent = parent;
        this._items = {};
    }

    /**
     * @inheritDoc
     */
    static get className()
    {
        return 'utils/PerformanceMetricScope';
    }

    /**
     * @let {String}
     */
    get name()
    {
        return this._name;
    }

    /**
     * @let {PerformanceMetrics}
     */
    get parent()
    {
        return this._parent;
    }

    /**
     * @let {Map}
     */
    get items()
    {
        return this._items;
    }

    /**
     * Clears all recorded timers
     */
    clear()
    {
        this._items = {};
    }

    /**
     * Renders all recorded timers to the console
     */
    show(patterns)
    {
        // eslint-disable-next-line no-console
        console.log(chalk.bold('\n' + this.name + ' Timers:'));
        for (const name in this.items)
        {
            const item = this.items[name];
            let display = true;
            if (patterns)
            {
                display = false;
                for (const pattern of patterns)
                {
                    if (item.name.includes(pattern) || minimatch(item.name, pattern))
                    {
                        display = true;
                    }
                }
            }
            if (display)
            {
                // eslint-disable-next-line no-console
                console.log(chalk.yellow(' ' + item.name));
                // eslint-disable-next-line no-console
                console.log('  count: ' + item.count + ', average: ' + item.average.toFixed(2) + ', total: ' + item.total);
            }
        }
    }

    /**
     * Saves all recorded timers to a json file.
     * If the file exists the timers will be appended
     */
    save(filename, label)
    {
        let data = [];
        if (fs.existsSync(filename))
        {
            data = JSON.parse(fs.readFileSync(filename, { encoding: 'utf8' }));
        }
        data.push(
            {
                date: Date.now(),
                label: label,
                timers: this.items
            });
        fs.writeFileSync(filename, JSON.stringify(data, null, 4), { encoding: 'utf8' });
    }

    /**
     * Starts a timer
     *
     * @param {String} name
     */
    start(name)
    {
        if (!this.items[name])
        {
            this.items[name] =
            {
                name: name,
                current: 0,
                count: 0,
                total: 0,
                min: 0,
                max: 0,
                average: 0
            };
        }
        this.stop(name);
        if (this.parent)
        {
            this.parent.start(name);
        }
        const item = this.items[name];
        item.current = Date.now();
    }

    /**
     * Stops a timer
     *
     * @param {String} name
     */
    stop(name)
    {
        if (this.parent)
        {
            this.parent.stop(name);
        }
        const item = this.items[name];
        if (!item || item.current == 0)
        {
            return;
        }
        const time = (Date.now() - item.current);
        item.total+= time;
        item.count++;
        item.current = 0;
        item.min = Math.min(item.min, time);
        item.max = Math.max(item.max, time);
        item.average = item.total / item.count;
    }
}

/**
 * @class
 * @memberOf utils
 * @extends {Base}
 */
class PerformanceMetrics extends Base
{
    /**
     * @ignore
     */
    constructor(name, parent)
    {
        super();
        this._current = new PerformanceMetricScope();
        this._enabled = false;
    }

    /**
     * @inheritDoc
     */
    static get className()
    {
        return 'utils/PerformanceMetrics';
    }

    /**
     * @let {PerformanceMetricScope}
     */
    get current()
    {
        return this._current;
    }

    /**
     * @let {Boolean}
     */
    get enabled()
    {
        return this._enabled;
    }

    /**
     * Enables performance metrics
     */
    enable(name)
    {
        this._enabled = true;
    }

    /**
     * Enables performance metrics
     */
    disable()
    {
        this._enabled = false;
    }

    /**
     * Creates a new logging scope
     *
     * @param {String} name
     */
    pushScope(name)
    {
        if (!this.enabled)
        {
            return;
        }

        this._current = new PerformanceMetricScope(name, this._current);
    }

    /**
     * Removes the top most logging scope
     */
    popScope()
    {
        if (!this.enabled)
        {
            return;
        }

        this._current = this._current.parent;
    }

    /**
     * Renders all recorded timers to the console
     */
    show(patterns)
    {
        if (!this.enabled)
        {
            return;
        }
        this.current.show(patterns);
    }

    /**
     * Renders all recorded timers to the console
     */
    save(filename, label)
    {
        if (!this.enabled)
        {
            return;
        }
        this.current.save(filename, label);
    }

    /**
     * Starts a timer
     *
     * @param {String} name
     */
    start(name)
    {
        if (!this.enabled)
        {
            return;
        }

        this.current.start(name);
    }

    /**
     * Stops a timer
     *
     * @param {String} name
     */
    stop(name)
    {
        if (!this.enabled)
        {
            return;
        }

        this.current.stop(name);
    }
}

/**
 * Exports
 * @ignore
 */
module.exports.PerformanceMetricScope = PerformanceMetricScope;
module.exports.PerformanceMetrics = PerformanceMetrics;
module.exports.metrics = new PerformanceMetrics();
module.exports.__metrics = new PerformanceMetrics();
<commit_msg>fix(utils.performance): use more precise timer<commit_after>'use strict';

/**
 * Requirements
 * @ignore
 */
const Base = require('../Base.js').Base;
const chalk = require('chalk');
const minimatch = require('minimatch');
const fs = require('fs');
const now = require('performance-now');

/**
 * @class
 * @memberOf utils
 * @extends {Base}
 */
class PerformanceMetricScope extends Base
{
    /**
     * @ignore
     */
    constructor(name, parent)
    {
        super();
        this._name = name || 'root';
        this._parent = parent;
        this._items = {};
    }

    /**
     * @inheritDoc
     */
    static get className()
    {
        return 'utils/PerformanceMetricScope';
    }

    /**
     * @let {String}
     */
    get name()
    {
        return this._name;
    }

    /**
     * @let {PerformanceMetrics}
     */
    get parent()
    {
        return this._parent;
    }

    /**
     * @let {Map}
     */
    get items()
    {
        return this._items;
    }

    /**
     * Clears all recorded timers
     */
    clear()
    {
        this._items = {};
    }

    /**
     * Renders all recorded timers to the console
     */
    show(patterns)
    {
        // eslint-disable-next-line no-console
        console.log(chalk.bold('\n' + this.name + ' Timers:'));
        for (const name in this.items)
        {
            const item = this.items[name];
            let display = true;
            if (patterns)
            {
                display = false;
                for (const pattern of patterns)
                {
                    if (item.name.includes(pattern) || minimatch(item.name, pattern))
                    {
                        display = true;
                    }
                }
            }
            if (display)
            {
                // eslint-disable-next-line no-console
                console.log(chalk.yellow(' ' + item.name));
                // eslint-disable-next-line no-console
                console.log('  count: ' + item.count + ', average: ' + item.average.toFixed(2) + ', total: ' + item.total);
            }
        }
    }

    /**
     * Saves all recorded timers to a json file.
     * If the file exists the timers will be appended
     */
    save(filename, label)
    {
        let data = [];
        if (fs.existsSync(filename))
        {
            data = JSON.parse(fs.readFileSync(filename, { encoding: 'utf8' }));
        }
        data.push(
            {
                date: Date.now(),
                label: label,
                timers: this.items
            });
        fs.writeFileSync(filename, JSON.stringify(data, null, 4), { encoding: 'utf8' });
    }

    /**
     * Starts a timer
     *
     * @param {String} name
     */
    start(name)
    {
        if (!this.items[name])
        {
            this.items[name] =
            {
                name: name,
                current: 0,
                count: 0,
                total: 0,
                min: Number.MAX_VALUE,
                max: 0,
                average: 0,
            };
        }
        this.stop(name);
        if (this.parent)
        {
            this.parent.start(name);
        }
        const item = this.items[name];
        item.current = now();
    }

    /**
     * Stops a timer
     *
     * @param {String} name
     */
    stop(name)
    {
        if (this.parent)
        {
            this.parent.stop(name);
        }
        const item = this.items[name];
        if (!item || item.current == 0)
        {
            return;
        }
        const time = (now() - item.current);
        item.total+= time;
        item.count++;
        item.current = 0;
        item.min = Math.min(item.min, time);
        item.max = Math.max(item.max, time);
        item.average = item.total / item.count;
    }
}

/**
 * @class
 * @memberOf utils
 * @extends {Base}
 */
class PerformanceMetrics extends Base
{
    /**
     * @ignore
     */
    constructor(name, parent)
    {
        super();
        this._current = new PerformanceMetricScope();
        this._enabled = false;
    }

    /**
     * @inheritDoc
     */
    static get className()
    {
        return 'utils/PerformanceMetrics';
    }

    /**
     * @let {PerformanceMetricScope}
     */
    get current()
    {
        return this._current;
    }

    /**
     * @let {Boolean}
     */
    get enabled()
    {
        return this._enabled;
    }

    /**
     * Enables performance metrics
     */
    enable(name)
    {
        this._enabled = true;
    }

    /**
     * Enables performance metrics
     */
    disable()
    {
        this._enabled = false;
    }

    /**
     * Creates a new logging scope
     *
     * @param {String} name
     */
    pushScope(name)
    {
        if (!this.enabled)
        {
            return;
        }

        this._current = new PerformanceMetricScope(name, this._current);
    }

    /**
     * Removes the top most logging scope
     */
    popScope()
    {
        if (!this.enabled)
        {
            return;
        }

        this._current = this._current.parent;
    }

    /**
     * Renders all recorded timers to the console
     */
    show(patterns)
    {
        if (!this.enabled)
        {
            return;
        }
        this.current.show(patterns);
    }

    /**
     * Renders all recorded timers to the console
     */
    save(filename, label)
    {
        if (!this.enabled)
        {
            return;
        }
        this.current.save(filename, label);
    }

    /**
     * Starts a timer
     *
     * @param {String} name
     */
    start(name)
    {
        if (!this.enabled)
        {
            return;
        }

        this.current.start(name);
    }

    /**
     * Stops a timer
     *
     * @param {String} name
     */
    stop(name)
    {
        if (!this.enabled)
        {
            return;
        }

        this.current.stop(name);
    }
}

/**
 * Exports
 * @ignore
 */
module.exports.PerformanceMetricScope = PerformanceMetricScope;
module.exports.PerformanceMetrics = PerformanceMetrics;
module.exports.metrics = new PerformanceMetrics();
module.exports.__metrics = new PerformanceMetrics();
<|endoftext|>