<commit_before>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF 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.
*/

import {__DEV__} from '../config';
import * as zrUtil from 'zrender/src/core/util';
import OrdinalScale from '../scale/Ordinal';
import IntervalScale from '../scale/Interval';
import Scale from '../scale/Scale';
import * as numberUtil from '../util/number';
import {
    prepareLayoutBarSeries,
    makeColumnLayout,
    retrieveColumnLayout
} from '../layout/barGrid';
import BoundingRect from 'zrender/src/core/BoundingRect';

import '../scale/Time';
import '../scale/Log';

/**
 * Get axis scale extent before niced.
 * Item of returned array can only be number (including Infinity and NaN).
 */
export function getScaleExtent(scale, model) {
    var scaleType = scale.type;

    var min = model.getMin();
    var max = model.getMax();
    var fixMin = min != null;
    var fixMax = max != null;
    var originalExtent = scale.getExtent();

    var axisDataLen;
    var boundaryGap;
    var span;
    if (scaleType === 'ordinal') {
        axisDataLen = model.getCategories().length;
    }
    else {
        boundaryGap = model.get('boundaryGap');
        if (!zrUtil.isArray(boundaryGap)) {
            boundaryGap = [boundaryGap || 0, boundaryGap || 0];
        }
        if (typeof boundaryGap[0] === 'boolean') {
            if (__DEV__) {
                console.warn('Boolean type for boundaryGap is only '
                    + 'allowed for ordinal axis. Please use string in '
                    + 'percentage instead, e.g., "20%". Currently, '
                    + 'boundaryGap is set to be 0.');
            }
            boundaryGap = [0, 0];
        }
        boundaryGap[0] = numberUtil.parsePercent(boundaryGap[0], 1);
        boundaryGap[1] = numberUtil.parsePercent(boundaryGap[1], 1);
        span = (originalExtent[1] - originalExtent[0])
            || Math.abs(originalExtent[0]);
    }

    // Notice: When min/max is not set (that is, when there are null/undefined,
    // which is the most common case), these cases should be ensured:
    // (1) For 'ordinal', show all axis.data.
    // (2) For others:
    //      + `boundaryGap` is applied (if min/max set, boundaryGap is
    //      disabled).
    //      + If `needCrossZero`, min/max should be zero, otherwise, min/max should
    //      be the result that originalExtent enlarged by boundaryGap.
    // (3) If no data, it should be ensured that `scale.setBlank` is set.

    // FIXME
    // (1) When min/max is 'dataMin' or 'dataMax', should boundaryGap be able to used?
    // (2) When `needCrossZero` and all data is positive/negative, should it be ensured
    // that the results processed by boundaryGap are positive/negative?

    if (min == null) {
        min = scaleType === 'ordinal'
            ? (axisDataLen ? 0 : NaN)
            : originalExtent[0] - boundaryGap[0] * span;
    }
    if (max == null) {
        max = scaleType === 'ordinal'
            ? (axisDataLen ? axisDataLen - 1 : NaN)
            : originalExtent[1] + boundaryGap[1] * span;
    }

    if (min === 'dataMin') {
        min = originalExtent[0];
    }
    else if (typeof min === 'function') {
        min = min({
            min: originalExtent[0],
            max: originalExtent[1]
        });
    }

    if (max === 'dataMax') {
        max = originalExtent[1];
    }
    else if (typeof max === 'function') {
        max = max({
            min: originalExtent[0],
            max: originalExtent[1]
        });
    }

    (min == null || !isFinite(min)) && (min = NaN);
    (max == null || !isFinite(max)) && (max = NaN);

    scale.setBlank(
        zrUtil.eqNaN(min)
        || zrUtil.eqNaN(max)
        || (scaleType === 'ordinal' && !scale.getOrdinalMeta().categories.length)
    );

    // Evaluate if axis needs cross zero
    if (model.getNeedCrossZero()) {
        // Axis is over zero and min is not set
        if (min > 0 && max > 0 && !fixMin) {
            min = 0;
        }
        // Axis is under zero and max is not set
        if (min < 0 && max < 0 && !fixMax) {
            max = 0;
        }
    }

    // If bars are placed on a base axis of type time or interval account for axis boundary overflow and current axis
    // is base axis
    // FIXME
    // (1) Consider support value axis, where below zero and axis `onZero` should be handled properly.
    // (2) Refactor the logic with `barGrid`. Is it not need to `makeBarWidthAndOffsetInfo` twice with different extent?
    //     Should not depend on series type `bar`?
    // (3) Fix that might overlap when using dataZoom.
    // (4) Consider other chart types using `barGrid`?
    // See #6728, #4862, `test/bar-overflow-time-plot.html`
    var ecModel = model.ecModel;
    if (ecModel && (scaleType === 'time' /*|| scaleType === 'interval' */)) {
        var barSeriesModels = prepareLayoutBarSeries('bar', ecModel);
        var isBaseAxisAndHasBarSeries;

        zrUtil.each(barSeriesModels, function (seriesModel) {
            isBaseAxisAndHasBarSeries |= seriesModel.getBaseAxis() === model.axis;
        });

        if (isBaseAxisAndHasBarSeries) {
            // Calculate placement of bars on axis
            var barWidthAndOffset = makeColumnLayout(barSeriesModels);

            // Adjust axis min and max to account for overflow
            var adjustedScale = adjustScaleForOverflow(min, max, model, barWidthAndOffset);
            min = adjustedScale.min;
            max = adjustedScale.max;
        }
    }

    return [min, max];
}

function adjustScaleForOverflow(min, max, model, barWidthAndOffset) {

    // Get Axis Length
    var axisExtent = model.axis.getExtent();
    var axisLength = axisExtent[1] - axisExtent[0];

    // Get bars on current base axis and calculate min and max overflow
    var barsOnCurrentAxis = retrieveColumnLayout(barWidthAndOffset, model.axis);
    if (barsOnCurrentAxis === undefined) {
        return {min: min, max: max};
    }

    var minOverflow = Infinity;
    zrUtil.each(barsOnCurrentAxis, function (item) {
        minOverflow = Math.min(item.offset, minOverflow);
    });
    var maxOverflow = -Infinity;
    zrUtil.each(barsOnCurrentAxis, function (item) {
        maxOverflow = Math.max(item.offset + item.width, maxOverflow);
    });
    minOverflow = Math.abs(minOverflow);
    maxOverflow = Math.abs(maxOverflow);
    var totalOverFlow = minOverflow + maxOverflow;

    // Calulate required buffer based on old range and overflow
    var oldRange = max - min;
    var oldRangePercentOfNew = (1 - (minOverflow + maxOverflow) / axisLength);
    var overflowBuffer = ((oldRange / oldRangePercentOfNew) - oldRange);

    max += overflowBuffer * (maxOverflow / totalOverFlow);
    min -= overflowBuffer * (minOverflow / totalOverFlow);

    return {min: min, max: max};
}

export function niceScaleExtent(scale, model) {
    var extent = getScaleExtent(scale, model);
    var fixMin = model.getMin() != null;
    var fixMax = model.getMax() != null;
    var splitNumber = model.get('splitNumber');

    if (scale.type === 'log') {
        scale.base = model.get('logBase');
    }

    var scaleType = scale.type;
    scale.setExtent(extent[0], extent[1]);
    scale.niceExtent({
        splitNumber: splitNumber,
        fixMin: fixMin,
        fixMax: fixMax,
        minInterval: (scaleType === 'interval' || scaleType === 'time')
            ? model.get('minInterval') : null,
        maxInterval: (scaleType === 'interval' || scaleType === 'time')
            ? model.get('maxInterval') : null
    });

    // If some one specified the min, max. And the default calculated interval
    // is not good enough. He can specify the interval. It is often appeared
    // in angle axis with angle 0 - 360. Interval calculated in interval scale is hard
    // to be 60.
    // FIXME
    var interval = model.get('interval');
    if (interval != null) {
        scale.setInterval && scale.setInterval(interval);
    }
}

/**
 * @param {module:echarts/model/Model} model
 * @param {string} [axisType] Default retrieve from model.type
 * @return {module:echarts/scale/*}
 */
export function createScaleByModel(model, axisType) {
    axisType = axisType || model.get('type');
    if (axisType) {
        switch (axisType) {
            // Buildin scale
            case 'category':
                return new OrdinalScale(
                    model.getOrdinalMeta
                        ? model.getOrdinalMeta()
                        : model.getCategories(),
                    [Infinity, -Infinity]
                );
            case 'value':
                return new IntervalScale();
            // Extended scale, like time and log
            default:
                return (Scale.getClass(axisType) || IntervalScale).create(model);
        }
    }
}

/**
 * Check if the axis corss 0
 */
export function ifAxisCrossZero(axis) {
    var dataExtent = axis.scale.getExtent();
    var min = dataExtent[0];
    var max = dataExtent[1];
    return !((min > 0 && max > 0) || (min < 0 && max < 0));
}

/**
 * @param {module:echarts/coord/Axis} axis
 * @return {Function} Label formatter function.
 *         param: {number} tickValue,
 *         param: {number} idx, the index in all ticks.
 *                         If category axis, this param is not requied.
 *         return: {string} label string.
 */
export function makeLabelFormatter(axis) {
    var labelFormatter = axis.getLabelModel().get('formatter');
    var categoryTickStart = axis.type === 'category' ? axis.scale.getExtent()[0] : null;

    if (typeof labelFormatter === 'string') {
        labelFormatter = (function (tpl) {
            return function (val) {
                // For category axis, get raw value; for numeric axis,
                // get foramtted label like '1,333,444'.
                val = axis.scale.getLabel(val);
                return tpl.replace('{value}', val != null ? val : '');
            };
        })(labelFormatter);
        // Consider empty array
        return labelFormatter;
    }
    else if (typeof labelFormatter === 'function') {
        return function (tickValue, idx) {
            // The original intention of `idx` is "the index of the tick in all ticks".
            // But the previous implementation of category axis do not consider the
            // `axisLabel.interval`, which cause that, for example, the `interval` is
            // `1`, then the ticks "name5", "name7", "name9" are displayed, where the
            // corresponding `idx` are `0`, `2`, `4`, but not `0`, `1`, `2`. So we keep
            // the definition here for back compatibility.
            if (categoryTickStart != null) {
                idx = tickValue - categoryTickStart;
            }
            return labelFormatter(getAxisRawValue(axis, tickValue), idx);
        };
    }
    else {
        return function (tick) {
            return axis.scale.getLabel(tick);
        };
    }
}

export function getAxisRawValue(axis, value) {
    // In category axis with data zoom, tick is not the original
    // index of axis.data. So tick should not be exposed to user
    // in category axis.
    return axis.type === 'category' ? axis.scale.getLabel(value) : value;
}

/**
 * @param {module:echarts/coord/Axis} axis
 * @return {module:zrender/core/BoundingRect} Be null/undefined if no labels.
 */
export function estimateLabelUnionRect(axis) {
    var axisModel = axis.model;
    var scale = axis.scale;

    if (!axisModel.get('axisLabel.show') || scale.isBlank()) {
        return;
    }

    var isCategory = axis.type === 'category';

    var realNumberScaleTicks;
    var tickCount;
    var categoryScaleExtent = scale.getExtent();

    // Optimize for large category data, avoid call `getTicks()`.
    if (isCategory) {
        tickCount = scale.count();
    }
    else {
        realNumberScaleTicks = scale.getTicks();
        tickCount = realNumberScaleTicks.length;
    }

    var axisLabelModel = axis.getLabelModel();
    var labelFormatter = makeLabelFormatter(axis);

    var rect;
    var step = 1;
    // Simple optimization for large amount of labels
    if (tickCount > 40) {
        step = Math.ceil(tickCount / 40);
    }
    for (var i = 0; i < tickCount; i += step) {
        var tickValue = realNumberScaleTicks ? realNumberScaleTicks[i] : categoryScaleExtent[0] + i;
        var label = labelFormatter(tickValue);
        var unrotatedSingleRect = axisLabelModel.getTextRect(label);
        var singleRect = rotateTextRect(unrotatedSingleRect, axisLabelModel.get('rotate') || 0);

        rect ? rect.union(singleRect) : (rect = singleRect);
    }

    return rect;
}

function rotateTextRect(textRect, rotate) {
    var rotateRadians = rotate * Math.PI / 180;
    var boundingBox = textRect.plain();
    var beforeWidth = boundingBox.width;
    var beforeHeight = boundingBox.height;
    var afterWidth = beforeWidth * Math.cos(rotateRadians) + beforeHeight * Math.sin(rotateRadians);
    var afterHeight = beforeWidth * Math.sin(rotateRadians) + beforeHeight * Math.cos(rotateRadians);
    var rotatedRect = new BoundingRect(boundingBox.x, boundingBox.y, afterWidth, afterHeight);

    return rotatedRect;
}

/**
 * @param {module:echarts/src/model/Model} model axisLabelModel or axisTickModel
 * @return {number|String} Can be null|'auto'|number|function
 */
export function getOptionCategoryInterval(model) {
    var interval = model.get('interval');
    return interval == null ? 'auto' : interval;
}

/**
 * Set `categoryInterval` as 0 implicitly indicates that
 * show all labels reguardless of overlap.
 * @param {Object} axis axisModel.axis
 * @return {boolean}
 */
export function shouldShowAllLabels(axis) {
    return axis.type === 'category'
        && getOptionCategoryInterval(axis.getLabelModel()) === 0;
}

<commit_msg>Feat: use auto calculate if min /max is null<commit_after>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF 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.
*/

import {__DEV__} from '../config';
import * as zrUtil from 'zrender/src/core/util';
import OrdinalScale from '../scale/Ordinal';
import IntervalScale from '../scale/Interval';
import Scale from '../scale/Scale';
import * as numberUtil from '../util/number';
import {
    prepareLayoutBarSeries,
    makeColumnLayout,
    retrieveColumnLayout
} from '../layout/barGrid';
import BoundingRect from 'zrender/src/core/BoundingRect';

import '../scale/Time';
import '../scale/Log';

/**
 * Get axis scale extent before niced.
 * Item of returned array can only be number (including Infinity and NaN).
 */
export function getScaleExtent(scale, model) {
    var scaleType = scale.type;

    var min = model.getMin();
    var max = model.getMax();
    var originalExtent = scale.getExtent();

    var axisDataLen;
    var boundaryGap;
    var span;
    if (scaleType === 'ordinal') {
        axisDataLen = model.getCategories().length;
    }
    else {
        boundaryGap = model.get('boundaryGap');
        if (!zrUtil.isArray(boundaryGap)) {
            boundaryGap = [boundaryGap || 0, boundaryGap || 0];
        }
        if (typeof boundaryGap[0] === 'boolean') {
            if (__DEV__) {
                console.warn('Boolean type for boundaryGap is only '
                    + 'allowed for ordinal axis. Please use string in '
                    + 'percentage instead, e.g., "20%". Currently, '
                    + 'boundaryGap is set to be 0.');
            }
            boundaryGap = [0, 0];
        }
        boundaryGap[0] = numberUtil.parsePercent(boundaryGap[0], 1);
        boundaryGap[1] = numberUtil.parsePercent(boundaryGap[1], 1);
        span = (originalExtent[1] - originalExtent[0])
            || Math.abs(originalExtent[0]);
    }

    // Notice: When min/max is not set (that is, when there are null/undefined,
    // which is the most common case), these cases should be ensured:
    // (1) For 'ordinal', show all axis.data.
    // (2) For others:
    //      + `boundaryGap` is applied (if min/max set, boundaryGap is
    //      disabled).
    //      + If `needCrossZero`, min/max should be zero, otherwise, min/max should
    //      be the result that originalExtent enlarged by boundaryGap.
    // (3) If no data, it should be ensured that `scale.setBlank` is set.

    // FIXME
    // (1) When min/max is 'dataMin' or 'dataMax', should boundaryGap be able to used?
    // (2) When `needCrossZero` and all data is positive/negative, should it be ensured
    // that the results processed by boundaryGap are positive/negative?

    if (min === 'dataMin') {
        min = originalExtent[0];
    }
    else if (typeof min === 'function') {
        min = min({
            min: originalExtent[0],
            max: originalExtent[1]
        });
    }

    if (max === 'dataMax') {
        max = originalExtent[1];
    }
    else if (typeof max === 'function') {
        max = max({
            min: originalExtent[0],
            max: originalExtent[1]
        });
    }

    if (min == null) {
        min = scaleType === 'ordinal'
            ? (axisDataLen ? 0 : NaN)
            : originalExtent[0] - boundaryGap[0] * span;
    }
    if (max == null) {
        max = scaleType === 'ordinal'
            ? (axisDataLen ? axisDataLen - 1 : NaN)
            : originalExtent[1] + boundaryGap[1] * span;
    }

    (min == null || !isFinite(min)) && (min = NaN);
    (max == null || !isFinite(max)) && (max = NaN);

    scale.setBlank(
        zrUtil.eqNaN(min)
        || zrUtil.eqNaN(max)
        || (scaleType === 'ordinal' && !scale.getOrdinalMeta().categories.length)
    );

    // Evaluate if axis needs cross zero
    if (model.getNeedCrossZero()) {
        // Axis is over zero and min is not set
        if (min > 0 && max > 0 && !(min != null)) {
            min = 0;
        }
        // Axis is under zero and max is not set
        if (min < 0 && max < 0 && !(max != null)) {
            max = 0;
        }
    }

    // If bars are placed on a base axis of type time or interval account for axis boundary overflow and current axis
    // is base axis
    // FIXME
    // (1) Consider support value axis, where below zero and axis `onZero` should be handled properly.
    // (2) Refactor the logic with `barGrid`. Is it not need to `makeBarWidthAndOffsetInfo` twice with different extent?
    //     Should not depend on series type `bar`?
    // (3) Fix that might overlap when using dataZoom.
    // (4) Consider other chart types using `barGrid`?
    // See #6728, #4862, `test/bar-overflow-time-plot.html`
    var ecModel = model.ecModel;
    if (ecModel && (scaleType === 'time' /*|| scaleType === 'interval' */)) {
        var barSeriesModels = prepareLayoutBarSeries('bar', ecModel);
        var isBaseAxisAndHasBarSeries;

        zrUtil.each(barSeriesModels, function (seriesModel) {
            isBaseAxisAndHasBarSeries |= seriesModel.getBaseAxis() === model.axis;
        });

        if (isBaseAxisAndHasBarSeries) {
            // Calculate placement of bars on axis
            var barWidthAndOffset = makeColumnLayout(barSeriesModels);

            // Adjust axis min and max to account for overflow
            var adjustedScale = adjustScaleForOverflow(min, max, model, barWidthAndOffset);
            min = adjustedScale.min;
            max = adjustedScale.max;
        }
    }

    return [min, max];
}

function adjustScaleForOverflow(min, max, model, barWidthAndOffset) {

    // Get Axis Length
    var axisExtent = model.axis.getExtent();
    var axisLength = axisExtent[1] - axisExtent[0];

    // Get bars on current base axis and calculate min and max overflow
    var barsOnCurrentAxis = retrieveColumnLayout(barWidthAndOffset, model.axis);
    if (barsOnCurrentAxis === undefined) {
        return {min: min, max: max};
    }

    var minOverflow = Infinity;
    zrUtil.each(barsOnCurrentAxis, function (item) {
        minOverflow = Math.min(item.offset, minOverflow);
    });
    var maxOverflow = -Infinity;
    zrUtil.each(barsOnCurrentAxis, function (item) {
        maxOverflow = Math.max(item.offset + item.width, maxOverflow);
    });
    minOverflow = Math.abs(minOverflow);
    maxOverflow = Math.abs(maxOverflow);
    var totalOverFlow = minOverflow + maxOverflow;

    // Calulate required buffer based on old range and overflow
    var oldRange = max - min;
    var oldRangePercentOfNew = (1 - (minOverflow + maxOverflow) / axisLength);
    var overflowBuffer = ((oldRange / oldRangePercentOfNew) - oldRange);

    max += overflowBuffer * (maxOverflow / totalOverFlow);
    min -= overflowBuffer * (minOverflow / totalOverFlow);

    return {min: min, max: max};
}

export function niceScaleExtent(scale, model) {
    var extent = getScaleExtent(scale, model);
    var min = model.getMin();
    var max = model.getMax();
    var originalExtent = scale.getExtent();

    if (typeof min === 'function') {
        min = min({
            min: originalExtent[0],
            max: originalExtent[1]
        });
    }

    if (typeof max === 'function') {
        max = max({
            min: originalExtent[0],
            max: originalExtent[1]
        });
    }

    var splitNumber = model.get('splitNumber');

    if (scale.type === 'log') {
        scale.base = model.get('logBase');
    }

    var scaleType = scale.type;
    scale.setExtent(extent[0], extent[1]);
    scale.niceExtent({
        splitNumber: splitNumber,
        fixMin: min != null,
        fixMax: max != null,
        minInterval: (scaleType === 'interval' || scaleType === 'time')
            ? model.get('minInterval') : null,
        maxInterval: (scaleType === 'interval' || scaleType === 'time')
            ? model.get('maxInterval') : null
    });

    // If some one specified the min, max. And the default calculated interval
    // is not good enough. He can specify the interval. It is often appeared
    // in angle axis with angle 0 - 360. Interval calculated in interval scale is hard
    // to be 60.
    // FIXME
    var interval = model.get('interval');
    if (interval != null) {
        scale.setInterval && scale.setInterval(interval);
    }
}

/**
 * @param {module:echarts/model/Model} model
 * @param {string} [axisType] Default retrieve from model.type
 * @return {module:echarts/scale/*}
 */
export function createScaleByModel(model, axisType) {
    axisType = axisType || model.get('type');
    if (axisType) {
        switch (axisType) {
            // Buildin scale
            case 'category':
                return new OrdinalScale(
                    model.getOrdinalMeta
                        ? model.getOrdinalMeta()
                        : model.getCategories(),
                    [Infinity, -Infinity]
                );
            case 'value':
                return new IntervalScale();
            // Extended scale, like time and log
            default:
                return (Scale.getClass(axisType) || IntervalScale).create(model);
        }
    }
}

/**
 * Check if the axis corss 0
 */
export function ifAxisCrossZero(axis) {
    var dataExtent = axis.scale.getExtent();
    var min = dataExtent[0];
    var max = dataExtent[1];
    return !((min > 0 && max > 0) || (min < 0 && max < 0));
}

/**
 * @param {module:echarts/coord/Axis} axis
 * @return {Function} Label formatter function.
 *         param: {number} tickValue,
 *         param: {number} idx, the index in all ticks.
 *                         If category axis, this param is not requied.
 *         return: {string} label string.
 */
export function makeLabelFormatter(axis) {
    var labelFormatter = axis.getLabelModel().get('formatter');
    var categoryTickStart = axis.type === 'category' ? axis.scale.getExtent()[0] : null;

    if (typeof labelFormatter === 'string') {
        labelFormatter = (function (tpl) {
            return function (val) {
                // For category axis, get raw value; for numeric axis,
                // get foramtted label like '1,333,444'.
                val = axis.scale.getLabel(val);
                return tpl.replace('{value}', val != null ? val : '');
            };
        })(labelFormatter);
        // Consider empty array
        return labelFormatter;
    }
    else if (typeof labelFormatter === 'function') {
        return function (tickValue, idx) {
            // The original intention of `idx` is "the index of the tick in all ticks".
            // But the previous implementation of category axis do not consider the
            // `axisLabel.interval`, which cause that, for example, the `interval` is
            // `1`, then the ticks "name5", "name7", "name9" are displayed, where the
            // corresponding `idx` are `0`, `2`, `4`, but not `0`, `1`, `2`. So we keep
            // the definition here for back compatibility.
            if (categoryTickStart != null) {
                idx = tickValue - categoryTickStart;
            }
            return labelFormatter(getAxisRawValue(axis, tickValue), idx);
        };
    }
    else {
        return function (tick) {
            return axis.scale.getLabel(tick);
        };
    }
}

export function getAxisRawValue(axis, value) {
    // In category axis with data zoom, tick is not the original
    // index of axis.data. So tick should not be exposed to user
    // in category axis.
    return axis.type === 'category' ? axis.scale.getLabel(value) : value;
}

/**
 * @param {module:echarts/coord/Axis} axis
 * @return {module:zrender/core/BoundingRect} Be null/undefined if no labels.
 */
export function estimateLabelUnionRect(axis) {
    var axisModel = axis.model;
    var scale = axis.scale;

    if (!axisModel.get('axisLabel.show') || scale.isBlank()) {
        return;
    }

    var isCategory = axis.type === 'category';

    var realNumberScaleTicks;
    var tickCount;
    var categoryScaleExtent = scale.getExtent();

    // Optimize for large category data, avoid call `getTicks()`.
    if (isCategory) {
        tickCount = scale.count();
    }
    else {
        realNumberScaleTicks = scale.getTicks();
        tickCount = realNumberScaleTicks.length;
    }

    var axisLabelModel = axis.getLabelModel();
    var labelFormatter = makeLabelFormatter(axis);

    var rect;
    var step = 1;
    // Simple optimization for large amount of labels
    if (tickCount > 40) {
        step = Math.ceil(tickCount / 40);
    }
    for (var i = 0; i < tickCount; i += step) {
        var tickValue = realNumberScaleTicks ? realNumberScaleTicks[i] : categoryScaleExtent[0] + i;
        var label = labelFormatter(tickValue);
        var unrotatedSingleRect = axisLabelModel.getTextRect(label);
        var singleRect = rotateTextRect(unrotatedSingleRect, axisLabelModel.get('rotate') || 0);

        rect ? rect.union(singleRect) : (rect = singleRect);
    }

    return rect;
}

function rotateTextRect(textRect, rotate) {
    var rotateRadians = rotate * Math.PI / 180;
    var boundingBox = textRect.plain();
    var beforeWidth = boundingBox.width;
    var beforeHeight = boundingBox.height;
    var afterWidth = beforeWidth * Math.cos(rotateRadians) + beforeHeight * Math.sin(rotateRadians);
    var afterHeight = beforeWidth * Math.sin(rotateRadians) + beforeHeight * Math.cos(rotateRadians);
    var rotatedRect = new BoundingRect(boundingBox.x, boundingBox.y, afterWidth, afterHeight);

    return rotatedRect;
}

/**
 * @param {module:echarts/src/model/Model} model axisLabelModel or axisTickModel
 * @return {number|String} Can be null|'auto'|number|function
 */
export function getOptionCategoryInterval(model) {
    var interval = model.get('interval');
    return interval == null ? 'auto' : interval;
}

/**
 * Set `categoryInterval` as 0 implicitly indicates that
 * show all labels reguardless of overlap.
 * @param {Object} axis axisModel.axis
 * @return {boolean}
 */
export function shouldShowAllLabels(axis) {
    return axis.type === 'category'
        && getOptionCategoryInterval(axis.getLabelModel()) === 0;
}

<|endoftext|>


<commit_before>/*
 * jQuery Timer Plugin
 * http://www.evanbot.com/article/jquery-timer-plugin/23
 *
 * @version      1.0
 * @copyright    2009 Evan Byrne (http://www.evanbot.com)
 */

jQuery.timer = function(time,func,callback){
        var a = {timer:setTimeout(func,time),callback:null}
        if(typeof(callback) == 'function'){a.callback = callback;}
        return a;
};

jQuery.clearTimer = function(a){
        clearTimeout(a.timer);
        if(typeof(a.callback) == 'function'){a.callback();};
        return this;
};

var twohanded = Object()
twohanded["A"] =  "twohanded/th_a.jpg";
twohanded["B"] =  "twohanded/th_b.jpg";
twohanded["C"] =  "twohanded/th_c.jpg";
twohanded["D"] =  "twohanded/th_d.jpg";
twohanded["E"] =  "twohanded/th_e.jpg";
twohanded["F"] =  "twohanded/th_f.jpg";
twohanded["G"] =  "twohanded/th_g.jpg";
twohanded["H"] =  ["twohanded/th_h0.jpg", "twohanded/th_h1.jpg",  "twohanded/th_h2.jpg", "twohanded/th_h3.jpg", "twohanded/th_h4.jpg"];
twohanded["I"] =  "twohanded/th_i.jpg";
twohanded["J"] =  ["twohanded/th_j0.jpg", "twohanded/th_j1.jpg", "twohanded/th_j2.jpg"];
twohanded["K"] =  "twohanded/th_k.jpg";
twohanded["L"] =  "twohanded/th_l.jpg";
twohanded["M"] =  "twohanded/th_m.jpg";
twohanded["N"] =  "twohanded/th_n.jpg";
twohanded["O"] =  "twohanded/th_o.jpg";
twohanded["P"] =  "twohanded/th_p.jpg";
twohanded["Q"] =  "twohanded/th_q.jpg";
twohanded["R"] =  "twohanded/th_r.jpg";
twohanded["S"] =  "twohanded/th_s.jpg";
twohanded["T"] =  "twohanded/th_t.jpg";
twohanded["U"] =  "twohanded/th_u.jpg";
twohanded["V"] =  "twohanded/th_v.jpg";
twohanded["W"] =  "twohanded/th_w.jpg";
twohanded["X"] =  "twohanded/th_x.jpg";
twohanded["Y"] =  "twohanded/th_y.jpg";
twohanded["Z"] =  "twohanded/th_z.jpg";
twohanded["transition"] = "twohanded/transition.jpg";

var onehanded = Object()
onehanded["A"] = "onehanded/oh_a.jpg";
onehanded["B"] = "onehanded/oh_b.jpg";
onehanded["C"] = "onehanded/oh_c.jpg";
onehanded["D"] = "onehanded/oh_d.jpg";
onehanded["E"] = "onehanded/oh_e.jpg";
onehanded["F"] = "onehanded/oh_f.jpg";
onehanded["G"] = "onehanded/oh_g.jpg";
onehanded["H"] = "onehanded/oh_h.jpg";
onehanded["I"] = "onehanded/oh_i.jpg";
onehanded["J"] = ["onehanded/oh_j0.jpg","onehanded/oh_j1.jpg","onehanded/oh_j2.jpg","onehanded/oh_j3.jpg"];
onehanded["K"] = "onehanded/oh_k.jpg";
onehanded["L"] = "onehanded/oh_l.jpg";
onehanded["M"] = "onehanded/oh_m.jpg";
onehanded["N"] = "onehanded/oh_n.jpg";
onehanded["O"] = "onehanded/oh_o.jpg";
onehanded["P"] = "onehanded/oh_p.jpg";
onehanded["Q"] = "onehanded/oh_q.jpg";
onehanded["R"] = "onehanded/oh_r.jpg";
onehanded["S"] = "onehanded/oh_s.jpg";
onehanded["T"] = "onehanded/oh_t.jpg";
onehanded["U"] = "onehanded/oh_u.jpg";
onehanded["V"] = "onehanded/oh_v.jpg";
onehanded["W"] = "onehanded/oh_w.jpg";
onehanded["X"] = "onehanded/oh_x.jpg";
onehanded["Y"] = "onehanded/oh_y.jpg";
onehanded["Z"] = ["onehanded/oh_z0.jpg", "onehanded/oh_z1.jpg", "onehanded/oh_z2.jpg", "onehanded/oh_z3.jpg"];
onehanded["transition"] = "onehanded/transition.jpg";

(function( $ ){

	  $.fn.fingerspellimage = function(baseurl, images) {
		    /* add a fingerspelling image and setup the binding */

		  	return this.each(function() {
				if ($(this).attr("class") != 'blank') {

			    	letter = $(this).attr("id");

					if (typeof(images[letter]) == 'object') {
					  imagesrc = images[letter][0];
					} else {
					  imagesrc = images[letter];
					}

					/* make a new image */
					var image = new Image();
					$(image).attr('src', baseurl+imagesrc);
					$(this).append(image);
					$(this).append("
"+letter+"
");
					$(this).click(function() {
						display_letter("#mainimg", $(this).attr("id"), 1500,  baseurl, images);
					});
				}
		  	});
		}

	})( jQuery );

function update_image(imageid, image) {

    $(imageid).attr('src', image);
}

/* an animation plan is a sequence of objects
   with properties:
   'src' - image source url
   'time' -- time in milliseconds to display

    we have two procedures, one to build a plan given
    a word, another to animate a plan
*/

function plan_string(str, speed, baseurl, images) {
    plan = [plan_transition(speed, baseurl)];
    for(var i=0; i<str.length; i++) {
        plan = plan.concat(plan_letter(str[i], speed, baseurl, images));
        /* insert a transition between letters */
        if (i<str.length-1) {
            plan = plan.concat(plan_transition(speed, baseurl));
        }
    }
    return plan;
}

function plan_transition(speed, baseurl) {
    return( [{src: baseurl+"twohanded/transition.jpg", time: speed/5}]);
}

function plan_letter(letter, speed, baseurl, images) {

    letter = letter.toUpperCase();

    if (images[letter] == undefined) {
        return plan_transition(speed, baseurl);
    }
    /* check if we have one or multiple images */
    if (typeof(images[letter]) == 'object') {
        /* a sequence, we animate them */
        imglist = images[letter];
        result = [];
        brieftime = speed/4;  /* ms time between images */

        for(var i=0; i<imglist.length; i++) {
            result.push({src: baseurl+imglist[i], time: brieftime});
        }

        return(result);

    } else {
        return([{src: baseurl+images[letter], time: speed}]);
    }
}

/* animate a plan
   show the first image,
   schedule animation of the remainder after the given delay
*/
function animate_plan(imageid, plan) {
    if (plan.length == 0) {
        return
    }
    step = plan.shift();
    update_image(imageid, step['src']);
    /* define a callback function to do the rest */
    var newfun = function () {
        animate_plan(imageid, plan);
    }
    /* schedule newfn in a bit */
    $.timer(step['time'], newfun);
}

function display_letter(imageid, letter, speed, baseurl, images) {
    plan = plan_letter(letter, speed, baseurl, images);
    animate_plan(imageid, plan);
}

function display_string(imageid, letter, speed, baseurl, images) {
    /* TODO: interrupt any playing animations before starting */
    plan = plan_string(letter, speed, baseurl, images);
    animate_plan(imageid, plan);
}

function fingerspell_play(baseurl, images) {
    $.mobile.silentScroll(0);
    speed = $('input:radio[name=speed]:checked').val();
    display_string("#mainimg", $('#text').val(), speed, baseurl, images);
    return false;
}

<commit_msg>Use blur() to try to close the keyboard on iphone after text input - needs testing<commit_after>/*
 * jQuery Timer Plugin
 * http://www.evanbot.com/article/jquery-timer-plugin/23
 *
 * @version      1.0
 * @copyright    2009 Evan Byrne (http://www.evanbot.com)
 */

jQuery.timer = function(time,func,callback){
        var a = {timer:setTimeout(func,time),callback:null}
        if(typeof(callback) == 'function'){a.callback = callback;}
        return a;
};

jQuery.clearTimer = function(a){
        clearTimeout(a.timer);
        if(typeof(a.callback) == 'function'){a.callback();};
        return this;
};

var twohanded = Object()
twohanded["A"] =  "twohanded/th_a.jpg";
twohanded["B"] =  "twohanded/th_b.jpg";
twohanded["C"] =  "twohanded/th_c.jpg";
twohanded["D"] =  "twohanded/th_d.jpg";
twohanded["E"] =  "twohanded/th_e.jpg";
twohanded["F"] =  "twohanded/th_f.jpg";
twohanded["G"] =  "twohanded/th_g.jpg";
twohanded["H"] =  ["twohanded/th_h0.jpg", "twohanded/th_h1.jpg",  "twohanded/th_h2.jpg", "twohanded/th_h3.jpg", "twohanded/th_h4.jpg"];
twohanded["I"] =  "twohanded/th_i.jpg";
twohanded["J"] =  ["twohanded/th_j0.jpg", "twohanded/th_j1.jpg", "twohanded/th_j2.jpg"];
twohanded["K"] =  "twohanded/th_k.jpg";
twohanded["L"] =  "twohanded/th_l.jpg";
twohanded["M"] =  "twohanded/th_m.jpg";
twohanded["N"] =  "twohanded/th_n.jpg";
twohanded["O"] =  "twohanded/th_o.jpg";
twohanded["P"] =  "twohanded/th_p.jpg";
twohanded["Q"] =  "twohanded/th_q.jpg";
twohanded["R"] =  "twohanded/th_r.jpg";
twohanded["S"] =  "twohanded/th_s.jpg";
twohanded["T"] =  "twohanded/th_t.jpg";
twohanded["U"] =  "twohanded/th_u.jpg";
twohanded["V"] =  "twohanded/th_v.jpg";
twohanded["W"] =  "twohanded/th_w.jpg";
twohanded["X"] =  "twohanded/th_x.jpg";
twohanded["Y"] =  "twohanded/th_y.jpg";
twohanded["Z"] =  "twohanded/th_z.jpg";
twohanded["transition"] = "twohanded/transition.jpg";

var onehanded = Object()
onehanded["A"] = "onehanded/oh_a.jpg";
onehanded["B"] = "onehanded/oh_b.jpg";
onehanded["C"] = "onehanded/oh_c.jpg";
onehanded["D"] = "onehanded/oh_d.jpg";
onehanded["E"] = "onehanded/oh_e.jpg";
onehanded["F"] = "onehanded/oh_f.jpg";
onehanded["G"] = "onehanded/oh_g.jpg";
onehanded["H"] = "onehanded/oh_h.jpg";
onehanded["I"] = "onehanded/oh_i.jpg";
onehanded["J"] = ["onehanded/oh_j0.jpg","onehanded/oh_j1.jpg","onehanded/oh_j2.jpg","onehanded/oh_j3.jpg"];
onehanded["K"] = "onehanded/oh_k.jpg";
onehanded["L"] = "onehanded/oh_l.jpg";
onehanded["M"] = "onehanded/oh_m.jpg";
onehanded["N"] = "onehanded/oh_n.jpg";
onehanded["O"] = "onehanded/oh_o.jpg";
onehanded["P"] = "onehanded/oh_p.jpg";
onehanded["Q"] = "onehanded/oh_q.jpg";
onehanded["R"] = "onehanded/oh_r.jpg";
onehanded["S"] = "onehanded/oh_s.jpg";
onehanded["T"] = "onehanded/oh_t.jpg";
onehanded["U"] = "onehanded/oh_u.jpg";
onehanded["V"] = "onehanded/oh_v.jpg";
onehanded["W"] = "onehanded/oh_w.jpg";
onehanded["X"] = "onehanded/oh_x.jpg";
onehanded["Y"] = "onehanded/oh_y.jpg";
onehanded["Z"] = ["onehanded/oh_z0.jpg", "onehanded/oh_z1.jpg", "onehanded/oh_z2.jpg", "onehanded/oh_z3.jpg"];
onehanded["transition"] = "onehanded/transition.jpg";

(function( $ ){

	  $.fn.fingerspellimage = function(baseurl, images) {
		    /* add a fingerspelling image and setup the binding */

		  	return this.each(function() {
				if ($(this).attr("class") != 'blank') {

			    	letter = $(this).attr("id");

					if (typeof(images[letter]) == 'object') {
					  imagesrc = images[letter][0];
					} else {
					  imagesrc = images[letter];
					}

					/* make a new image */
					var image = new Image();
					$(image).attr('src', baseurl+imagesrc);
					$(this).append(image);
					$(this).append("
"+letter+"
");
					$(this).click(function() {
						display_letter("#mainimg", $(this).attr("id"), 1500,  baseurl, images);
					});
				}
		  	});
		}

	})( jQuery );

function update_image(imageid, image) {

    $(imageid).attr('src', image);
}

/* an animation plan is a sequence of objects
   with properties:
   'src' - image source url
   'time' -- time in milliseconds to display

    we have two procedures, one to build a plan given
    a word, another to animate a plan
*/

function plan_string(str, speed, baseurl, images) {
    plan = [plan_transition(speed, baseurl)];
    for(var i=0; i<str.length; i++) {
        plan = plan.concat(plan_letter(str[i], speed, baseurl, images));
        /* insert a transition between letters */
        if (i<str.length-1) {
            plan = plan.concat(plan_transition(speed, baseurl));
        }
    }
    return plan;
}

function plan_transition(speed, baseurl) {
    return( [{src: baseurl+"twohanded/transition.jpg", time: speed/5}]);
}

function plan_letter(letter, speed, baseurl, images) {

    letter = letter.toUpperCase();

    if (images[letter] == undefined) {
        return plan_transition(speed, baseurl);
    }
    /* check if we have one or multiple images */
    if (typeof(images[letter]) == 'object') {
        /* a sequence, we animate them */
        imglist = images[letter];
        result = [];
        brieftime = speed/4;  /* ms time between images */

        for(var i=0; i<imglist.length; i++) {
            result.push({src: baseurl+imglist[i], time: brieftime});
        }

        return(result);

    } else {
        return([{src: baseurl+images[letter], time: speed}]);
    }
}

/* animate a plan
   show the first image,
   schedule animation of the remainder after the given delay
*/
function animate_plan(imageid, plan) {
    if (plan.length == 0) {
        return
    }
    step = plan.shift();
    update_image(imageid, step['src']);
    /* define a callback function to do the rest */
    var newfun = function () {
        animate_plan(imageid, plan);
    }
    /* schedule newfn in a bit */
    $.timer(step['time'], newfun);
}

function display_letter(imageid, letter, speed, baseurl, images) {
    plan = plan_letter(letter, speed, baseurl, images);
    animate_plan(imageid, plan);
}

function display_string(imageid, letter, speed, baseurl, images) {
    /* TODO: interrupt any playing animations before starting */
    plan = plan_string(letter, speed, baseurl, images);
    animate_plan(imageid, plan);
}

function fingerspell_play(baseurl, images) {
    $.mobile.silentScroll(0);
    $('#text').blur();  /* remove focus from the text box to force closing keyboard on iphone */
    speed = $('input:radio[name=speed]:checked').val();
    display_string("#mainimg", $('#text').val(), speed, baseurl, images);
    return false;
}

<|endoftext|>


<commit_before>/* @flow */
import React, { PropTypes, Component } from 'react';
import { Button, Input, Row, Col } from 'react-bootstrap';
import { FormattedMessage, intlShape, injectIntl } from 'react-intl';
import { generateValidation } from 'redux-form-validation';
import TextInput from 'components/FormFields/TextInput';
import HorizontalRadioGroup from 'components/FormFields/HorizontalRadioGroup';
import FormErrorMessages from 'components/FormFields/FormErrorMessages';
import validations from './ProfileEditForm.validations';
import { reduxForm } from 'redux-form';
import { messages } from './ProfileEditForm.i18n';
import styles from './ProfileEditForm.scss';
import { autobind } from 'core-decorators';

const MALE: string = 'male';
const FEMALE: string = 'female';

class ProfileEditForm extends React.Component {
  static propTypes = {
    fields: PropTypes.object.isRequired,
    intl: intlShape.isRequired,
    values: PropTypes.object.isRequired,
    pristine: PropTypes.bool.isRequired,
    invalid: PropTypes.bool.isRequired,
    resetForm: PropTypes.func.isRequired,
    user: PropTypes.object.isRequired,
    handleUpdate: PropTypes.func.isRequired,
  };

  @autobind
  onUpdateClick() {
    this.props.handleUpdate(Object.assign({}, this.props.user, this.props.values));
  }

  @autobind
  onResetClick() {
    this.props.resetForm();
  }

  isUpdateButtonDisabled(): boolean {
    return this.props.pristine || this.props.invalid;
  }

  isResetButtonDisabled(): boolean {
    return this.props.pristine;
  }

  render(): Component {
    const { fields: { givenName, familyName, nickname, email, emailVerified, gender, locale, notes } } = this.props;
    const { formatMessage } = this.props.intl;
    const genderValues = [
      {
        label: formatMessage(messages.gender.male.label),
        value: MALE,
      },
      {
        label: formatMessage(messages.gender.female.label),
        value: FEMALE,
      },
    ];

    // in a real app, the locales would be populated via service call:
    const locales: string[] = ['en-GB', 'en-AU', 'es-ES', 'es-CR', 'es-NI'];

    return (

        <form onSubmit={this.onUpdateClick}>
          <Row>
            <Col sm={2}>

            </Col>
            <Col sm={5}>
              <TextInput field={givenName} placeholder={formatMessage(messages.givenName.placeholder)}>
                <FormErrorMessages field={givenName} />
              </TextInput>
              <TextInput field={familyName} placeholder={formatMessage(messages.familyName.placeholder)}>
                <FormErrorMessages field={familyName} />
              </TextInput>
              <TextInput field={nickname} placeholder={formatMessage(messages.nickname.placeholder)} />
              <TextInput field={email} type="email" placeholder={formatMessage(messages.email.placeholder)}>
                <FormErrorMessages field={email} />
              </TextInput>
              <Input type="checkbox" label={formatMessage(messages.emailVerified.label)} {...emailVerified} />
            </Col>
            <Col sm={5}>
              <HorizontalRadioGroup field={gender} values={genderValues} />
              <Input type="select" label={formatMessage(messages.locale.label)} {...locale}>
                {locales.map(_locale => <option key={_locale} value={_locale}>{_locale}</option>)}
              </Input>
              <Input type="textarea" label={formatMessage(messages.notes.label)} {...notes} />
            </Col>
          </Row>
          <Row>
            <Col sm={2} />
            <Col sm={10}>
              <Button
                bsStyle="primary"
                onClick={this.onUpdateClick}
                disabled={this.isUpdateButtonDisabled()}
              >
                <FormattedMessage {...messages.save.label} />
              </Button>
              {
                // Need to include the preceding non-breaking space, because when React renders the HTML,
                // there is no gap in the markup between the buttons - which results in the buttons being
                // flush up against each other.
              }
              <Button
                bsStyle="default"
                onClick={this.onResetClick}
                disabled={this.isResetButtonDisabled()}
              >
                <FormattedMessage {...messages.reset.label} />
              </Button>
            </Col>
          </Row>
        </form>

    );
  }
}

const reduxFormConfig: Object = {
  form: 'editProfile',
  ...generateValidation(validations),
};

const mapStateToProps = (state, props) => ({ initialValues: props.user });

export default reduxForm(reduxFormConfig, mapStateToProps)(injectIntl(ProfileEditForm));
<commit_msg>Change `locale` to DropDown<commit_after>/* @flow */
import React, { PropTypes, Component } from 'react';
import { Button, Input, Row, Col } from 'react-bootstrap';
import { FormattedMessage, intlShape, injectIntl } from 'react-intl';
import { generateValidation } from 'redux-form-validation';
import TextInput from 'components/FormFields/TextInput';
import HorizontalRadioGroup from 'components/FormFields/HorizontalRadioGroup';
import DropDown from 'components/FormFields/DropDown';
import FormErrorMessages from 'components/FormFields/FormErrorMessages';
import validations from './ProfileEditForm.validations';
import { reduxForm } from 'redux-form';
import { messages } from './ProfileEditForm.i18n';
import styles from './ProfileEditForm.scss';
import { autobind } from 'core-decorators';

const MALE: string = 'male';
const FEMALE: string = 'female';

class ProfileEditForm extends React.Component {
  static propTypes = {
    fields: PropTypes.object.isRequired,
    intl: intlShape.isRequired,
    values: PropTypes.object.isRequired,
    pristine: PropTypes.bool.isRequired,
    invalid: PropTypes.bool.isRequired,
    resetForm: PropTypes.func.isRequired,
    user: PropTypes.object.isRequired,
    handleUpdate: PropTypes.func.isRequired,
  };

  @autobind
  onUpdateClick() {
    this.props.handleUpdate(Object.assign({}, this.props.user, this.props.values));
  }

  @autobind
  onResetClick() {
    this.props.resetForm();
  }

  isUpdateButtonDisabled(): boolean {
    return this.props.pristine || this.props.invalid;
  }

  isResetButtonDisabled(): boolean {
    return this.props.pristine;
  }

  render(): Component {
    const { fields: { givenName, familyName, nickname, email, emailVerified, gender, locale, notes } } = this.props;
    const { formatMessage } = this.props.intl;
    const genderValues = [
      {
        label: formatMessage(messages.gender.male.label),
        value: MALE,
      },
      {
        label: formatMessage(messages.gender.female.label),
        value: FEMALE,
      },
    ];

    // in a real app, the locales would be populated via service call:
    const locales: string[] = ['en-GB', 'en-AU', 'es-ES', 'es-CR', 'es-NI'];

    return (

        <form onSubmit={this.onUpdateClick}>
          <Row>
            <Col sm={2}>

            </Col>
            <Col sm={5}>
              <TextInput field={givenName} placeholder={formatMessage(messages.givenName.placeholder)}>
                <FormErrorMessages field={givenName} />
              </TextInput>
              <TextInput field={familyName} placeholder={formatMessage(messages.familyName.placeholder)}>
                <FormErrorMessages field={familyName} />
              </TextInput>
              <TextInput field={nickname} placeholder={formatMessage(messages.nickname.placeholder)} />
              <TextInput field={email} type="email" placeholder={formatMessage(messages.email.placeholder)}>
                <FormErrorMessages field={email} />
              </TextInput>
              <Input type="checkbox" label={formatMessage(messages.emailVerified.label)} {...emailVerified} />
            </Col>
            <Col sm={5}>
              <HorizontalRadioGroup field={gender} values={genderValues} />
              <DropDown label={formatMessage(messages.locale.label)} field={locale} values={locales} />
              <Input type="textarea" label={formatMessage(messages.notes.label)} {...notes} />
            </Col>
          </Row>
          <Row>
            <Col sm={2} />
            <Col sm={10}>
              <Button
                bsStyle="primary"
                onClick={this.onUpdateClick}
                disabled={this.isUpdateButtonDisabled()}
              >
                <FormattedMessage {...messages.save.label} />
              </Button>
              {
                // Need to include the preceding non-breaking space, because when React renders the HTML,
                // there is no gap in the markup between the buttons - which results in the buttons being
                // flush up against each other.
              }
              <Button
                bsStyle="default"
                onClick={this.onResetClick}
                disabled={this.isResetButtonDisabled()}
              >
                <FormattedMessage {...messages.reset.label} />
              </Button>
            </Col>
          </Row>
        </form>

    );
  }
}

const reduxFormConfig: Object = {
  form: 'editProfile',
  ...generateValidation(validations),
};

const mapStateToProps = (state, props) => ({ initialValues: props.user });

export default reduxForm(reduxFormConfig, mapStateToProps)(injectIntl(ProfileEditForm));
<|endoftext|>


<commit_before>'use strict';

const electron = require('electron');
const ipc = electron.ipcRenderer;
const NativeNotification = Notification;

var unreadCountTimer = setInterval(function() {
  if (!this.count) {
    this.count = 0;
  }

  // count in sidebar
  var unreadCount = document.getElementsByClassName('unread-title').length;

  // count for active channel
  if(!electron.remote.getCurrentWindow().isFocused()) {
    var newSeparators = document.getElementsByClassName('new-separator active');
    for (var i = 0; i < newSeparators.length; i++) {
      if (newSeparators[i].offsetParent !== null) {
        unreadCount += 1;
      }
    }
  }

  if (this.count != unreadCount) {
    ipc.sendToHost('onUnreadCountChange', unreadCount);
  }
  this.count = unreadCount;
}, 1000);

// On Windows 8.1 and Windows 8, a shortcut with a Application User Model ID must be installed to the Start screen.
// In current version, use tray balloon for notification
function isLowerThanOrEqualWindows8_1() {
  if (process.platform != 'win32') {
    return false;
  }
  var osVersion = require('../../common/osVersion');
  return (osVersion.major <= 6 && osVersion.minor <= 3);
};

// Show balloon when notified.
function overrideNotificationWithBalloon() {
  Notification = function(title, options) {
    ipc.send('notified', {
      title: title,
      options: options
    });
  };
  Notification.requestPermission = function(callback) {
    callback('granted');
  };
  Notification.prototype.close = function() {};
};

// Show window even if it is hidden/minimized when notification is clicked.
function overrideNotification() {
  Notification = function(title, options) {
    this.notification = new NativeNotification(title, options);
  };
  Notification.requestPermission = function(callback) {
    callback('granted');
  };
  Notification.prototype.close = function() {
    this.notification.close();
  };
  Notification.prototype.__defineSetter__('onclick', function(callback) {
    this.notification.onclick = function() {
      if (process.platform === 'win32') {
        // show() breaks Aero Snap state.
        electron.remote.getCurrentWindow().focus();
      }
      else {
        electron.remote.getCurrentWindow().show();
      }
      ipc.sendToHost('onNotificationClick');
      callback();
    };
  });
}

if (process.platform === 'win32' && isLowerThanOrEqualWindows8_1()) {
  overrideNotificationWithBalloon();
}
else {
  overrideNotification();
}
<commit_msg>Remove unnecessary class name.<commit_after>'use strict';

const electron = require('electron');
const ipc = electron.ipcRenderer;
const NativeNotification = Notification;

var unreadCountTimer = setInterval(function() {
  if (!this.count) {
    this.count = 0;
  }

  // count in sidebar
  var unreadCount = document.getElementsByClassName('unread-title').length;

  // count for active channel
  if(!electron.remote.getCurrentWindow().isFocused()) {
    var newSeparators = document.getElementsByClassName('new-separator');
    for (var i = 0; i < newSeparators.length; i++) {
      if (newSeparators[i].offsetParent !== null) {
        unreadCount += 1;
      }
    }
  }

  if (this.count != unreadCount) {
    ipc.sendToHost('onUnreadCountChange', unreadCount);
  }
  this.count = unreadCount;
}, 1000);

// On Windows 8.1 and Windows 8, a shortcut with a Application User Model ID must be installed to the Start screen.
// In current version, use tray balloon for notification
function isLowerThanOrEqualWindows8_1() {
  if (process.platform != 'win32') {
    return false;
  }
  var osVersion = require('../../common/osVersion');
  return (osVersion.major <= 6 && osVersion.minor <= 3);
};

// Show balloon when notified.
function overrideNotificationWithBalloon() {
  Notification = function(title, options) {
    ipc.send('notified', {
      title: title,
      options: options
    });
  };
  Notification.requestPermission = function(callback) {
    callback('granted');
  };
  Notification.prototype.close = function() {};
};

// Show window even if it is hidden/minimized when notification is clicked.
function overrideNotification() {
  Notification = function(title, options) {
    this.notification = new NativeNotification(title, options);
  };
  Notification.requestPermission = function(callback) {
    callback('granted');
  };
  Notification.prototype.close = function() {
    this.notification.close();
  };
  Notification.prototype.__defineSetter__('onclick', function(callback) {
    this.notification.onclick = function() {
      if (process.platform === 'win32') {
        // show() breaks Aero Snap state.
        electron.remote.getCurrentWindow().focus();
      }
      else {
        electron.remote.getCurrentWindow().show();
      }
      ipc.sendToHost('onNotificationClick');
      callback();
    };
  });
}

if (process.platform === 'win32' && isLowerThanOrEqualWindows8_1()) {
  overrideNotificationWithBalloon();
}
else {
  overrideNotification();
}
<|endoftext|>


<commit_before>"use strict";

var _ = require('underscore');

var Socket = function (io) {
    this.io = io;

    this.setupListeners();
};

Socket.prototype.setupListeners = function () {

    this.io.on('connection', function (socket) {

        console.log('User Connected');

    });

};

module.exports = Socket;<commit_msg>updated socket disconnect notifications<commit_after>"use strict";

var _ = require('underscore');

var Socket = function (io) {
    this.io = io;

    this.setupListeners();
};

Socket.prototype.setupListeners = function () {

    this.io.on('connection', function (socket) {

        console.log('User Connected');

        socket.on('disconnect', function() {
            console.log('User Disconnected');
        });

    });

};

module.exports = Socket;<|endoftext|>


<commit_before>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF 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.
 *
*/

/**
 * Position error object
 *
 * @constructor
 * @param code
 * @param message
 */
var PositionError = function(code, message) {
    this.code = code || null;
    this.message = message || '';
};

PositionError.PERMISSION_DENIED = 1;
PositionError.POSITION_UNAVAILABLE = 2;
PositionError.TIMEOUT = 3;

module.exports = PositionError;
<commit_msg>CB-2845 PositionError constants not attached to prototype as specified in W3C document<commit_after>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF 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.
 *
*/

/**
 * Position error object
 *
 * @constructor
 * @param code
 * @param message
 */
var PositionError = function(code, message) {
    this.code = code || null;
    this.message = message || '';
};

PositionError.prototype.PERMISSION_DENIED = PositionError.PERMISSION_DENIED = 1;
PositionError.prototype.POSITION_UNAVAILABLE = PositionError.POSITION_UNAVAILABLE = 2;
PositionError.prototype.TIMEOUT = PositionError.TIMEOUT = 3;

module.exports = PositionError;
<|endoftext|>


<commit_before>var _ = require('underscore'),
    combine = require('./jsCombine'),
    configLoader = require('./config'),
    Context = require('./context'),
    fs = require('fs'),
    fu = require('./fileUtil'),
    plugin = require('./plugin'),
    watch = require('./watcher.js'),
    growl = require('growl');

function logError(err) {
    // TODO : Move this to the executable
    console.error(err.stack || err.message);
    growl.notify(err.message, { title: 'Lumbar error' });
}

var config, configCache;
function loadConfig(path) {
  try {
    configCache = {};
    config = configLoader.load(path);
  } catch (err) {
    // Do not die a horrible death if this is just a syntax error
    logError(err);
  }
}

exports.fileUtil = fu;
exports.plugin = plugin.plugin;
exports.init = function(configFile, options) {
    var outdir = options.outdir,
        minimize = options.minimize,
        plugins = plugin.create(options);

    function initPlatforms() {
      config.platformList().forEach(function(platform) {
        if (!platform) {
          return;
        }
        try {
          console.log("mkdir:\t\033[90mmaking directory\033[0m " + outdir + '/' + platform);
          fs.mkdirSync(outdir + '/' + platform, 0755);
        } catch (err) {
          if (err.code !== 'EEXIST') {
            throw err;
          }
        }
      });
    }

    function buildPlatform(context, callback) {
      buildMode('scripts', context, callback);
      buildMode('styles', context, callback);
    }
    function buildMode(mode, context, callback) {
      var modules = config.moduleList(context.package);

      context = context.clone();
      context.mode = mode;

      plugins.generatedFiles(context).forEach(function(fileConfig) {
        var fileContext = context.clone(true);
        fileContext.fileConfig = fileConfig;
        fileContext.resources = [];
        fileContext.fileCache = fileContext.combined ? {} : undefined;

        if (fileContext.combined) {
          var fileName = plugins.fileName(fileContext);
          fileContext.fileName = outdir + '/' + fileName.path + '.' + fileName.extension;
        }

        var returned = 0;
        modules.forEach(function(module) {
          var moduleContext = fileContext.clone();
          moduleContext.module = module;

          buildModule(moduleContext, function(err, data) {
            if (err) {
              return callback(err);
            }

            returned++;
            if (fileContext.combined) {
              if (returned === modules.length) {
                combineResources(fileContext, fileContext.package, function(err, data) {
                  if (data) {
                    data.package = fileContext.package;
                  }
                  callback(err, data);
                });
              }
            } else if (data) {    // No files for a particular module mode
              callback(err, data);
            }
          });
        });
      });
    }
    function buildModule(context, callback) {
      context.module = config.module(context.module);
      context.options = options;
      context.configCache = configCache;
      context.fileCache = context.combined ? context.fileCache : {};
      context.moduleCache = {};

      if (!context.combined) {
        var fileName = plugins.fileName(context);
        context.fileName = outdir + '/' + fileName.path + '.' + fileName.extension;
      }

      config.fileList(plugins, context, function(err, resources) {
        if (err) {
          return callback(err);
        }

        resources = resources.map(function(resource) {
          var resourceContext = context.clone();
          resourceContext.resource = resource;
          return plugins.resource(resourceContext);
        }).filter(function(resource) { return resource; });

        context.moduleResources = resources;
        plugins.module(context);

        if (!context.combined) {
          context.resources = context.moduleResources;
          context.moduleResources = undefined;
          combineResources(context, context.module.name, function(err, data) {
            if (data) {
              data.package = context.package;
              data.module = context.module.name;
            }
            callback(err, data);
          });
        } else {
          context.resources.push.apply(context.resources, context.moduleResources);
          context.moduleResources = undefined;
          callback();
        }
      });
    }
    function combineResources(context, name, callback) {
      var resources = context.resources;
      if (!resources.length) {
        return;
      }

      plugins.file(context);
      combineFile(resources, context, name, callback);

      context.fileCache = undefined;
    }
    function combineFile(list, context, name, callback) {
      combine.combine(
          list,
          context.fileName,
          options.minimize && context.mode === 'scripts',
          context.mode === 'styles',
          function(err, data) {
        if (err) {
          fs.unlink(context.fileName);
        }

        if (data) {
          data.fileConfig = context.fileConfig;
          data.platform = context.platform;
          data.mode = context.mode;
        }
        callback(err, data)
      });
    }

    loadConfig(configFile);
    initPlatforms();

    return {
      use: function(plugin) {
        plugins.use(plugin);
      },
      build: function(packageName, callback) {
        var packages = packageName ? [packageName] : config.packageList();
        packages.forEach(function(package) {
          var platforms = config.platformList(package);
          platforms.forEach(function(platform) {
            buildPlatform(new Context({package: package, platform: platform}, config, plugins), callback);
          });
        });
      },
      watch: function(packageName, callback) {
        if (!fs.watch) {
          throw new Error('Watch requires fs.watch, introduced in Node v0.6.0');
        }

        var packages = packageName ? [packageName] : config.packageList(),
            self = this;

        // Watch for changes in the config file
        // WARN : This isn't really safe for multiple executions, this is a concious design decision
        watch.watchFile(configFile, [], function() {
          loadConfig(configFile);

          // Cleanup what we can, breaking things along the way
          watch.unwatchAll();

          // Give it a chance to cleanup before start recreating. Attempting to avoid the too many files error.
          setTimeout(function() {
            initPlatforms();
            self.watch(packageName, callback);
          }, 1000);
        });

        // Watch the individual components
        packages.forEach(function(name) {
          self.build(name, function(err, status) {
            if (err) {
              logError(err);
              return;
            }

            callback(err, status);

            var context = new Context(status, config, plugins),
                input = status.input.map(function(input) { return fu.resolvePath(input.dir || input); });
            watch.watchFile({ virtual: status.fileName }, input, _.debounce(function() {
              if (context.module) {
                buildModule(context.clone(), callback);
              } else {
                buildMode(context.mode, context.clone(), callback);
              }
            }, 500));
          });
        });
      },
      unwatch: function() {
        watch.unwatchAll();
      }
    };
};
<commit_msg>Update growl for 1.4<commit_after>var _ = require('underscore'),
    combine = require('./jsCombine'),
    configLoader = require('./config'),
    Context = require('./context'),
    fs = require('fs'),
    fu = require('./fileUtil'),
    plugin = require('./plugin'),
    watch = require('./watcher.js'),
    growl = require('growl');

function logError(err) {
    // TODO : Move this to the executable
    console.error(err.stack || err.message);
    growl(err.message, { title: 'Lumbar error' });
}

var config, configCache;
function loadConfig(path) {
  try {
    configCache = {};
    config = configLoader.load(path);
  } catch (err) {
    // Do not die a horrible death if this is just a syntax error
    logError(err);
  }
}

exports.fileUtil = fu;
exports.plugin = plugin.plugin;
exports.init = function(configFile, options) {
    var outdir = options.outdir,
        minimize = options.minimize,
        plugins = plugin.create(options);

    function initPlatforms() {
      config.platformList().forEach(function(platform) {
        if (!platform) {
          return;
        }
        try {
          console.log("mkdir:\t\033[90mmaking directory\033[0m " + outdir + '/' + platform);
          fs.mkdirSync(outdir + '/' + platform, 0755);
        } catch (err) {
          if (err.code !== 'EEXIST') {
            throw err;
          }
        }
      });
    }

    function buildPlatform(context, callback) {
      buildMode('scripts', context, callback);
      buildMode('styles', context, callback);
    }
    function buildMode(mode, context, callback) {
      var modules = config.moduleList(context.package);

      context = context.clone();
      context.mode = mode;

      plugins.generatedFiles(context).forEach(function(fileConfig) {
        var fileContext = context.clone(true);
        fileContext.fileConfig = fileConfig;
        fileContext.resources = [];
        fileContext.fileCache = fileContext.combined ? {} : undefined;

        if (fileContext.combined) {
          var fileName = plugins.fileName(fileContext);
          fileContext.fileName = outdir + '/' + fileName.path + '.' + fileName.extension;
        }

        var returned = 0;
        modules.forEach(function(module) {
          var moduleContext = fileContext.clone();
          moduleContext.module = module;

          buildModule(moduleContext, function(err, data) {
            if (err) {
              return callback(err);
            }

            returned++;
            if (fileContext.combined) {
              if (returned === modules.length) {
                combineResources(fileContext, fileContext.package, function(err, data) {
                  if (data) {
                    data.package = fileContext.package;
                  }
                  callback(err, data);
                });
              }
            } else if (data) {    // No files for a particular module mode
              callback(err, data);
            }
          });
        });
      });
    }
    function buildModule(context, callback) {
      context.module = config.module(context.module);
      context.options = options;
      context.configCache = configCache;
      context.fileCache = context.combined ? context.fileCache : {};
      context.moduleCache = {};

      if (!context.combined) {
        var fileName = plugins.fileName(context);
        context.fileName = outdir + '/' + fileName.path + '.' + fileName.extension;
      }

      config.fileList(plugins, context, function(err, resources) {
        if (err) {
          return callback(err);
        }

        resources = resources.map(function(resource) {
          var resourceContext = context.clone();
          resourceContext.resource = resource;
          return plugins.resource(resourceContext);
        }).filter(function(resource) { return resource; });

        context.moduleResources = resources;
        plugins.module(context);

        if (!context.combined) {
          context.resources = context.moduleResources;
          context.moduleResources = undefined;
          combineResources(context, context.module.name, function(err, data) {
            if (data) {
              data.package = context.package;
              data.module = context.module.name;
            }
            callback(err, data);
          });
        } else {
          context.resources.push.apply(context.resources, context.moduleResources);
          context.moduleResources = undefined;
          callback();
        }
      });
    }
    function combineResources(context, name, callback) {
      var resources = context.resources;
      if (!resources.length) {
        return;
      }

      plugins.file(context);
      combineFile(resources, context, name, callback);

      context.fileCache = undefined;
    }
    function combineFile(list, context, name, callback) {
      combine.combine(
          list,
          context.fileName,
          options.minimize && context.mode === 'scripts',
          context.mode === 'styles',
          function(err, data) {
        if (err) {
          fs.unlink(context.fileName);
        }

        if (data) {
          data.fileConfig = context.fileConfig;
          data.platform = context.platform;
          data.mode = context.mode;
        }
        callback(err, data)
      });
    }

    loadConfig(configFile);
    initPlatforms();

    return {
      use: function(plugin) {
        plugins.use(plugin);
      },
      build: function(packageName, callback) {
        var packages = packageName ? [packageName] : config.packageList();
        packages.forEach(function(package) {
          var platforms = config.platformList(package);
          platforms.forEach(function(platform) {
            buildPlatform(new Context({package: package, platform: platform}, config, plugins), callback);
          });
        });
      },
      watch: function(packageName, callback) {
        if (!fs.watch) {
          throw new Error('Watch requires fs.watch, introduced in Node v0.6.0');
        }

        var packages = packageName ? [packageName] : config.packageList(),
            self = this;

        // Watch for changes in the config file
        // WARN : This isn't really safe for multiple executions, this is a concious design decision
        watch.watchFile(configFile, [], function() {
          loadConfig(configFile);

          // Cleanup what we can, breaking things along the way
          watch.unwatchAll();

          // Give it a chance to cleanup before start recreating. Attempting to avoid the too many files error.
          setTimeout(function() {
            initPlatforms();
            self.watch(packageName, callback);
          }, 1000);
        });

        // Watch the individual components
        packages.forEach(function(name) {
          self.build(name, function(err, status) {
            if (err) {
              logError(err);
              return;
            }

            callback(err, status);

            var context = new Context(status, config, plugins),
                input = status.input.map(function(input) { return fu.resolvePath(input.dir || input); });
            watch.watchFile({ virtual: status.fileName }, input, _.debounce(function() {
              if (context.module) {
                buildModule(context.clone(), callback);
              } else {
                buildMode(context.mode, context.clone(), callback);
              }
            }, 500));
          });
        });
      },
      unwatch: function() {
        watch.unwatchAll();
      }
    };
};
<|endoftext|>


<commit_before>var rockets;
var lifespan = 200;

// target
var target;

function setup() {
  canvas = createCanvas(800, 800);

  // create rocket objs
  rockets = new Rockets();

  // create new target
  target = createVector(width / 2, 50);
}

function draw() {
  background(0);

  // update rockets
  rockets.run();

  // draw target
  noStroke();
  fill("#0F0");
  ellipse(target.x, target.y, 20, 20);
}

// group of rockets as a class
function Rockets() {
  this.rockets = [];
  this.population = 50;

  for (var i = 0; i < this.population; i++) {
    this.rockets[i] = new Rocket();
  }

  this.run = function() {
    for (var i = 0; i < this.population; i++) {
      this.rockets[i].applyForce(createVector(0, 0.01))
      this.rockets[i].update();
      this.rockets[i].show();
    }
  }

  this.isAlive = function() {
    var allAlive = true;
    for (var i = 0; i < this.population; i++) {
      if (this.rockets[i].isAlive == false) {
        allAlive = false;
        break;
      }
    }
    return allAlive;
  }
}

// rocket class
function Rocket() {
  // attributes
  this.position = createVector(width / 2, height - 20);
  this.velocity = p5.Vector.random2D();
  this.acceleration = createVector();
  this.dna = new DNA();

  // measures how long it has lived
  this.life = 0;

  // alive when life < lifespan
  this.isAlive = true;

  // enabled when it hasnt crashed
  this.isEnabled = true;

  // methods
  this.applyForce = function(force) {
    this.acceleration.add(force);
  }
  this.update = function() {
    // add dna to acceleration
    this.applyForce(this.dna.genes[this.life]);
    this.life++;

    if (this.life >= lifespan) {
      this.isAlive = false;
    }

    this.velocity.add(this.acceleration);
    this.position.add(this.velocity);
    this.acceleration.mult(0);

    // check collision only when still enabled
    if (this.isEnabled) {
      this.checkCollision();
    }
  }
  this.show = function() {
    push()
    translate(this.position.x, this.position.y);
    rotate(this.velocity.heading());
    noStroke();

    if (this.isAlive) {
      fill("#0F0");
    } else {
      fill(150);
    }

    rectMode(CENTER);

    if (this.isEnabled) {
      rect(0, 0, 20, 10);
    }

    pop();
  }

  this.checkCollision = function() {
    // checks the collision on the side
    if (this.position.x >= width || this.position.x <= 0 ||
    this.position.y >= height || this.position.y <= 0) {
      this.isEnabled = false;
    }
  }
}

// DNA class defines behavior of rockets
function DNA() {
  this.genes = [];
  for (var i = 0; i < lifespan; i++) {
    this.genes[i] = p5.Vector.random2D().setMag(0.5);
  }
}
<commit_msg>Added resetting<commit_after>var rockets;
var lifespan = 200;

// target
var target;

function setup() {
  canvas = createCanvas(800, 800);

  // create rocket objs
  rockets = new Rockets();

  // create new target
  target = createVector(width / 2, 50);
}

function draw() {
  background(0);

  // update rockets
  rockets.run();

  // reset if everyone is dead, reset
  if (rockets.allEnabled() == false) {
    rockets = new Rockets();
  }

  // draw target
  noStroke();
  fill("#0F0");
  ellipse(target.x, target.y, 20, 20);
}

// group of rockets as a class
function Rockets() {
  this.rockets = [];
  this.population = 50;

  for (var i = 0; i < this.population; i++) {
    this.rockets[i] = new Rocket();
  }

  this.run = function() {
    for (var i = 0; i < this.population; i++) {
      this.rockets[i].applyForce(createVector(0, 0.05))
      this.rockets[i].update();
      this.rockets[i].show();
    }
  }

  this.allEnabled = function() {
    var isEnabled = false;
    for (var i = 0; i < this.population; i++) {
      if (this.rockets[i].isEnabled == true) {
        isEnabled = true;
        break;
      }
    }
    return isEnabled;
  }
}

// rocket class
function Rocket() {
  // attributes
  this.position = createVector(width / 2, height - 20);
  this.velocity = p5.Vector.random2D();
  this.acceleration = createVector();
  this.dna = new DNA();

  // measures how long it has lived
  this.life = 0;

  // alive when life < lifespan
  this.isAlive = true;

  // enabled when it hasnt crashed
  this.isEnabled = true;

  // methods
  this.applyForce = function(force) {
    this.acceleration.add(force);
  }
  this.update = function() {
    // add dna to acceleration
    this.applyForce(this.dna.genes[this.life]);
    this.life++;

    if (this.life >= lifespan) {
      this.isAlive = false;
    }

    this.velocity.add(this.acceleration);
    this.position.add(this.velocity);
    this.acceleration.mult(0);

    // check collision only when still enabled
    if (this.isEnabled) {
      this.checkCollision();
    }
  }
  this.show = function() {
    push()
    translate(this.position.x, this.position.y);
    rotate(this.velocity.heading());
    noStroke();

    if (this.isAlive) {
      fill("#0F0");
    } else {
      fill(150);
    }

    rectMode(CENTER);

    if (this.isEnabled) {
      rect(0, 0, 20, 10);
    }

    pop();
  }

  this.checkCollision = function() {
    // checks the collision on the side
    if (this.position.x >= width || this.position.x <= 0 ||
    this.position.y >= height || this.position.y <= 0) {
      this.isEnabled = false;
    }
  }
}

// DNA class defines behavior of rockets
function DNA() {
  this.genes = [];
  for (var i = 0; i < lifespan; i++) {
    this.genes[i] = p5.Vector.random2D().setMag(0.5);
  }
}
<|endoftext|>


<commit_before>/*
 * Waltz - Enterprise Architecture
 * Copyright (C) 2016  Khartec Ltd.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import _ from 'lodash';

function controller($stateParams,
                    personStore,
                    surveyRunStore,
                    surveyTemplateStore) {
    const templateId = $stateParams.id;

    const vm = this;

    vm.people = {};

    surveyTemplateStore
        .getById(templateId)
        .then(t => {
            vm.template = t;
            personStore
                .getById(t.ownerId)
                .then(p => {
                    if (p) {
                        vm.people[t.ownerId] = p;
                    }
                });
        });

    surveyRunStore
        .findByTemplateId(templateId)
        .then(rs => {
            [vm.issuedAndCompletedRuns = [], vm.draftRuns = []] = _.partition(rs, r => r.status !== 'DRAFT');
            _.chain(rs)
                .map('ownerId')
                .uniq()
                .value()
                .forEach(personId => personStore
                    .getById(personId)
                    .then(p => {
                        if (p) {
                            vm.people[p.id] = p;
                        }
                    }));
        });

}

controller.$inject = [
    '$stateParams',
    'PersonStore',
    'SurveyRunStore',
    'SurveyTemplateStore'
];

const page = {
    controller,
    controllerAs: 'ctrl',
    template: require('./survey-template-view.html')
};

export default page;<commit_msg>Survey: template view doesn't display template owner if there's no runs or the owner isn't one of the runs' owners<commit_after>/*
 * Waltz - Enterprise Architecture
 * Copyright (C) 2016  Khartec Ltd.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import _ from 'lodash';

function controller($stateParams,
                    personStore,
                    surveyRunStore,
                    surveyTemplateStore) {
    const templateId = $stateParams.id;

    const vm = this;

    vm.people = {};

    surveyTemplateStore
        .getById(templateId)
        .then(t => {
            if (t) {
                vm.template = t;
                personStore
                    .getById(t.ownerId)
                    .then(p => {
                        if (p) {
                            vm.people[t.ownerId] = p;
                        }
                    });
            }
        });

    surveyRunStore
        .findByTemplateId(templateId)
        .then(rs => {
            [vm.issuedAndCompletedRuns = [], vm.draftRuns = []] = _.partition(rs, r => r.status !== 'DRAFT');
            _.chain(rs)
                .map('ownerId')
                .uniq()
                .value()
                .forEach(personId => personStore
                    .getById(personId)
                    .then(p => {
                        if (p) {
                            vm.people[p.id] = p;
                        }
                    }));
        });

}

controller.$inject = [
    '$stateParams',
    'PersonStore',
    'SurveyRunStore',
    'SurveyTemplateStore'
];

const page = {
    controller,
    controllerAs: 'ctrl',
    template: require('./survey-template-view.html')
};

export default page;<|endoftext|>


<commit_before>/**
 * Created by nuintun on 2015/4/27.
 */

'use strict';

var is = require('is');
var css = require('css');
var path = require('path');
var join = path.join;
var extname = path.extname;
var rename = require('rename');
var udeps = require('umd-deps');
var cdeps = require('./css-deps');
var util = require('./util');
var debug = util.debug;
var colors = util.colors;

/**
 * Transport file id
 * - vinyl: vinyl object
 * - required options: idleading, rename
 */

function transportId(vinyl, options){
  var id;
  var pkg = util.parsePackage(vinyl);
  var renameOpts = util.getRenameOpts(options.rename);
  var idleading = resolveIdleading(options.idleading, vinyl.path, pkg);

  // get id
  id = util.template(idleading, pkg);
  // rename id
  id = rename.parse(util.addExt(id));
  id = rename(id, renameOpts);
  id = util.normalize(util.hideExt(id));

  // seajs has hacked css before 3.0.0
  // https://github.com/seajs/seajs/blob/2.2.1/src/util-path.js#L49
  // demo https://github.com/popomore/seajs-test/tree/master/css-deps
  if (extname(id) === '.css') {
    id += '.js';
  }

  // debug
  debug('transport id: %s', colors.dataBold(id));

  // rewrite file path
  vinyl.path = join(vinyl.cwd, vinyl.base, util.addExt(id));
  // set vinyl package info
  vinyl.package = util.extend(vinyl.package, { id: id }, pkg);

  return id;
}

/**
 * Transport cmd dependencies.
 * - vinyl: vinyl object
 * - required options: idleading
 */

function transportDeps(vinyl, options){
  var deps = [];
  var localDepsMaps = [];
  var alias = options.alias;
  var paths = options.paths;
  var vars = options.vars;

  // replace require and collect dependencies
  vinyl.contents = new Buffer(udeps(vinyl.contents.toString(), function (id, flag){
    // normalize id
    id = util.normalize(id);

    // id is not a local file
    if (!util.isLocal(id)) {
      // cache dependencie id
      deps.push(id);

      return id;
    }

    var path;
    var isRelative = util.isRelative(id);
    var renameOpts = util.getRenameOpts(options.rename);

    // parse id form alias, paths, vars
    id = util.parseAlias(id, alias);
    id = util.parsePaths(id, paths);
    id = util.parseAlias(id, alias);
    id = util.parseVars(id, vars);
    id = util.parseAlias(id, alias);

    // normalize id
    id = util.normalize(id);

    // if end with /, find index file
    if (id.substring(id.length - 1) === '/') {
      id += 'index';
    }

    // add extname
    path = util.addExt(id);

    // debug
    debug('transport%s dependencies: %s', flag ? ' ' + flag : '', colors.dataBold(id));

    // rename id
    id = rename.parse(path);
    id = (isRelative ? './' : '') + rename(id, renameOpts);

    // hide extname
    id = util.hideExt(id);

    // seajs has hacked css before 3.0.0
    // https://github.com/seajs/seajs/blob/2.2.1/src/util-path.js#L49
    // demo https://github.com/popomore/seajs-test/tree/master/css-deps
    if (extname(id) === '.css') {
      id += '.js';
    }

    // normalize id
    id = util.normalize(id);

    // cache dependencie id and path
    if (flag === null) {
      // cache dependencie id
      deps.push(id);

      // get absolute path
      path = util.resolve(path, vinyl, options.wwwroot);

      // cache dependencie absolute path
      localDepsMaps.push({
        id: id,
        path: path
      });
    }

    return id;
  }, true));

  // Cache file dependencies
  vinyl.package = util.extend(vinyl.package, {
    dependencies: deps,
    localDepsMaps: localDepsMaps
  });

  return deps;
}

/**
 * Transport css dependencies.
 * - vinyl: vinyl object
 */

function transportCssDeps(vinyl, options){
  var deps = [];
  var localDepsMaps = [];

  // replace imports and collect dependencies
  vinyl.contents = new Buffer(cdeps(vinyl.contents, function (id){
    var path;

    // normalize id
    id = util.normalize(id);

    // id is not a local file
    if (!util.isLocal(id)) {
      // cache dependencie id
      deps.push(id);

      return id;
    }

    var isRelative = util.isRelative(id);
    var isAbsolute = util.isAbsolute(id);
    var renameOpts = util.getRenameOpts(options.rename);

    if (!isAbsolute && !isRelative) {
      id = './' + id;
      isRelative = true;
    }

    // if end with /, find index file
    if (id.substring(id.length - 1) === '/') {
      id += 'index.css';
    }

    // add extname
    id = path = util.addExt(id);

    // rename path
    id = rename.parse(id);
    id = (isRelative ? './' : '') + util.normalize(rename(id, renameOpts));
    // hide extname
    id = util.hideExt(id);

    // seajs has hacked css before 3.0.0
    // https://github.com/seajs/seajs/blob/2.2.1/src/util-path.js#L49
    // demo https://github.com/popomore/seajs-test/tree/master/css-deps
    if (extname(id) === '.css') {
      id += '.js';
    }

    // normalize id
    id = util.normalize(id);

    // debug
    debug('transport dependencies: %s', colors.dataBold(id));

    // get absolute path
    path = util.resolve(path, vinyl, options.wwwroot);

    // cache dependencie id
    deps.push(id);
    // cache dependencie absolute path
    localDepsMaps.push({
      id: id,
      path: path
    });

    // delete all import
    return false;
  }, options.oncsspath));

  // Cache file dependencies
  vinyl.package = util.extend(vinyl.package, {
    dependencies: deps,
    localDepsMaps: localDepsMaps
  });

  return deps;
}

/*
 Create a stream for parser in lib/parser
 */

function createParser(type, transport){
  return function (vinyl, options){
    // debug
    debug('transport %s: %s', type, colors.dataBold(util.normalize(vinyl.path)));

    vinyl = transport(vinyl, options);

    return vinyl;
  };
}

/**
 * resolve id leading
 * @param idleading
 * @param filepath
 * @param pkg
 * @returns {*}
 */

function resolveIdleading(idleading, filepath, pkg){
  return is.fn(idleading) ? idleading(filepath, pkg) : idleading;
}

/**
 * Exports module.
 */

exports.transportId = transportId;
exports.transportDeps = transportDeps;
exports.createParser = createParser;
exports.resolveIdleading = resolveIdleading;
exports.transportCssDeps = transportCssDeps;<commit_msg>add source file<commit_after>/**
 * Created by nuintun on 2015/4/27.
 */

'use strict';

var is = require('is');
var css = require('css');
var path = require('path');
var join = path.join;
var extname = path.extname;
var rename = require('rename');
var udeps = require('umd-deps');
var cdeps = require('./css-deps');
var util = require('./util');
var debug = util.debug;
var colors = util.colors;

/**
 * Transport file id
 * - vinyl: vinyl object
 * - required options: idleading, rename
 */

function transportId(vinyl, options){
  var id;
  var pkg = util.parsePackage(vinyl);
  var renameOpts = util.getRenameOpts(options.rename);
  var idleading = resolveIdleading(options.idleading, vinyl.path, pkg);

  // get id
  id = util.template(idleading, pkg);
  // rename id
  id = rename.parse(util.addExt(id));
  id = rename(id, renameOpts);
  id = util.normalize(util.hideExt(id));

  // seajs has hacked css before 3.0.0
  // https://github.com/seajs/seajs/blob/2.2.1/src/util-path.js#L49
  // demo https://github.com/popomore/seajs-test/tree/master/css-deps
  if (extname(id) === '.css') {
    id += '.js';
  }

  // debug
  debug('transport id: %s', colors.dataBold(id));

  // rewrite file path
  vinyl.path = join(vinyl.cwd, vinyl.base, util.addExt(id));
  // set vinyl package info
  vinyl.package = util.extend(vinyl.package, { id: id }, pkg);

  return id;
}

/**
 * Transport cmd dependencies.
 * - vinyl: vinyl object
 * - required options: idleading
 */

function transportDeps(vinyl, options){
  var deps = [];
  var localDepsMaps = [];
  var alias = options.alias;
  var paths = options.paths;
  var vars = options.vars;

  // replace require and collect dependencies
  vinyl.contents = new Buffer(udeps(vinyl.contents.toString(), function (id, flag){
    // normalize id
    id = util.normalize(id);

    // id is not a local file
    if (!util.isLocal(id)) {
      // cache dependencie id
      deps.push(id);

      return id;
    }

    var path;
    var isRelative = util.isRelative(id);
    var renameOpts = util.getRenameOpts(options.rename);

    // parse id form alias, paths, vars
    id = util.parseAlias(id, alias);
    id = util.parsePaths(id, paths);
    id = util.parseAlias(id, alias);
    id = util.parseVars(id, vars);
    id = util.parseAlias(id, alias);

    // normalize id
    id = util.normalize(id);

    // if end with /, find index file
    if (id.substring(id.length - 1) === '/') {
      id += 'index';
    }

    // add extname
    path = util.addExt(id);

    // debug
    debug('transport%s dependencies: %s', flag ? ' ' + flag : '', colors.dataBold(id));

    // rename id
    id = rename.parse(path);
    id = (isRelative ? './' : '') + rename(id, renameOpts);

    // hide extname
    id = util.hideExt(id);

    // seajs has hacked css before 3.0.0
    // https://github.com/seajs/seajs/blob/2.2.1/src/util-path.js#L49
    // demo https://github.com/popomore/seajs-test/tree/master/css-deps
    if (extname(id) === '.css') {
      id += '.js';
    }

    // normalize id
    id = util.normalize(id);

    // cache dependencie id and path
    if (flag === null) {
      // cache dependencie id
      deps.push(id);

      // get absolute path
      path = util.resolve(path, vinyl, options.wwwroot);

      // cache dependencie absolute path
      localDepsMaps.push({
        id: id,
        path: path
      });
    }

    return id;
  }, true));

  // Cache file dependencies
  vinyl.package = util.extend(vinyl.package, {
    dependencies: deps,
    localDepsMaps: localDepsMaps
  });

  return deps;
}

/**
 * Transport css dependencies.
 * - vinyl: vinyl object
 */

function transportCssDeps(vinyl, options){
  var deps = [];
  var localDepsMaps = [];

  // replace imports and collect dependencies
  vinyl.contents = new Buffer(cdeps(vinyl.contents, function (id){
    var path;

    // normalize id
    id = util.normalize(id);

    // id is not a local file
    if (!util.isLocal(id)) {
      // cache dependencie id
      deps.push(id);

      return id;
    }

    var isRelative = util.isRelative(id);
    var isAbsolute = util.isAbsolute(id);
    var renameOpts = util.getRenameOpts(options.rename);

    if (!isAbsolute && !isRelative) {
      id = './' + id;
      isRelative = true;
    }

    // if end with /, find index file
    if (id.substring(id.length - 1) === '/') {
      id += 'index.css';
    }

    // add extname
    id = path = util.addExt(id);

    // rename path
    id = rename.parse(id);
    id = (isRelative ? './' : '') + util.normalize(rename(id, renameOpts));
    // hide extname
    id = util.hideExt(id);

    // seajs has hacked css before 3.0.0
    // https://github.com/seajs/seajs/blob/2.2.1/src/util-path.js#L49
    // demo https://github.com/popomore/seajs-test/tree/master/css-deps
    if (extname(id) === '.css') {
      id += '.js';
    }

    // normalize id
    id = util.normalize(id);

    // debug
    debug('transport dependencies: %s', colors.dataBold(id));

    // get absolute path
    path = util.resolve(path, vinyl, options.wwwroot);

    // cache dependencie id
    deps.push(id);
    // cache dependencie absolute path
    localDepsMaps.push({
      id: id,
      path: path
    });

    // delete all import
    return false;
  }, options.oncsspath));

  // Cache file dependencies
  vinyl.package = util.extend(vinyl.package, {
    dependencies: deps,
    localDepsMaps: localDepsMaps
  });

  return deps;
}

/*
 Create a stream for parser in lib/parser
 */

function createParser(type, transport){
  return function (vinyl, options){
    // debug
    debug('read %s: %s', type, colors.dataBold(util.normalize(vinyl.path)));

    vinyl = transport(vinyl, options);

    return vinyl;
  };
}

/**
 * resolve id leading
 * @param idleading
 * @param filepath
 * @param pkg
 * @returns {*}
 */

function resolveIdleading(idleading, filepath, pkg){
  return is.fn(idleading) ? idleading(filepath, pkg) : idleading;
}

/**
 * Exports module.
 */

exports.transportId = transportId;
exports.transportDeps = transportDeps;
exports.createParser = createParser;
exports.resolveIdleading = resolveIdleading;
exports.transportCssDeps = transportCssDeps;<|endoftext|>