<commit_before>import EventEmitter from 'eventemitter3';
import _ from 'lodash';
import { uuidRegExp } from './utils/helpers';

import {
    getUri,
    getParallel,
    getAllContainers,
    getAllNodes,
    getAllTasks,
    getAllServices,
    getAllNodeClusters,
    getWebSocket
} from './utils/request';

let STARTED = 0;

let SINGLETON;
let CURRENT_SERVICES_URIS;

let PHYSICAL_STRUCT;

let tutumEventHandler = (e) => {
    console.log(e);
};

let nodeOrContainerExists = (arr, value) => {

    for (var i = 0, iLen = arr.length; i < iLen; i++) {

        if (arr[i].ID == value) return true;
    }
    return false;
};

let strToHash = (str) => {
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
        hash = str.charCodeAt(i) + ((hash << 5) - hash);
    }
    return hash;
};

let hashToHexColor = (hash) => {
    let color = "#";
    for (var i = 0; i < 3;) {
        color += ("00" + ((hash >> i++ * 8) & 0xFF).toString(16)).slice(-2);
    }
    return color;
}

let stringToColor = (str) => {
    let hash = strToHash(str);
    let color = hashToHexColor(hash);
    return color;
};

let physicalStructProvider = ([initialNodes, initialContainers]) => {
    let containers = _.map(initialContainers, _.cloneDeep);
    let nodeClusters = [{ uuid: "clusterid", name: "" }];
    let nodes = _.map(initialNodes, _.cloneDeep);
    let root = [];

    let addContainer = (container) => {
            var cloned = Object.assign({}, container);
            let NodeID = cloned.NodeID;
            _.find(root, (cluster) => {
                var node = _.find(cluster.children, { ID: NodeID });
                if (!node) return;
                var dt = new Date(cloned.UpdatedAt);
                var color = stringToColor(cloned.ServiceID);
                let serviceName = cloned.ServiceName;
                let imageNameRegex = /([^/]+?)(\:([^/]+))?$/;
                let imageNameMatches = imageNameRegex.exec(cloned.Spec.ContainerSpec.Image);
                let tagName = imageNameMatches[3];
                let dateStamp = dt.getDate() + "/" + (dt.getMonth() + 1) + " " + dt.getHours() + ":" + _.padStart(dt.getMinutes(), 2, "0");
                let startState = cloned.Status.State;

                let imageTag = "
" +
                    "" + serviceName + "" +
                    "
 image : " + imageNameMatches[0] +
                    "
 tag : " + (tagName ? tagName : "latest") +
                    "
" + (cloned.Spec.ContainerSpec.Args ? " cmd : " + cloned.Spec.ContainerSpec.Args + "
" : "") +
                    " updated : " + dateStamp +
                    "
" + cloned.Status.ContainerStatus.ContainerID +
                    "
 state : " + startState +
                    "
";

                if (node.Spec.Role == 'manager') {
                    let containerlink = window.location.href + "apis/containers/" + cloned.Status.ContainerStatus.ContainerID + "/json";
                    cloned.link = containerlink;
                }
                cloned.tag = imageTag;
                cloned.state = startState;

                node.children.push(cloned);
                return true;
            });
        },

        updateContainer = (container, services) => {
            let { uuid, node } = container;
            let [nodeUuid] = uuidRegExp.exec(node);
            _.find(root, (cluster) => {
                let node = _.findWhere(cluster.children, { uuid: nodeUuid });
                if (!node) return;

                let target = _.findWhere(node.children, { uuid }) || {};
                if (!target) return;

                Object.assign(target, container);
                return true;
            });
        },

        data = () => {
            let clone = _.cloneDeep(root);
            _.remove(clone, ({ uuid, children }) => {
                return uuid === 'BYON' && !children.length
            });

            return { root: clone };
        },

        addNodeCluster = (nodeCluster) => {
            var cloned = Object.assign({}, nodeCluster);
            cloned.children = [];
            root.push(cloned);
        },

        removeNodeCluster = (nodeCluster) => {
            _.remove(root, { uuid: nodeCluster.uuid });
        },

        updateNodeCluster = (nodeCluster) => {
            var currentCluster = _.findWhere(root, { uuid: nodeCluster.uuid });
            Object.assign(currentCluster, nodeCluster);
        },

        addNode = (node) => {
            let cloned = Object.assign({}, node);
            cloned.children = [];
            let clusterUuid = "clusterid";
            let cluster = _.findWhere(root, { uuid: clusterUuid });
            if (cluster) cluster.children.push(cloned);
        },
        updateNode = (node, state, spec) => {
            node.state = state;
            node.Spec = spec;
        },
        updateData = (resources) => {
            updateNodes(resources[0]);

            updateContainers(resources[1], resources[2]);
            data();
        },
        updateNodes = (nodes) => {
            let currentnodelist = root[0].children;
            for (let node of nodes) {
                if (!nodeOrContainerExists(currentnodelist, node.ID)) {
                    updateNode(node, 'ready');

                    addNode(node);
                } else {
                    for (let currentnode of currentnodelist) {
                        if (node.ID == currentnode.ID) {
                            name = node.Description.Hostname;
                            if (name.length > 0) {
                                currentnode.Description.Hostname = name;
                                currentnode.name = name + "
" + node.Spec.Role +
                                    "
" + (currentnode.Description.Resources.MemoryBytes / 1024 / 1024 / 1024).toFixed(3) + "G RAM
" +
                                    "" + (currentnode.Description.Platform.Architecture) + "/" + (currentnode.Description.Platform.OS) + "" +
                                    "
";
                                for (var key in node.Spec.Labels) {
                                    if (node.Spec.Labels[key].length > 0) {
                                        currentnode.name += "
" + key + "=" + node.Spec.Labels[key] + "";
                                    } else {
                                        currentnode.name += "
" + key + "";
                                    }
                                }
                                currentnode.name += "
"
                            }
                            updateNode(currentnode, node.state, node.Spec);
                        }
                    }

                }
            }
            for (let node of currentnodelist) {
                if (!nodeOrContainerExists(nodes, node.ID)) {
                    updateNode(node, 'down');
                }
            }
        },
        updateContainers = (containers, services) => {
            let nodes = root[0].children;
            // clearn all current children before rendering
            for (let node of nodes) {
                node.children = [];
            }

            for (let container of containers) {
                let contNodeId = container.NodeID;
                let service = _.find(services, function(o) { return o.ID == container.ServiceID; });
                container.ServiceName = service.Spec.Name;
                for (var i = 0, iLen = nodes.length; i < iLen; i++) {
                    if (nodes[i].ID == contNodeId) {
                        addContainer(container);
                    }
                }

            }

        };

    nodeClusters.forEach(addNodeCluster);
    nodes.forEach(addNode);

    containers.forEach(addContainer);

    return {
        addContainer,
        updateData,
        updateContainer,
        data,
        addNode,
        updateNode,
        addNodeCluster,
        removeNodeCluster,
        updateNodeCluster,
    };
}

class DataProvider extends EventEmitter {
    constructor() {
        super()
    }

    start() {
        STARTED = 1;
        //console.log(STARTED);
        var clusterInit = Promise.all([
                getAllNodes(),
                getAllTasks(),
                getAllServices()
            ])
            .then((resources) => {
                _.remove(resources[1], (nc) => nc.state === 'Empty cluster' || nc.state === 'Terminated');
                return resources;
            });

        Promise.all([clusterInit])
            .then(([resources]) => {
                PHYSICAL_STRUCT = physicalStructProvider(resources);
                this.emit('infrastructure-data', PHYSICAL_STRUCT.data());
                this.emit('start-reload');
            });
    }

    reload() {
        if (STARTED == 0) return;
        STARTED++;

        // console.log(STARTED);
        var clusterInit = Promise.all([
                getAllNodes(),
                getAllTasks(),
                getAllServices()
            ])
            .then((resources) => {
                _.remove(resources[1], (nc) => nc.state === 'Empty cluster' || nc.state === 'Terminated');
                return resources;
            });

        Promise.all([clusterInit])
            .then(([resources]) => {
                if (!PHYSICAL_STRUCT)
                    PHYSICAL_STRUCT = physicalStructProvider(resources);
                PHYSICAL_STRUCT.updateData(resources);
                this.emit('infrastructure-data', PHYSICAL_STRUCT.data());
            });
    }
}

export default SINGLETON = new DataProvider();
<commit_msg>Revert "Zeropad minutes"<commit_after>import EventEmitter from 'eventemitter3';
import _ from 'lodash';
import { uuidRegExp } from './utils/helpers';

import {
    getUri,
    getParallel,
    getAllContainers,
    getAllNodes,
    getAllTasks,
    getAllServices,
    getAllNodeClusters,
    getWebSocket
} from './utils/request';

let STARTED = 0;

let SINGLETON;
let CURRENT_SERVICES_URIS;

let PHYSICAL_STRUCT;

let tutumEventHandler = (e) => {
    console.log(e);
};

let nodeOrContainerExists = (arr, value) => {

    for (var i = 0, iLen = arr.length; i < iLen; i++) {

        if (arr[i].ID == value) return true;
    }
    return false;
};

let strToHash = (str) => {
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
        hash = str.charCodeAt(i) + ((hash << 5) - hash);
    }
    return hash;
};

let hashToHexColor = (hash) => {
    let color = "#";
    for (var i = 0; i < 3;) {
        color += ("00" + ((hash >> i++ * 8) & 0xFF).toString(16)).slice(-2);
    }
    return color;
}

let stringToColor = (str) => {
    let hash = strToHash(str);
    let color = hashToHexColor(hash);
    return color;
};

let physicalStructProvider = ([initialNodes, initialContainers]) => {
    let containers = _.map(initialContainers, _.cloneDeep);
    let nodeClusters = [{ uuid: "clusterid", name: "" }];
    let nodes = _.map(initialNodes, _.cloneDeep);
    let root = [];

    let addContainer = (container) => {
            var cloned = Object.assign({}, container);
            let NodeID = cloned.NodeID;
            _.find(root, (cluster) => {
                var node = _.find(cluster.children, { ID: NodeID });
                if (!node) return;
                var dt = new Date(cloned.UpdatedAt);
                var color = stringToColor(cloned.ServiceID);
                let serviceName = cloned.ServiceName;
                let imageNameRegex = /([^/]+?)(\:([^/]+))?$/;
                let imageNameMatches = imageNameRegex.exec(cloned.Spec.ContainerSpec.Image);
                let tagName = imageNameMatches[3];
                let dateStamp = dt.getDate() + "/" + (dt.getMonth() + 1) + " " + dt.getHours() + ":" + dt.getMinutes();
                let startState = cloned.Status.State;

                let imageTag = "
" +
                    "" + serviceName + "" +
                    "
 image : " + imageNameMatches[0] +
                    "
 tag : " + (tagName ? tagName : "latest") +
                    "
" + (cloned.Spec.ContainerSpec.Args ? " cmd : " + cloned.Spec.ContainerSpec.Args + "
" : "") +
                    " updated : " + dateStamp +
                    "
" + cloned.Status.ContainerStatus.ContainerID +
                    "
 state : " + startState +
                    "
";

                if (node.Spec.Role == 'manager') {
                    let containerlink = window.location.href + "apis/containers/" + cloned.Status.ContainerStatus.ContainerID + "/json";
                    cloned.link = containerlink;
                }
                cloned.tag = imageTag;
                cloned.state = startState;

                node.children.push(cloned);
                return true;
            });
        },

        updateContainer = (container, services) => {
            let { uuid, node } = container;
            let [nodeUuid] = uuidRegExp.exec(node);
            _.find(root, (cluster) => {
                let node = _.findWhere(cluster.children, { uuid: nodeUuid });
                if (!node) return;

                let target = _.findWhere(node.children, { uuid }) || {};
                if (!target) return;

                Object.assign(target, container);
                return true;
            });
        },

        data = () => {
            let clone = _.cloneDeep(root);
            _.remove(clone, ({ uuid, children }) => {
                return uuid === 'BYON' && !children.length
            });

            return { root: clone };
        },

        addNodeCluster = (nodeCluster) => {
            var cloned = Object.assign({}, nodeCluster);
            cloned.children = [];
            root.push(cloned);
        },

        removeNodeCluster = (nodeCluster) => {
            _.remove(root, { uuid: nodeCluster.uuid });
        },

        updateNodeCluster = (nodeCluster) => {
            var currentCluster = _.findWhere(root, { uuid: nodeCluster.uuid });
            Object.assign(currentCluster, nodeCluster);
        },

        addNode = (node) => {
            let cloned = Object.assign({}, node);
            cloned.children = [];
            let clusterUuid = "clusterid";
            let cluster = _.findWhere(root, { uuid: clusterUuid });
            if (cluster) cluster.children.push(cloned);
        },
        updateNode = (node, state, spec) => {
            node.state = state;
            node.Spec = spec;
        },
        updateData = (resources) => {
            updateNodes(resources[0]);

            updateContainers(resources[1], resources[2]);
            data();
        },
        updateNodes = (nodes) => {
            let currentnodelist = root[0].children;
            for (let node of nodes) {
                if (!nodeOrContainerExists(currentnodelist, node.ID)) {
                    updateNode(node, 'ready');

                    addNode(node);
                } else {
                    for (let currentnode of currentnodelist) {
                        if (node.ID == currentnode.ID) {
                            name = node.Description.Hostname;
                            if (name.length > 0) {
                                currentnode.Description.Hostname = name;
                                currentnode.name = name + "
" + node.Spec.Role +
                                    "
" + (currentnode.Description.Resources.MemoryBytes / 1024 / 1024 / 1024).toFixed(3) + "G RAM
" +
                                    "" + (currentnode.Description.Platform.Architecture) + "/" + (currentnode.Description.Platform.OS) + "" +
                                    "
";
                                for (var key in node.Spec.Labels) {
                                    if (node.Spec.Labels[key].length > 0) {
                                        currentnode.name += "
" + key + "=" + node.Spec.Labels[key] + "";
                                    } else {
                                        currentnode.name += "
" + key + "";
                                    }
                                }
                                currentnode.name += "
"
                            }
                            updateNode(currentnode, node.state, node.Spec);
                        }
                    }

                }
            }
            for (let node of currentnodelist) {
                if (!nodeOrContainerExists(nodes, node.ID)) {
                    updateNode(node, 'down');
                }
            }
        },
        updateContainers = (containers, services) => {
            let nodes = root[0].children;
            // clearn all current children before rendering
            for (let node of nodes) {
                node.children = [];
            }

            for (let container of containers) {
                let contNodeId = container.NodeID;
                let service = _.find(services, function(o) { return o.ID == container.ServiceID; });
                container.ServiceName = service.Spec.Name;
                for (var i = 0, iLen = nodes.length; i < iLen; i++) {
                    if (nodes[i].ID == contNodeId) {
                        addContainer(container);
                    }
                }

            }

        };

    nodeClusters.forEach(addNodeCluster);
    nodes.forEach(addNode);

    containers.forEach(addContainer);

    return {
        addContainer,
        updateData,
        updateContainer,
        data,
        addNode,
        updateNode,
        addNodeCluster,
        removeNodeCluster,
        updateNodeCluster,
    };
}

class DataProvider extends EventEmitter {
    constructor() {
        super()
    }

    start() {
        STARTED = 1;
        //console.log(STARTED);
        var clusterInit = Promise.all([
                getAllNodes(),
                getAllTasks(),
                getAllServices()
            ])
            .then((resources) => {
                _.remove(resources[1], (nc) => nc.state === 'Empty cluster' || nc.state === 'Terminated');
                return resources;
            });

        Promise.all([clusterInit])
            .then(([resources]) => {
                PHYSICAL_STRUCT = physicalStructProvider(resources);
                this.emit('infrastructure-data', PHYSICAL_STRUCT.data());
                this.emit('start-reload');
            });
    }

    reload() {
        if (STARTED == 0) return;
        STARTED++;

        // console.log(STARTED);
        var clusterInit = Promise.all([
                getAllNodes(),
                getAllTasks(),
                getAllServices()
            ])
            .then((resources) => {
                _.remove(resources[1], (nc) => nc.state === 'Empty cluster' || nc.state === 'Terminated');
                return resources;
            });

        Promise.all([clusterInit])
            .then(([resources]) => {
                if (!PHYSICAL_STRUCT)
                    PHYSICAL_STRUCT = physicalStructProvider(resources);
                PHYSICAL_STRUCT.updateData(resources);
                this.emit('infrastructure-data', PHYSICAL_STRUCT.data());
            });
    }
}

export default SINGLETON = new DataProvider();<|endoftext|>


<commit_before>/* eslint-disable max-statements, max-lines-per-function */

/**
* @license Apache-2.0
*
* Copyright (c) 2020 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var isNumberArray = require( '@stdlib/assert/is-number-array' ).primitives;
var isTypedArrayLike = require( '@stdlib/assert/is-typed-array-like' );
var setReadOnly = require( '@stdlib/utils/define-read-only-property' );
var isObject = require( '@stdlib/assert/is-plain-object' );
var ranks = require( '@stdlib/stats/ranks' );
var normalCDF = require( '@stdlib/stats/base/dists/normal/cdf' ).factory;
var signrankCDF = require( '@stdlib/stats/base/dists/signrank/cdf' );
var tabulate = require( '@stdlib/utils/tabulate' );
var signum = require( '@stdlib/math/base/special/signum' );
var sqrt = require( '@stdlib/math/base/special/sqrt' );
var abs = require( '@stdlib/math/base/special/abs' );
var validate = require( './validate.js' );
var unique = require( './unique.js' );
var print = require( './print.js' ); // eslint-disable-line stdlib/no-redeclare

// VARIABLES //

var pnorm = normalCDF( 0.0, 1.0 );

// MAIN //

/**
* Computes a Wilcoxon signed rank test.
*
* @param {NumericArray} x - data array
* @param {NumericArray} [y] - optional paired data array
* @param {Options} [options] - function options
* @param {number} [options.alpha=0.05] - significance level
* @param {string} [options.alternative='two-sided'] - alternative hypothesis (`two-sided`, `less` or `greater`)
* @param {string} [options.zeroMethod='wilcox'] - method governing how zero-differences are handled (`pratt`, `wilcox` or `zsplit`)
* @param {boolean} [options.correction=true] - continuity correction adjusting the Wilcoxon rank statistic by 0.5 towards the mean
* @param {boolean} [options.exact=false] - whether to force using the exact distribution instead of a normal approximation when there are more than fifty data points
* @param {number} [options.mu=0] - location parameter under H0
* @throws {TypeError} x argument has to be a typed array or array of numbers
* @throws {TypeError} y argument has to be a typed array or array of numbers
* @throws {TypeError} options has to be simple object
* @throws {TypeError} alpha option has to be a number primitive
* @throws {RangeError} alpha option has to be a number in the interval `[0,1]`
* @throws {TypeError} alternative option has to be a string primitive
* @throws {Error} alternative option must be `two-sided`, `less` or `greater`
* @throws {TypeError} zeroMethod option has to be a string primitive
* @throws {Error} zeroMethod option must be `pratt`, `wilcox` or `zsplit`
* @throws {TypeError} correction option has to be a boolean primitive
* @throws {TypeError} exact option has to be a boolean primitive
* @throws {TypeError} mu option has to be a number primitive
* @returns {Object} test result object
*
* @example
* var x = [ 6, 8, 14, 16, 23, 24, 28, 29, 41, -48, 49, 56, 60, -67, 75 ];
* var out = wilcoxon( x, {
*     'mu': 2
* });
*
* @example
* var x = [ 6, 8, 14, 16, 23, 24, 28, 29, 41, -48, 49, 56, 60, -67, 75 ];
* var out = wilcoxon( x, {
*     'alternative': 'greater'
* });
*/
function wilcoxon() {
	var correction;
	var zeroMethod;
	var options;
	var hasTies;
	var counts;
	var repsum;
	var rplus;
	var nzero;
	var rzero;
	var alpha;
	var pval;
	var opts;
	var stat;
	var alt;
	var err;
	var len;
	var tmp;
	var out;
	var ad;
	var mu;
	var mn;
	var se;
	var d;
	var i;
	var r;
	var T;
	var v;
	var x;
	var y;

	x = arguments[ 0 ];
	if ( !isTypedArrayLike( x ) && !isNumberArray( x ) ) {
		throw new TypeError( 'invalid argument. First argument `x` must be a numeric array. Value: `' + x + '`.' );
	}
	len = x.length;
	if ( arguments.length > 1 ) {
		if ( isObject( arguments[ 1 ] ) ) {
			options = arguments[ 1 ];
		}
		else {
			y = arguments[ 1 ];
			if ( !isTypedArrayLike( y ) && !isNumberArray( y ) ) {
				throw new TypeError( 'invalid argument. Argument `y` must be a numeric array. Value: `' + y + '`.' );
			}
			if ( len !== y.length ) {
				throw new Error( 'invalid arguments. Arguments `x` and `y` must be arrays of the same length' );
			}
			if ( arguments.length > 2 ) {
				options = arguments[ 2 ];
			}
		}
	}
	opts = {};
	if ( options ) {
		err = validate( opts, options );
		if ( err ) {
			throw err;
		}
	}
	mu = opts.mu || 0.0;
	correction = opts.correction || true;
	if ( opts.alpha === void 0 ) {
		alpha = 0.05;
	} else {
		alpha = opts.alpha;
	}
	if ( len < 2 ) {
		throw new Error( 'invalid argument. First argument `x` must contain at least two elements. Value: `' + x + '`' );
	}
	alt = opts.alternative || 'two-sided';
	zeroMethod = opts.zeroMethod || 'wilcox';

	if ( zeroMethod === 'wilcox' ) {
		// Only keep all non-zero differences:
		d = [];
		if ( y ) {
			for ( let i = 0; i < len; i++ ) {
				v = ( x[ i ] - y[ i ] ) - mu;
				if ( v !== 0 ) {
					d.push( v );
				}
			}
		} else {
			for ( let i = 0; i < len; i++ ) {
				if ( x[ i ] !== 0 ) {
					d.push( x[ i ] - mu );
				}
			}
		}
		nzero = x.length - d.length;
	} else {
		d = new Array( len );
		nzero = 0;
		if ( y ) {
			for ( i = 0; i < len; i++ ) {
				d[ i ] = ( x[ i ] - y[ i ] ) - mu;
				if ( d[ i ] === 0 ) {
					nzero += 1;
				}
			}
		} else {
			for ( i = 0; i < len; i++ ) {
				d[ i ] = x[ i ] - mu;
				if ( d[ i ] === 0 ) {
					nzero += 1;
				}
			}
		}
	}
	if ( nzero === len ) {
		throw new Error( '`x` or `x - y` cannot be zero for all elements.' );
	}
	// Update length after potentially discarding zero values:
	len = d.length;
	ad = new Array( len );
	for ( i = 0; i < len; i++ ) {
		ad[ i ] = abs( d[ i ] );
	}
	r = ranks( ad );
	rplus = 0;
	rzero = 0;
	for ( let i = 0; i < len; i++ ) {
		if ( d[ i ] > 0 ) {
			rplus += r[ i ];
		}
		else if ( d[ i ] === 0 ) {
			rzero += r[ i ];
		}
	}
	hasTies = unique( r ).length !== r.length;
	if ( zeroMethod === 'zsplit' ) {
		rplus += rzero / 2.0;
	}
	T = rplus;
	mn = len * ( len + 1.0 ) * 0.25;
	se = len * ( len + 1.0 ) * ( ( 2.0 * len ) + 1.0 );

	if ( zeroMethod === 'pratt' ) {
		tmp = [];
		for ( i = 0; i < len; i++ ) {
			if ( d[ i ] !== 0 ) {
				tmp.push( r[ i ] );
			}
		}
		r = tmp;
		mn -= nzero * ( nzero + 1.0 ) * 0.25;
		se -= nzero * ( nzero + 1.0 ) * ( ( 2.0 * nzero ) + 1.0 );
	}
	counts = tabulate( r );
	repsum = 0;
	for ( i = 0; i < counts.length; i++ ) {
		if ( counts[ i ][ 1 ] > 1 ) {
			v = counts[ i ][ 1 ];
			repsum += v * ( (v*v) - 1 );
		}
	}
	if ( repsum > 0 ) {
		// Correction for repeated values:
		se -= 0.5 * repsum;
	}
	se = sqrt( se / 24.0 );

	if (
		( len > 50 && !opts.exact ) ||
		nzero > 0 ||
		hasTies
	) {
		d = 0;
		if ( correction ) {
			switch ( alt ) {
			case 'two-sided':
				d = 0.5 * signum( T - mn );
				break;
			case 'less':
				d = -0.5;
				break;
			default:
				d = 0.5;
				break;
			}
		}
		// Compute test statistic and p-value using normal approximation:
		stat = ( T - mn - d ) / se;
		if ( alt === 'two-sided' ) {
			pval = 2.0 * ( 1.0 - pnorm( abs( stat ) ) );
		} else if ( alt === 'greater' ) {
			pval = 1.0 - pnorm( stat );
		} else {
			pval = pnorm( stat );
		}
	} else {
		// Compute test statistic and p-value using exact critical values:
		stat = T;
		if ( alt === 'two-sided' ) {
			if ( stat > ( len * ( len+1 ) / 4 ) ) {
				pval = 2.0 * ( 1 - signrankCDF( stat - 1, len ) );
			} else {
				pval = 2.0 * signrankCDF( stat, len );
			}
		} else if ( alt === 'greater' ) {
			pval = 1.0 - signrankCDF( stat - 1, len );
		} else {
			pval = signrankCDF( stat, len );
		}
	}
	out = {};
	setReadOnly( out, 'rejected', pval <= alpha );
	setReadOnly( out, 'alpha', alpha );
	setReadOnly( out, 'pValue', pval );
	setReadOnly( out, 'statistic', T );
	setReadOnly( out, 'nullValue', mu );
	setReadOnly( out, 'alternative', alt );
	setReadOnly( out, 'method', ( ( y ) ? 'Paired' : 'One-Sample' ) + ' Wilcoxon signed rank test' );
	setReadOnly( out, 'print', print );
	return out;
}

// EXPORTS //

module.exports = wilcoxon;
<commit_msg>Fix correction option assignment<commit_after>/* eslint-disable max-statements, max-lines-per-function */

/**
* @license Apache-2.0
*
* Copyright (c) 2020 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var isNumberArray = require( '@stdlib/assert/is-number-array' ).primitives;
var isTypedArrayLike = require( '@stdlib/assert/is-typed-array-like' );
var setReadOnly = require( '@stdlib/utils/define-read-only-property' );
var isObject = require( '@stdlib/assert/is-plain-object' );
var ranks = require( '@stdlib/stats/ranks' );
var normalCDF = require( '@stdlib/stats/base/dists/normal/cdf' ).factory;
var signrankCDF = require( '@stdlib/stats/base/dists/signrank/cdf' );
var tabulate = require( '@stdlib/utils/tabulate' );
var signum = require( '@stdlib/math/base/special/signum' );
var sqrt = require( '@stdlib/math/base/special/sqrt' );
var abs = require( '@stdlib/math/base/special/abs' );
var validate = require( './validate.js' );
var unique = require( './unique.js' );
var print = require( './print.js' ); // eslint-disable-line stdlib/no-redeclare

// VARIABLES //

var pnorm = normalCDF( 0.0, 1.0 );

// MAIN //

/**
* Computes a Wilcoxon signed rank test.
*
* @param {NumericArray} x - data array
* @param {NumericArray} [y] - optional paired data array
* @param {Options} [options] - function options
* @param {number} [options.alpha=0.05] - significance level
* @param {string} [options.alternative='two-sided'] - alternative hypothesis (`two-sided`, `less` or `greater`)
* @param {string} [options.zeroMethod='wilcox'] - method governing how zero-differences are handled (`pratt`, `wilcox` or `zsplit`)
* @param {boolean} [options.correction=true] - continuity correction adjusting the Wilcoxon rank statistic by 0.5 towards the mean
* @param {boolean} [options.exact=false] - whether to force using the exact distribution instead of a normal approximation when there are more than fifty data points
* @param {number} [options.mu=0] - location parameter under H0
* @throws {TypeError} x argument has to be a typed array or array of numbers
* @throws {TypeError} y argument has to be a typed array or array of numbers
* @throws {TypeError} options has to be simple object
* @throws {TypeError} alpha option has to be a number primitive
* @throws {RangeError} alpha option has to be a number in the interval `[0,1]`
* @throws {TypeError} alternative option has to be a string primitive
* @throws {Error} alternative option must be `two-sided`, `less` or `greater`
* @throws {TypeError} zeroMethod option has to be a string primitive
* @throws {Error} zeroMethod option must be `pratt`, `wilcox` or `zsplit`
* @throws {TypeError} correction option has to be a boolean primitive
* @throws {TypeError} exact option has to be a boolean primitive
* @throws {TypeError} mu option has to be a number primitive
* @returns {Object} test result object
*
* @example
* var x = [ 6, 8, 14, 16, 23, 24, 28, 29, 41, -48, 49, 56, 60, -67, 75 ];
* var out = wilcoxon( x, {
*     'mu': 2
* });
*
* @example
* var x = [ 6, 8, 14, 16, 23, 24, 28, 29, 41, -48, 49, 56, 60, -67, 75 ];
* var out = wilcoxon( x, {
*     'alternative': 'greater'
* });
*/
function wilcoxon() {
	var correction;
	var zeroMethod;
	var options;
	var hasTies;
	var counts;
	var repsum;
	var rplus;
	var nzero;
	var rzero;
	var alpha;
	var pval;
	var opts;
	var stat;
	var alt;
	var err;
	var len;
	var tmp;
	var out;
	var ad;
	var mu;
	var mn;
	var se;
	var d;
	var i;
	var r;
	var T;
	var v;
	var x;
	var y;

	x = arguments[ 0 ];
	if ( !isTypedArrayLike( x ) && !isNumberArray( x ) ) {
		throw new TypeError( 'invalid argument. First argument `x` must be a numeric array. Value: `' + x + '`.' );
	}
	len = x.length;
	if ( arguments.length > 1 ) {
		if ( isObject( arguments[ 1 ] ) ) {
			options = arguments[ 1 ];
		}
		else {
			y = arguments[ 1 ];
			if ( !isTypedArrayLike( y ) && !isNumberArray( y ) ) {
				throw new TypeError( 'invalid argument. Argument `y` must be a numeric array. Value: `' + y + '`.' );
			}
			if ( len !== y.length ) {
				throw new Error( 'invalid arguments. Arguments `x` and `y` must be arrays of the same length' );
			}
			if ( arguments.length > 2 ) {
				options = arguments[ 2 ];
			}
		}
	}
	opts = {};
	if ( options ) {
		err = validate( opts, options );
		if ( err ) {
			throw err;
		}
	}
	mu = opts.mu || 0.0;
	if ( opts.correction === void 0 ) {
		correction = true;
	} else {
		correction = opts.correction;
	}
	if ( opts.alpha === void 0 ) {
		alpha = 0.05;
	} else {
		alpha = opts.alpha;
	}
	if ( len < 2 ) {
		throw new Error( 'invalid argument. First argument `x` must contain at least two elements. Value: `' + x + '`' );
	}
	alt = opts.alternative || 'two-sided';
	zeroMethod = opts.zeroMethod || 'wilcox';

	if ( zeroMethod === 'wilcox' ) {
		// Only keep all non-zero differences:
		d = [];
		if ( y ) {
			for ( let i = 0; i < len; i++ ) {
				v = ( x[ i ] - y[ i ] ) - mu;
				if ( v !== 0 ) {
					d.push( v );
				}
			}
		} else {
			for ( let i = 0; i < len; i++ ) {
				if ( x[ i ] !== 0 ) {
					d.push( x[ i ] - mu );
				}
			}
		}
		nzero = x.length - d.length;
	} else {
		d = new Array( len );
		nzero = 0;
		if ( y ) {
			for ( i = 0; i < len; i++ ) {
				d[ i ] = ( x[ i ] - y[ i ] ) - mu;
				if ( d[ i ] === 0 ) {
					nzero += 1;
				}
			}
		} else {
			for ( i = 0; i < len; i++ ) {
				d[ i ] = x[ i ] - mu;
				if ( d[ i ] === 0 ) {
					nzero += 1;
				}
			}
		}
	}
	if ( nzero === len ) {
		throw new Error( '`x` or `x - y` cannot be zero for all elements.' );
	}
	// Update length after potentially discarding zero values:
	len = d.length;
	ad = new Array( len );
	for ( i = 0; i < len; i++ ) {
		ad[ i ] = abs( d[ i ] );
	}
	r = ranks( ad );
	rplus = 0;
	rzero = 0;
	for ( let i = 0; i < len; i++ ) {
		if ( d[ i ] > 0 ) {
			rplus += r[ i ];
		}
		else if ( d[ i ] === 0 ) {
			rzero += r[ i ];
		}
	}
	hasTies = unique( r ).length !== r.length;
	if ( zeroMethod === 'zsplit' ) {
		rplus += rzero / 2.0;
	}
	T = rplus;
	mn = len * ( len + 1.0 ) * 0.25;
	se = len * ( len + 1.0 ) * ( ( 2.0 * len ) + 1.0 );

	if ( zeroMethod === 'pratt' ) {
		tmp = [];
		for ( i = 0; i < len; i++ ) {
			if ( d[ i ] !== 0 ) {
				tmp.push( r[ i ] );
			}
		}
		r = tmp;
		mn -= nzero * ( nzero + 1.0 ) * 0.25;
		se -= nzero * ( nzero + 1.0 ) * ( ( 2.0 * nzero ) + 1.0 );
	}
	counts = tabulate( r );
	repsum = 0;
	for ( i = 0; i < counts.length; i++ ) {
		if ( counts[ i ][ 1 ] > 1 ) {
			v = counts[ i ][ 1 ];
			repsum += v * ( (v*v) - 1 );
		}
	}
	if ( repsum > 0 ) {
		// Correction for repeated values:
		se -= 0.5 * repsum;
	}
	se = sqrt( se / 24.0 );

	if (
		( len > 50 && !opts.exact ) ||
		nzero > 0 ||
		hasTies
	) {
		d = 0;
		if ( correction ) {
			switch ( alt ) {
			case 'two-sided':
				d = 0.5 * signum( T - mn );
				break;
			case 'less':
				d = -0.5;
				break;
			default:
				d = 0.5;
				break;
			}
		}
		// Compute test statistic and p-value using normal approximation:
		stat = ( T - mn - d ) / se;
		if ( alt === 'two-sided' ) {
			pval = 2.0 * ( 1.0 - pnorm( abs( stat ) ) );
		} else if ( alt === 'greater' ) {
			pval = 1.0 - pnorm( stat );
		} else {
			pval = pnorm( stat );
		}
	} else {
		// Compute test statistic and p-value using exact critical values:
		stat = T;
		if ( alt === 'two-sided' ) {
			if ( stat > ( len * ( len+1 ) / 4 ) ) {
				pval = 2.0 * ( 1 - signrankCDF( stat - 1, len ) );
			} else {
				pval = 2.0 * signrankCDF( stat, len );
			}
		} else if ( alt === 'greater' ) {
			pval = 1.0 - signrankCDF( stat - 1, len );
		} else {
			pval = signrankCDF( stat, len );
		}
	}
	out = {};
	setReadOnly( out, 'rejected', pval <= alpha );
	setReadOnly( out, 'alpha', alpha );
	setReadOnly( out, 'pValue', pval );
	setReadOnly( out, 'statistic', T );
	setReadOnly( out, 'nullValue', mu );
	setReadOnly( out, 'alternative', alt );
	setReadOnly( out, 'method', ( ( y ) ? 'Paired' : 'One-Sample' ) + ' Wilcoxon signed rank test' );
	setReadOnly( out, 'print', print );
	return out;
}

// EXPORTS //

module.exports = wilcoxon;
<|endoftext|>


<commit_before>'use strict';

// MODULES //

var isString = require( '@stdlib/utils/is-string' ).isPrimitive;
var isFunction = require( '@stdlib/utils/is-function' );
var copy = require( '@stdlib/utils/copy' );
var cwd = require( '@stdlib/utils/cwd' );
var defaults = require( './defaults.json' );
var validate = require( './validate.js' );
var evaluate = require( './vm_evaluate.js' );
var transform = require( './transform.js' );

// VARIABLES //

var FILENAME = 'timeit.js';
var MIN_TIME = 0.1; // seconds
var ITERATIONS = 10; // 10^1
var MAX_ITERATIONS = 10000000000; // 10^10

// MAIN //

/**
* Times a snippet.
*
* @param {string} code - snippet to time
* @param {Options} [options] - function options
* @param {string} [options.before=""] - setup code
* @param {string} [options.after=""] - cleanup code
* @param {(PositiveInteger|null)} [options.iterations=1e6] - number of iterations
* @param {PositiveInteger} [options.repeats=3] - number of repeats
* @param {boolean} [options.asynchronous=false] - boolean indicating whether a snippet is asynchronous
* @param {Callback} clbk - callback to invoke upon completion
* @throws {TypeError} first argument must be a string
* @throws {TypeError} options argument must be an object
* @throws {TypeError} must provide valid options
* @throws {TypeError} callback argument must be a function
*
* @example
* var code = '';
* code += 'var x = Math.pow( Math.random(), 3 );';
* code += 'if ( x !== x ) {';
* code += 'throw new Error( \'Something went wrong.\' );';
* code += '}';
*
* timeit( code, done );
*
* function done( error, results ) {
*     if ( error ) {
*         throw error;
*     }
*     console.dir( results );
* }
*/
function timeit( code, options, clbk ) {
	var results;
	var opts;
	var dir;
	var err;
	var idx;
	var cb;

	if ( !isString( code ) ) {
		throw new TypeError( 'invalid input argument. First argument must be a primitive string. Value: `' + code + '`.' );
	}
	opts = copy( defaults );
	if ( arguments.length === 2 ) {
		cb = options;
	} else {
		cb = clbk;
		err = validate( opts, options );
		if ( err ) {
			throw err;
		}
	}
	if ( !isFunction( cb ) ) {
		throw new TypeError( 'invalid input argument. Callback argument must be a function. Value: `' + cb + '`.' );
	}
	results = new Array( opts.repeats );
	dir = cwd();
	idx = 0;

	// Pretest to check for early returns and/or errors...
	try {
		evaluate( code, opts, FILENAME, dir, onTest );
	} catch ( error ) {
		err = new Error( 'evaluation error. Encountered an error when evaluating snippet. '+error.message );
		return done( err );
	}

	/**
	* Evaluates a code snippet on the next turn of the event loop. Waiting until the next turn avoids the current turn being bogged down by a long running queue.
	*
	* @private
	* @param {Callback} clbk - callback
	*/
	function next( clbk ) {
		process.nextTick( onTick );
		/**
		* Callback invoked upon next turn of event loop.
		*
		* @private
		*/
		function onTick() {
			evaluate( code, opts, FILENAME, dir, clbk );
		} // end FUNCTION onTick()
	} // end FUNCTION next()

	/**
	* Callback invoked after completing pretest.
	*
	* @private
	* @param {(Error|null)} error - error object
	*/
	function onTest( error ) {
		if ( error ) {
			return done( error );
		}
		if ( opts.iterations === null ) {
			opts.iterations = ITERATIONS;
			return next( onRun );
		}
		// Begin timing the snippet...
		return next( onFinish );
	} // end FUNCTION onTest()

	/**
	* Callback invoked upon running a pre-run to determine the number of iterations.
	*
	* @private
	* @param {(Error|null)} error - error object
	* @param {NonNegativeIntegerArray} time - results
	*/
	function onRun( error, time ) {
		var t;
		if ( error ) {
			return done( error );
		}
		t = time[ 0 ] + time[ 1 ]/1e9;
		if (
			t < MIN_TIME &&
			opts.iterations < MAX_ITERATIONS
		) {
			opts.iterations *= 10;
			return next( onRun );
		}
		// Begin timing the snippet...
		return next( onFinish );
	} // end FUNCTION onRun()

	/**
	* Callback invoked upon executing code.
	*
	* @private
	* @param {(Error|null)} error - error object
	* @param {NonNegativeIntegerArray} time - results
	*/
	function onFinish( error, time ) {
		if ( error ) {
			return done( error );
		}
		results[ idx ] = time;
		idx += 1;
		if ( idx < opts.repeats ) {
			return next( onFinish );
		}
		done( null, results );
	} // end FUNCTION onFinish()

	/**
	* Callback invoked upon completion.
	*
	* @private
	* @param {(Error|null)} error - error object
	* @param {ArrayArray} results - raw results
	*/
	function done( error, results ) {
		var out;
		if ( !error ) {
			out = transform( results, opts.iterations );
		}
		// Avoid releasing the zalgo:
		process.nextTick( onTick );
		/**
		* Callback invoked upon the next tick.
		*
		* @private
		*/
		function onTick() {
			if ( error ) {
				return cb( error );
			}
			cb( null, out );
		} // end FUNCTION onTick()
	} // end FUNCTION done()
} // end FUNCTION timeit()

// EXPORTS //

module.exports = timeit;
<commit_msg>Add check that timing results are returned during pre-test<commit_after>'use strict';

// MODULES //

var isString = require( '@stdlib/utils/is-string' ).isPrimitive;
var isFunction = require( '@stdlib/utils/is-function' );
var isArray = require( '@stdlib/utils/is-array' );
var copy = require( '@stdlib/utils/copy' );
var cwd = require( '@stdlib/utils/cwd' );
var defaults = require( './defaults.json' );
var validate = require( './validate.js' );
var evaluate = require( './vm_evaluate.js' );
var transform = require( './transform.js' );

// VARIABLES //

var FILENAME = 'timeit.js';
var MIN_TIME = 0.1; // seconds
var ITERATIONS = 10; // 10^1
var MAX_ITERATIONS = 10000000000; // 10^10

// MAIN //

/**
* Times a snippet.
*
* @param {string} code - snippet to time
* @param {Options} [options] - function options
* @param {string} [options.before=""] - setup code
* @param {string} [options.after=""] - cleanup code
* @param {(PositiveInteger|null)} [options.iterations=1e6] - number of iterations
* @param {PositiveInteger} [options.repeats=3] - number of repeats
* @param {boolean} [options.asynchronous=false] - boolean indicating whether a snippet is asynchronous
* @param {Callback} clbk - callback to invoke upon completion
* @throws {TypeError} first argument must be a string
* @throws {TypeError} options argument must be an object
* @throws {TypeError} must provide valid options
* @throws {TypeError} callback argument must be a function
*
* @example
* var code = '';
* code += 'var x = Math.pow( Math.random(), 3 );';
* code += 'if ( x !== x ) {';
* code += 'throw new Error( \'Something went wrong.\' );';
* code += '}';
*
* timeit( code, done );
*
* function done( error, results ) {
*     if ( error ) {
*         throw error;
*     }
*     console.dir( results );
* }
*/
function timeit( code, options, clbk ) {
	var results;
	var opts;
	var dir;
	var err;
	var idx;
	var cb;

	if ( !isString( code ) ) {
		throw new TypeError( 'invalid input argument. First argument must be a primitive string. Value: `' + code + '`.' );
	}
	opts = copy( defaults );
	if ( arguments.length === 2 ) {
		cb = options;
	} else {
		cb = clbk;
		err = validate( opts, options );
		if ( err ) {
			throw err;
		}
	}
	if ( !isFunction( cb ) ) {
		throw new TypeError( 'invalid input argument. Callback argument must be a function. Value: `' + cb + '`.' );
	}
	results = new Array( opts.repeats );
	dir = cwd();
	idx = 0;

	// Pretest to check for early returns and/or errors...
	try {
		evaluate( code, opts, FILENAME, dir, onTest );
	} catch ( error ) {
		err = new Error( 'evaluation error. Encountered an error when evaluating snippet. '+error.message );
		return done( err );
	}

	/**
	* Evaluates a code snippet on the next turn of the event loop. Waiting until the next turn avoids the current turn being bogged down by a long running queue.
	*
	* @private
	* @param {Callback} clbk - callback
	*/
	function next( clbk ) {
		process.nextTick( onTick );
		/**
		* Callback invoked upon next turn of event loop.
		*
		* @private
		*/
		function onTick() {
			evaluate( code, opts, FILENAME, dir, clbk );
		} // end FUNCTION onTick()
	} // end FUNCTION next()

	/**
	* Callback invoked after completing pretest.
	*
	* @private
	* @param {(Error|null)} error - error object
	* @param {NonNegativeIntegerArray} time - results
	*/
	function onTest( error, time ) {
		if ( error ) {
			return done( error );
		}
		if ( !isArray( time ) || time.length !== 2 ) {
			// This should only happen if someone is a bad actor and attempts to call the `done` callback without providing timing results.
			error = new Error( 'evaluation error. Did not receive timing results.' );
			return done( error );
		}
		if ( opts.iterations === null ) {
			opts.iterations = ITERATIONS;
			return next( onRun );
		}
		// Begin timing the snippet...
		return next( onFinish );
	} // end FUNCTION onTest()

	/**
	* Callback invoked upon running a pre-run to determine the number of iterations.
	*
	* @private
	* @param {(Error|null)} error - error object
	* @param {NonNegativeIntegerArray} time - results
	*/
	function onRun( error, time ) {
		var t;
		if ( error ) {
			return done( error );
		}
		t = time[ 0 ] + time[ 1 ]/1e9;
		if (
			t < MIN_TIME &&
			opts.iterations < MAX_ITERATIONS
		) {
			opts.iterations *= 10;
			return next( onRun );
		}
		// Begin timing the snippet...
		return next( onFinish );
	} // end FUNCTION onRun()

	/**
	* Callback invoked upon executing code.
	*
	* @private
	* @param {(Error|null)} error - error object
	* @param {NonNegativeIntegerArray} time - results
	*/
	function onFinish( error, time ) {
		if ( error ) {
			return done( error );
		}
		results[ idx ] = time;
		idx += 1;
		if ( idx < opts.repeats ) {
			return next( onFinish );
		}
		done( null, results );
	} // end FUNCTION onFinish()

	/**
	* Callback invoked upon completion.
	*
	* @private
	* @param {(Error|null)} error - error object
	* @param {ArrayArray} results - raw results
	*/
	function done( error, results ) {
		var out;
		if ( !error ) {
			out = transform( results, opts.iterations );
		}
		// Avoid releasing the zalgo:
		process.nextTick( onTick );
		/**
		* Callback invoked upon the next tick.
		*
		* @private
		*/
		function onTick() {
			if ( error ) {
				return cb( error );
			}
			cb( null, out );
		} // end FUNCTION onTick()
	} // end FUNCTION done()
} // end FUNCTION timeit()

// EXPORTS //

module.exports = timeit;
<|endoftext|>


<commit_before>var assert = require('assert');
var tokenHelper = require('../token-helper');
var allOperators = require('../utils').binaryOperators;

module.exports = function() {};

module.exports.prototype = {

    configure: function(operators) {
        var isTrue = operators === true;

        assert(
            Array.isArray(operators) || isTrue,
            'requireSpaceBeforeBinaryOperators option requires array or true value'
        );

        if (isTrue) {
            operators = allOperators;
        }

        this._operatorIndex = {};
        for (var i = 0, l = operators.length; i < l; i++) {
            this._operatorIndex[operators[i]] = true;
        }
    },

    getOptionName: function() {
        return 'disallowSpaceBeforeBinaryOperators';
    },

    check: function(file, errors) {
        var operators = this._operatorIndex;

        function errorIfApplicable(token, i, tokens, operator) {
            var prevToken = tokens[i - 1];

            if (prevToken && prevToken.range[1] !== token.range[0]) {
                var loc = token.loc.start;

                errors.add(
                    'Operator ' + operator + ' should stick to preceding expression',
                    loc.line,
                    tokenHelper.getPointerEntities(loc.column, token.value.length)
                );
            }
        }

        // ":" for object property only but not for ternar
        if (operators[':']) {
            file.iterateNodesByType(['ObjectExpression'], function(node) {
                node.properties.forEach(function(prop) {
                    var token = tokenHelper.findOperatorByRangeStart(file, prop.range[0], ':'),
                        tokens = file.getTokens();

                    errorIfApplicable(token, tokens.indexOf( token ), tokens, ':');
                });
            });
        }

        // Comma
        if (operators[',']) {
            file.iterateTokensByType('Punctuator', function(token, i, tokens) {
                var operator = token.value;
                if (operator !== ',') {
                    return;
                }

                errorIfApplicable( token, i, tokens, operator );
            });
        }

        // For everything else
        file.iterateNodesByType(
            ['BinaryExpression', 'AssignmentExpression', 'LogicalExpression'],
            function(node) {
                if (operators[node.operator]) {
                    var part = tokenHelper.getTokenByRangeStartIfPunctuator(
                        file,
                        node.left.range[1],
                        node.operator
                    );

                    if (!part) {
                        errors.add(
                            'Operator ' + node.operator + ' should stick to preceding expression',
                            tokenHelper.findOperatorByRangeStart(
                                file, node.right.range[0], node.operator, true
                            ).loc.start
                        );
                    }
                }
            }
        );
    }

};
<commit_msg>Fix typo in error message<commit_after>var assert = require('assert');
var tokenHelper = require('../token-helper');
var allOperators = require('../utils').binaryOperators;

module.exports = function() {};

module.exports.prototype = {

    configure: function(operators) {
        var isTrue = operators === true;

        assert(
            Array.isArray(operators) || isTrue,
            'disallowSpaceBeforeBinaryOperators option requires array or true value'
        );

        if (isTrue) {
            operators = allOperators;
        }

        this._operatorIndex = {};
        for (var i = 0, l = operators.length; i < l; i++) {
            this._operatorIndex[operators[i]] = true;
        }
    },

    getOptionName: function() {
        return 'disallowSpaceBeforeBinaryOperators';
    },

    check: function(file, errors) {
        var operators = this._operatorIndex;

        function errorIfApplicable(token, i, tokens, operator) {
            var prevToken = tokens[i - 1];

            if (prevToken && prevToken.range[1] !== token.range[0]) {
                var loc = token.loc.start;

                errors.add(
                    'Operator ' + operator + ' should stick to preceding expression',
                    loc.line,
                    tokenHelper.getPointerEntities(loc.column, token.value.length)
                );
            }
        }

        // ":" for object property only but not for ternar
        if (operators[':']) {
            file.iterateNodesByType(['ObjectExpression'], function(node) {
                node.properties.forEach(function(prop) {
                    var token = tokenHelper.findOperatorByRangeStart(file, prop.range[0], ':'),
                        tokens = file.getTokens();

                    errorIfApplicable(token, tokens.indexOf( token ), tokens, ':');
                });
            });
        }

        // Comma
        if (operators[',']) {
            file.iterateTokensByType('Punctuator', function(token, i, tokens) {
                var operator = token.value;
                if (operator !== ',') {
                    return;
                }

                errorIfApplicable( token, i, tokens, operator );
            });
        }

        // For everything else
        file.iterateNodesByType(
            ['BinaryExpression', 'AssignmentExpression', 'LogicalExpression'],
            function(node) {
                if (operators[node.operator]) {
                    var part = tokenHelper.getTokenByRangeStartIfPunctuator(
                        file,
                        node.left.range[1],
                        node.operator
                    );

                    if (!part) {
                        errors.add(
                            'Operator ' + node.operator + ' should stick to preceding expression',
                            tokenHelper.findOperatorByRangeStart(
                                file, node.right.range[0], node.operator, true
                            ).loc.start
                        );
                    }
                }
            }
        );
    }

};
<|endoftext|>


<commit_before>function calcItem(item) {
  if(item.type == "input") {
    // check if card already exists or return default
    if($('#wrapper input[name="' + item.variable + '"]').length) {
      result = $('#wrapper input[name="' + item.variable + '"]').val();
    } else {
      result = item.attributes.default;
    }
  } else {
    // get formula
    var formula = item.attributes.formula;

    // get current values of input and prepare values of output variables
    $.each(config.items, function(index, element) {
      variable = new RegExp(element.variable, 'g');

      if(element.type == "input") {
        formula = formula.replace(variable, calcItem(element));
      } else {
        // check if element already exists
        if($('#wrapper input[name="' + element.variable + '"]').length) {
          formula = formula.replace(variable, $('#wrapper input[name="' + element.variable + '"]').val());
        } else {
          formula = formula.replace(variable, element.attributes.default);
        }
      }
    });

    // prepare output variable
    result = eval(formula);
  }

  // check limits
  if((item.attributes.max !== null) && (result > item.attributes.max)) {
    result = item.attributes.max;
  } else if ((item.attributes.min !== null) && (result < item.attributes.min)) {
    result = item.attributes.min;
  }

  // return result
  return result;
}
<commit_msg>adding round function for output variables<commit_after>function calcItem(item) {
  if(item.type == "input") {
    // check if card already exists or return default
    if($('#wrapper input[name="' + item.variable + '"]').length) {
      result = $('#wrapper input[name="' + item.variable + '"]').val();
    } else {
      result = item.attributes.default;
    }
  } else {
    // get formula
    var formula = item.attributes.formula;

    // get current values of input and prepare values of output variables
    $.each(config.items, function(index, element) {
      variable = new RegExp(element.variable, 'g');

      if(element.type == "input") {
        formula = formula.replace(variable, calcItem(element));
      } else {
        // check if element already exists
        if($('#wrapper input[name="' + element.variable + '"]').length) {
          formula = formula.replace(variable, $('#wrapper input[name="' + element.variable + '"]').val());
        } else {
          formula = formula.replace(variable, element.attributes.default);
        }
      }
    });

    // prepare output variable
    result = eval(formula);
  }

  // check limits
  if((item.attributes.max !== null) && (result > item.attributes.max)) {
    result = item.attributes.max;
  } else if ((item.attributes.min !== null) && (result < item.attributes.min)) {
    result = item.attributes.min;
  }

  // round result
  if((item.attributes.round !== null) && (item.type == "output")) {
    result = Math.round(result, item.attributes.round);
  }

  // return result
  return result;
}
<|endoftext|>


<commit_before>function organize() {
	$(function() {
		var navHeight = (window.innerHeight - $('#nav').height()) / 2;
		var contentHeight = (window.innerHeight - $('#content').height()) / 2;
		$('#nav').offset({top: navHeight, left: 10});
		$('#content').offset({top: contentHeight});
	});
}
<commit_msg>shifted everything up a little<commit_after>function organize() {
	$(function() {
		var navHeight = (window.innerHeight - $('#nav').height()) / 2 * 0.8;
		var contentHeight = (window.innerHeight - $('#content').height()) / 2 * 0.8;
		$('#nav').offset({top: navHeight, left: 10});
		$('#content').offset({top: contentHeight});
	});
}
<|endoftext|>


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

'use strict';
var fs = require('fs');

var angular = require('camunda-bpm-sdk-js/vendor/angular'),
    $ = require('jquery'),

    template = fs.readFileSync(__dirname + '/cam-widget-inline-field.html', 'utf8');

module.exports = [
  '$timeout',
  '$filter',
  '$document',
  function(
    $timeout,
    $filter,
    $document
  ) {

    return {
      scope: {
        varValue:       '=value',
        varType:        '@type',
        validator:      '&validate',
        change:         '&',
        onStart:        '&onStartEditing',
        onCancel:       '&onCancelEditing',

        placeholder:    '@',
        options:        '=?',
        allowNonOptions:'@',
        flexible:       '@',

        disableAutoselect: '=?'
      },

      template: template,

      link: function(scope, element) {
        var $bdyEl = $('body');
        var $btnsEl;
        var $ctrlsEl;

        var dateFilter = $filter('date'),
            dateFormat = 'yyyy-MM-dd\'T\'HH:mm:ss';

        var dateRegex = /(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)(?:.(\d\d\d)| )?$/;

        scope.editing = false;

        scope.isNumber = scope.varType === 'number';

        scope.$on('$locationChangeSuccess', function() {
          scope.cancelChange();
        });
        scope.$on('$destroy', function() {
          removeFromBody(true);
        });

        function convertDateStringToObject(date) {
          var YEAR, MONTH, DAY, HOURS, MINUTES, SECONDS, MILLISECONDS;

          var match = dateRegex.exec(date);

          if (match) {
            YEAR = parseInt(match[1] || 0, 10);
            MONTH = parseInt(match[2] || 0, 10) - 1;
            DAY = parseInt(match[3] || 0, 10);
            HOURS = parseInt(match[4] || 0, 10);
            MINUTES = parseInt(match[5] || 0, 10);
            SECONDS = parseInt(match[6] || 0, 10);
            MILLISECONDS = parseInt(match[7] || 0, 10);
            return new Date(YEAR, MONTH, DAY, HOURS, MINUTES, SECONDS, MILLISECONDS);
          }
        }

        function isDate() {
          return ['datetime', 'date', 'time'].indexOf(scope.varType) > -1;
        }

        function isSimpleField() {
          return ['color', 'email', 'month', 'number', 'range', 'tel', 'text', 'time', 'url', 'week'].indexOf(scope.varType) > -1;
        }

        function reset() {
          scope.editing =       false;
          scope.invalid =       false;
          scope.editValue =     scope.varValue;

          scope.validator =     scope.validator ||     function() {};
          scope.onStart =       scope.onStart ||       function() {};
          scope.onCancel =      scope.onCancel ||      function() {};
          scope.change =        scope.change ||        function() {};
          scope.options =       scope.options ||       [];
          scope.allowNonOptions=scope.allowNonOptions || false;
          scope.flexible =      scope.flexible ||      false;

          scope.varType =       scope.varType ? scope.varType : 'text';

          scope.simpleField = isSimpleField();

          if (isDate()) {
            var dateStr = scope.varValue,
                dateObj = null;

            if (dateStr) {
              dateObj = convertDateStringToObject(dateStr);
            } else {
              dateObj = Date.now();
            }

            scope.dateValue = dateObj;
          }
        }

        function bodyDirectChild($el) {
          if (!$el || !$el.length) {
            return false;
          }

          var $parent = $el.parent();
          if (!$parent || !$parent.length) {
            return false;
          }

          return $parent[0].tagName.toLowerCase() === 'body';
        }

        function positionElements() {
          var offset = $(element).offset();

          if(isDate()) {
            $btnsEl
              .addClass('datepicker-control')
              .show()
              .css({
                left: offset.left + ($ctrlsEl.outerWidth() - $btnsEl.outerWidth()),
                top: offset.top + $ctrlsEl.outerHeight()
              });
          } else {
            $btnsEl
              .removeClass('datepicker-control')
              .show()
              .css({
                left: offset.left + ($(element).outerWidth() - $btnsEl.outerWidth()),
                top: offset.top - $btnsEl.outerHeight()
              });
          }

          $ctrlsEl
            .show()
            .css({
              left: offset.left,
              top: offset.top + $(element).outerHeight()
            });

          if (isDate()) {
            var $datepickerEl = $ctrlsEl[0].querySelector('.uib-daypicker');

            if ($datepickerEl) {
              $datepickerEl.focus();
            }
          }

        }

        function appendToBody() {
          $ctrlsEl = (($ctrlsEl && $ctrlsEl.length) ? $ctrlsEl : $(element[0].querySelector('.field-control')))
            .hide();
          if (!bodyDirectChild($ctrlsEl)) {
            $bdyEl
              .append($ctrlsEl);
          }

          $btnsEl = (($btnsEl && $btnsEl.length) ? $btnsEl : $(element[0].querySelector('.btn-group')))
            .hide();
          if (!bodyDirectChild($btnsEl)) {
            $bdyEl
              .append($btnsEl);
          }

          $timeout(positionElements, 50);
        }

        function removeFromBody(force) {
          $timeout(function() {
            if (scope.editing && !force) { return; }

            if ($btnsEl && $btnsEl.remove) {
              $btnsEl.remove();
            }
            $btnsEl = null;

            if ($ctrlsEl && $ctrlsEl.remove) {
              $ctrlsEl.remove();
            }
            $ctrlsEl = null;
          }, 50);
        }

        function bodyClicked(evt) {
          return element[0].contains(evt.target) ||
            ($btnsEl && $btnsEl.length && $btnsEl[0].contains(evt.target)) ||
            ($ctrlsEl && $ctrlsEl.length && $ctrlsEl[0].contains(evt.target));
        }

        scope.$watch('editing', function(after, before) {
          if (after === before) { return; }

          if (scope.editing) {
            appendToBody();
            element.addClass('inline-editing');
          }
          else {
            removeFromBody();
            element.removeClass('inline-editing');
          }
        });

        function stopEditing(evt) {
          if(!scope.editing) {
            return;
          }

          if(bodyClicked(evt)) {
            return;
          }

          var targetElement = $(evt.target),
              expectedClasses = 'ng-binding text-muted';

          if (targetElement.hasClass(expectedClasses)) {
            return;
          }

          var children = targetElement.children();
          if (children.hasClass(expectedClasses)) {
            return;
          }

          scope.$apply(scope.cancelChange);
        }

        scope.changeType = function() {
          if(scope.varType === 'datetime') {
            scope.varType = 'text';
          } else {
            scope.varType = 'datetime';
          }
          reset();
          scope.editing = true;
          element[0].attributes.type.value = scope.varType;
          scope.simpleField = isSimpleField();
        };

        scope.startEditing = function() {
          if(!scope.editing) {
            reset();

            scope.editing = true;
            scope.onStart(scope);

            // save the current edit value to restore later
            var savedEditValue = scope.editValue;

            // clear the edit value so that typeahead shows all options
            // should not apply to simpleFields
            if (!scope.simpleField) {
              scope.editValue = '';
            }

            // Here is where it gets ugly: We have to wait for angular to apply the changes to the edit value, so that the
            // input field is rendered and we can open the typeahead dropdown (first timeout). However, the instantTypeahead directive does
            // not immediately register its functions to prevent IE from going crazy. Therefore, we have to wait for another cycle
            // (second timeout), before triggering an input event on the input field can open the instant typeahead dropdown.
            $timeout(function() {
              $timeout(function() {
                // and reset the edit value, so that the user can type
                scope.editValue = savedEditValue;

                // in the next apply cycle, the dropdown is open. We now have to
                // select the default value, if it exists:
                if(savedEditValue) {
                  var isValueOfTypeObject = typeof savedEditValue === 'object';
                  if (isValueOfTypeObject) {
                    angular.element(element[0].querySelector('[ng-model="editValue"]')).val(savedEditValue.value);
                  }

                  $timeout(function() {
                    var elems = $(element[0].querySelector('li[ng-mouseenter]'));
                    var compareValue = isValueOfTypeObject ? savedEditValue.value : savedEditValue;

                    for(var i = 0; i < elems.length; i++) {
                      var elem = elems[i];
                      if(elem.innerText.indexOf(compareValue) === 0) {
                        $(elem).trigger('mouseenter');
                        return;
                      }
                    }
                  });
                }
              });
            });

            $timeout(function() {
              angular.element(element[0].querySelector('[ng-model="editValue"]')).triggerHandler('click');

              $timeout(function() {
                $('[ng-model="editValue"]').focus();
                $('[ng-model="editValue"]').select();
                $document.bind('click', stopEditing);
              }, 50);
            });
          }
        };

        scope.applyChange = function(selection, evt) {
          scope.invalid = scope.validator(scope);

          if (!scope.invalid) {

            if(scope.simpleField) {
              scope.editValue = parseValue(
                $('[ng-model="editValue"]').val()
              );

              scope.varValue = scope.editValue;
            }
            else if (scope.varType === 'option') {
              if(scope.options.indexOf(selection) === -1 && !scope.allowNonOptions) {
                scope.cancelChange();
                return;
              }
              scope.editValue = selection || $('[ng-model="editValue"]').val();
              scope.varValue = scope.editValue;
            }
            else if (isDate()) {
              scope.varValue = dateFilter(scope.dateValue, dateFormat);
            }

            scope.$event = evt;
            scope.change(scope);

            scope.editing = false;

            $document.unbind('click', stopEditing);
          }
        };

        function parseValue(value) {
          if (scope.varType === 'number') {
            if (value.length > 0) {
              return +value;
            }

            return null;
          }

          return value;
        }

        scope.cancelChange = function() {
          if(scope.editing) {
            scope.editing = false;
            scope.onCancel(scope);

            $document.unbind('click', stopEditing);
          }
        };

        scope.changeDate = function(pickerScope) {
          scope.editValue = scope.dateValue = pickerScope.dateValue;
        };

        scope.selectNextInlineField = function(reversed) {
          var allFields = $('[cam-widget-inline-field][type=\'text\'], [cam-widget-inline-field][type=\'option\']');
          for(var i = reversed*(allFields.length - 1); i !== !reversed*(allFields.length-1); i += !reversed*2-1) {

            if(allFields[i] === element[0]) {
              $timeout(function() {
                var element = $(allFields[i+!reversed*2-1]);
                element.find('.view-value').click();
                // after clicking the next inline field, wait for the input to appear, then select all
                $timeout(function() {
                  element.find('input').select();
                });
              });
              return;
            }
          }
          // take the first/last one
          $timeout(function() {
            $(allFields[reversed*allFields.length - 1]).find('.view-value').click();
          });
        };

        scope.trapKeyboard = function(evt, reverse) {
          if(isDate() && evt.keyCode === 9) {
            // only trap tab key on date inputs
            if(!reverse && !evt.shiftKey) {
              // focus the date picker
              $('.cam-widget-inline-field.field-control > .datepicker > table')[0].focus();
              evt.preventDefault();
            } else if(reverse && evt.shiftKey) {
              // focus the cancel button
              $('.cam-widget-inline-field.btn-group > button[ng-click="cancelChange($event)"]')[0].focus();
              evt.preventDefault();
            }
          }
        };

        scope.cancelOnEsc = function(evt) {
          if(isDate() && evt.keyCode === 27) {
            scope.cancelChange();
          }
        };

        scope.handleKeydown = function(evt) {
          if(evt.keyCode === 13) {
            scope.applyChange(scope.selection, evt);
            evt.preventDefault();
          } else if(evt.keyCode === 27) {
            scope.cancelChange(evt);
            evt.preventDefault();
          } else if(evt.keyCode === 9) {
            scope.applyChange(scope.selection, evt);
            scope.selectNextInlineField(evt.shiftKey);
            evt.preventDefault();
          }
          scope.selection = null;
        };

        scope.selection = null;
        scope.saveSelection = function(selection) {
          scope.selection = selection;
          $timeout(function() {
            // check if the selection has been applied
            if(scope.selection === selection) {
              scope.applyChange(selection);
            }
          });
        };

      },

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

'use strict';
var fs = require('fs');

var angular = require('camunda-bpm-sdk-js/vendor/angular'),
    $ = require('jquery'),

    template = fs.readFileSync(__dirname + '/cam-widget-inline-field.html', 'utf8');

module.exports = [
  '$timeout',
  '$filter',
  '$document',
  function(
    $timeout,
    $filter,
    $document
  ) {

    return {
      scope: {
        varValue:       '=value',
        varType:        '@type',
        validator:      '&validate',
        change:         '&',
        onStart:        '&onStartEditing',
        onCancel:       '&onCancelEditing',

        placeholder:    '@',
        options:        '=?',
        allowNonOptions:'@',
        flexible:       '@',

        disableAutoselect: '=?'
      },

      template: template,

      link: function(scope, element) {
        var $bdyEl = $('body');
        var $btnsEl;
        var $ctrlsEl;

        var dateFilter = $filter('date'),
            dateFormat = 'yyyy-MM-dd\'T\'HH:mm:ss';

        var dateRegex = /(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)(?:.(\d\d\d)| )?$/;

        scope.editing = false;

        scope.isNumber = scope.varType === 'number';

        scope.$on('$locationChangeSuccess', function() {
          scope.cancelChange();
        });
        scope.$on('$destroy', function() {
          removeFromBody(true);
        });

        function convertDateStringToObject(date) {
          var YEAR, MONTH, DAY, HOURS, MINUTES, SECONDS, MILLISECONDS;

          var match = dateRegex.exec(date);

          if (match) {
            YEAR = parseInt(match[1] || 0, 10);
            MONTH = parseInt(match[2] || 0, 10) - 1;
            DAY = parseInt(match[3] || 0, 10);
            HOURS = parseInt(match[4] || 0, 10);
            MINUTES = parseInt(match[5] || 0, 10);
            SECONDS = parseInt(match[6] || 0, 10);
            MILLISECONDS = parseInt(match[7] || 0, 10);
            return new Date(YEAR, MONTH, DAY, HOURS, MINUTES, SECONDS, MILLISECONDS);
          }
        }

        function isDate() {
          return ['datetime', 'date', 'time'].indexOf(scope.varType) > -1;
        }

        function isSimpleField() {
          return ['color', 'email', 'month', 'number', 'range', 'tel', 'text', 'time', 'url', 'week'].indexOf(scope.varType) > -1;
        }

        function reset() {
          scope.editing =       false;
          scope.invalid =       false;
          scope.editValue =     scope.varValue;

          scope.validator =     scope.validator ||     function() {};
          scope.onStart =       scope.onStart ||       function() {};
          scope.onCancel =      scope.onCancel ||      function() {};
          scope.change =        scope.change ||        function() {};
          scope.options =       scope.options ||       [];
          scope.allowNonOptions=scope.allowNonOptions || false;
          scope.flexible =      scope.flexible ||      false;

          scope.varType =       scope.varType ? scope.varType : 'text';

          scope.simpleField = isSimpleField();

          if (isDate()) {
            var dateStr = scope.varValue,
                dateObj = null;

            if (dateStr) {
              dateObj = convertDateStringToObject(dateStr);
            } else {
              dateObj = new Date().setSeconds(0,0);
            }

            scope.dateValue = dateObj;
          }
        }

        function bodyDirectChild($el) {
          if (!$el || !$el.length) {
            return false;
          }

          var $parent = $el.parent();
          if (!$parent || !$parent.length) {
            return false;
          }

          return $parent[0].tagName.toLowerCase() === 'body';
        }

        function positionElements() {
          var offset = $(element).offset();

          if(isDate()) {
            $btnsEl
              .addClass('datepicker-control')
              .show()
              .css({
                left: offset.left + ($ctrlsEl.outerWidth() - $btnsEl.outerWidth()),
                top: offset.top + $ctrlsEl.outerHeight()
              });
          } else {
            $btnsEl
              .removeClass('datepicker-control')
              .show()
              .css({
                left: offset.left + ($(element).outerWidth() - $btnsEl.outerWidth()),
                top: offset.top - $btnsEl.outerHeight()
              });
          }

          $ctrlsEl
            .show()
            .css({
              left: offset.left,
              top: offset.top + $(element).outerHeight()
            });

          if (isDate()) {
            var $datepickerEl = $ctrlsEl[0].querySelector('.uib-daypicker');

            if ($datepickerEl) {
              $datepickerEl.focus();
            }
          }

        }

        function appendToBody() {
          $ctrlsEl = (($ctrlsEl && $ctrlsEl.length) ? $ctrlsEl : $(element[0].querySelector('.field-control')))
            .hide();
          if (!bodyDirectChild($ctrlsEl)) {
            $bdyEl
              .append($ctrlsEl);
          }

          $btnsEl = (($btnsEl && $btnsEl.length) ? $btnsEl : $(element[0].querySelector('.btn-group')))
            .hide();
          if (!bodyDirectChild($btnsEl)) {
            $bdyEl
              .append($btnsEl);
          }

          $timeout(positionElements, 50);
        }

        function removeFromBody(force) {
          $timeout(function() {
            if (scope.editing && !force) { return; }

            if ($btnsEl && $btnsEl.remove) {
              $btnsEl.remove();
            }
            $btnsEl = null;

            if ($ctrlsEl && $ctrlsEl.remove) {
              $ctrlsEl.remove();
            }
            $ctrlsEl = null;
          }, 50);
        }

        function bodyClicked(evt) {
          return element[0].contains(evt.target) ||
            ($btnsEl && $btnsEl.length && $btnsEl[0].contains(evt.target)) ||
            ($ctrlsEl && $ctrlsEl.length && $ctrlsEl[0].contains(evt.target));
        }

        scope.$watch('editing', function(after, before) {
          if (after === before) { return; }

          if (scope.editing) {
            appendToBody();
            element.addClass('inline-editing');
          }
          else {
            removeFromBody();
            element.removeClass('inline-editing');
          }
        });

        function stopEditing(evt) {
          if(!scope.editing) {
            return;
          }

          if(bodyClicked(evt)) {
            return;
          }

          var targetElement = $(evt.target),
              expectedClasses = 'ng-binding text-muted';

          if (targetElement.hasClass(expectedClasses)) {
            return;
          }

          var children = targetElement.children();
          if (children.hasClass(expectedClasses)) {
            return;
          }

          scope.$apply(scope.cancelChange);
        }

        scope.changeType = function() {
          if(scope.varType === 'datetime') {
            scope.varType = 'text';
          } else {
            scope.varType = 'datetime';
          }
          reset();
          scope.editing = true;
          element[0].attributes.type.value = scope.varType;
          scope.simpleField = isSimpleField();
        };

        scope.startEditing = function() {
          if(!scope.editing) {
            reset();

            scope.editing = true;
            scope.onStart(scope);

            // save the current edit value to restore later
            var savedEditValue = scope.editValue;

            // clear the edit value so that typeahead shows all options
            // should not apply to simpleFields
            if (!scope.simpleField) {
              scope.editValue = '';
            }

            // Here is where it gets ugly: We have to wait for angular to apply the changes to the edit value, so that the
            // input field is rendered and we can open the typeahead dropdown (first timeout). However, the instantTypeahead directive does
            // not immediately register its functions to prevent IE from going crazy. Therefore, we have to wait for another cycle
            // (second timeout), before triggering an input event on the input field can open the instant typeahead dropdown.
            $timeout(function() {
              $timeout(function() {
                // and reset the edit value, so that the user can type
                scope.editValue = savedEditValue;

                // in the next apply cycle, the dropdown is open. We now have to
                // select the default value, if it exists:
                if(savedEditValue) {
                  var isValueOfTypeObject = typeof savedEditValue === 'object';
                  if (isValueOfTypeObject) {
                    angular.element(element[0].querySelector('[ng-model="editValue"]')).val(savedEditValue.value);
                  }

                  $timeout(function() {
                    var elems = $(element[0].querySelector('li[ng-mouseenter]'));
                    var compareValue = isValueOfTypeObject ? savedEditValue.value : savedEditValue;

                    for(var i = 0; i < elems.length; i++) {
                      var elem = elems[i];
                      if(elem.innerText.indexOf(compareValue) === 0) {
                        $(elem).trigger('mouseenter');
                        return;
                      }
                    }
                  });
                }
              });
            });

            $timeout(function() {
              angular.element(element[0].querySelector('[ng-model="editValue"]')).triggerHandler('click');

              $timeout(function() {
                $('[ng-model="editValue"]').focus();
                $('[ng-model="editValue"]').select();
                $document.bind('click', stopEditing);
              }, 50);
            });
          }
        };

        scope.applyChange = function(selection, evt) {
          scope.invalid = scope.validator(scope);

          if (!scope.invalid) {

            if(scope.simpleField) {
              scope.editValue = parseValue(
                $('[ng-model="editValue"]').val()
              );

              scope.varValue = scope.editValue;
            }
            else if (scope.varType === 'option') {
              if(scope.options.indexOf(selection) === -1 && !scope.allowNonOptions) {
                scope.cancelChange();
                return;
              }
              scope.editValue = selection || $('[ng-model="editValue"]').val();
              scope.varValue = scope.editValue;
            }
            else if (isDate()) {
              scope.varValue = dateFilter(scope.dateValue, dateFormat);
            }

            scope.$event = evt;
            scope.change(scope);

            scope.editing = false;

            $document.unbind('click', stopEditing);
          }
        };

        function parseValue(value) {
          if (scope.varType === 'number') {
            if (value.length > 0) {
              return +value;
            }

            return null;
          }

          return value;
        }

        scope.cancelChange = function() {
          if(scope.editing) {
            scope.editing = false;
            scope.onCancel(scope);

            $document.unbind('click', stopEditing);
          }
        };

        scope.changeDate = function(pickerScope) {
          scope.editValue = scope.dateValue = pickerScope.dateValue;
        };

        scope.selectNextInlineField = function(reversed) {
          var allFields = $('[cam-widget-inline-field][type=\'text\'], [cam-widget-inline-field][type=\'option\']');
          for(var i = reversed*(allFields.length - 1); i !== !reversed*(allFields.length-1); i += !reversed*2-1) {

            if(allFields[i] === element[0]) {
              $timeout(function() {
                var element = $(allFields[i+!reversed*2-1]);
                element.find('.view-value').click();
                // after clicking the next inline field, wait for the input to appear, then select all
                $timeout(function() {
                  element.find('input').select();
                });
              });
              return;
            }
          }
          // take the first/last one
          $timeout(function() {
            $(allFields[reversed*allFields.length - 1]).find('.view-value').click();
          });
        };

        scope.trapKeyboard = function(evt, reverse) {
          if(isDate() && evt.keyCode === 9) {
            // only trap tab key on date inputs
            if(!reverse && !evt.shiftKey) {
              // focus the date picker
              $('.cam-widget-inline-field.field-control > .datepicker > table')[0].focus();
              evt.preventDefault();
            } else if(reverse && evt.shiftKey) {
              // focus the cancel button
              $('.cam-widget-inline-field.btn-group > button[ng-click="cancelChange($event)"]')[0].focus();
              evt.preventDefault();
            }
          }
        };

        scope.cancelOnEsc = function(evt) {
          if(isDate() && evt.keyCode === 27) {
            scope.cancelChange();
          }
        };

        scope.handleKeydown = function(evt) {
          if(evt.keyCode === 13) {
            scope.applyChange(scope.selection, evt);
            evt.preventDefault();
          } else if(evt.keyCode === 27) {
            scope.cancelChange(evt);
            evt.preventDefault();
          } else if(evt.keyCode === 9) {
            scope.applyChange(scope.selection, evt);
            scope.selectNextInlineField(evt.shiftKey);
            evt.preventDefault();
          }
          scope.selection = null;
        };

        scope.selection = null;
        scope.saveSelection = function(selection) {
          scope.selection = selection;
          $timeout(function() {
            // check if the selection has been applied
            if(scope.selection === selection) {
              scope.applyChange(selection);
            }
          });
        };

      },

      transclude: true
    };
  }];
<|endoftext|>


<commit_before>import React from 'react';
import SPELLS from 'common/SPELLS';
import SpellLink from 'common/SpellLink';
import SpellIcon from 'common/SpellIcon';
import { formatPercentage } from 'common/format';
import AbilityTracker from 'parser/shared/modules/AbilityTracker';
import Analyzer from 'parser/core/Analyzer';
import StatisticBox, { STATISTIC_ORDER } from 'interface/others/StatisticBox';

const CB_DURATION = 15000;
const debug = false;

class ComboBreaker extends Analyzer {
  static dependencies = {
    abilityTracker: AbilityTracker,
  };
  CBProcsTotal = 0;
  lastCBProcTime = null;
  consumedCBProc = 0;
  overwrittenCBProc = 0;

  on_byPlayer_applybuff(event) {
    const spellId = event.ability.guid;
    if (SPELLS.COMBO_BREAKER_BUFF.id === spellId) {
      this.lastCBProcTime = event.timestamp;
      debug && console.log('CB Proc Applied');
      this.CBProcsTotal += 1;
    }
  }

  on_byPlayer_refreshbuff(event) {
    const spellId = event.ability.guid;
    if (SPELLS.COMBO_BREAKER_BUFF.id === spellId) {
      this.lastCBProcTime = event.timestamp;
      debug && console.log('CB Proc Overwritten');
      this.CBProcsTotal += 1;
      this.overwrittenCBProc += 1;
    }
  }
  on_byPlayer_cast(event) {
    const spellId = event.ability.guid;
    if (SPELLS.BLACKOUT_KICK.id !== spellId) {
      return;
    }
    if (this.lastCBProcTime !== event.timestamp) {
     if (this.lastCBProcTime === null) {
        return;
      }
      const cbTimeframe = this.lastCBProcTime + CB_DURATION;
      if (event.timestamp <= cbTimeframe) {
       this.consumedCBProc += 1;
        debug && console.log(`CB Proc Consumed / Timestamp: ${event.timestamp}`);
       this.lastCBProcTime = null;
      }
    }
  }

  get usedCBProcs() {
    return this.consumedCBProc / this.CBProcsTotal;
  }

  get suggestionThresholds() {
    return {
      actual: this.usedCBProcs,
      isLessThan: {
        minor: 0.9,
        average: 0.8,
        major: 0.7,
      },
      style: 'percentage',
    };
  }

  suggestions(when) {
    when(this.suggestionThresholds).addSuggestion((suggest, actual, recommended) => {
        return suggest(Your <SpellLink id={SPELLS.COMBO_BREAKER_BUFF.id} /> procs should be used before you tiger palm again so they are not overwritten. While some will be overwritten due to higher priority of getting Chi for spenders, wasting <SpellLink id={SPELLS.COMBO_BREAKER_BUFF.id} /> procs is not optimal.)
          .icon(SPELLS.COMBO_BREAKER_BUFF.icon)
          .actual(`${formatPercentage(actual)}% used Combo Breaker procs`)
          .recommended(`>${formatPercentage(recommended)}% used Combo Breaker Procs is recommended`);
    });
  }

  statistic() {
    const averageCBProcs = this.abilityTracker.getAbility(SPELLS.TIGER_PALM.id).casts * (this.selectedCombatant.hasTrait(SPELLS.PRESSURE_POINT.id) ? 0.1 : 0.08);
    return (
      <StatisticBox
        position={STATISTIC_ORDER.CORE(6)}
        icon={<SpellIcon id={SPELLS.COMBO_BREAKER_BUFF.id} />}
        value={`${formatPercentage(this.usedCBProcs)}%`}
        label="Combo Breaker Procs Used"
        tooltip={<>You got a total of {this.CBProcsTotal} Combo Breaker procs and used {this.consumedCBProc} of them. Average number of procs from your Tiger Palms this fight is {averageCBProcs.toFixed(2)}, and you got {this.CBProcsTotal}.</>}
      />
   );
  }
}

export default ComboBreaker;
<commit_msg>Update Combo Breaker statistic<commit_after>import React from 'react';
import SPELLS from 'common/SPELLS';
import SpellLink from 'common/SpellLink';
import { formatPercentage } from 'common/format';
import Statistic from 'interface/statistics/Statistic';
import AbilityTracker from 'parser/shared/modules/AbilityTracker';
import Analyzer from 'parser/core/Analyzer';
import { STATISTIC_ORDER } from 'interface/others/StatisticBox';
import BoringSpellValueText from 'interface/statistics/components/BoringSpellValueText/index';

const CB_DURATION = 15000;
const debug = false;

class ComboBreaker extends Analyzer {
  static dependencies = {
    abilityTracker: AbilityTracker,
  };
  CBProcsTotal = 0;
  lastCBProcTime = null;
  consumedCBProc = 0;
  overwrittenCBProc = 0;

  on_byPlayer_applybuff(event) {
    const spellId = event.ability.guid;
    if (SPELLS.COMBO_BREAKER_BUFF.id === spellId) {
      this.lastCBProcTime = event.timestamp;
      debug && console.log('CB Proc Applied');
      this.CBProcsTotal += 1;
    }
  }

  on_byPlayer_refreshbuff(event) {
    const spellId = event.ability.guid;
    if (SPELLS.COMBO_BREAKER_BUFF.id === spellId) {
      this.lastCBProcTime = event.timestamp;
      debug && console.log('CB Proc Overwritten');
      this.CBProcsTotal += 1;
      this.overwrittenCBProc += 1;
    }
  }
  on_byPlayer_cast(event) {
    const spellId = event.ability.guid;
    if (SPELLS.BLACKOUT_KICK.id !== spellId) {
      return;
    }
    if (this.lastCBProcTime !== event.timestamp) {
     if (this.lastCBProcTime === null) {
        return;
      }
      const cbTimeframe = this.lastCBProcTime + CB_DURATION;
      if (event.timestamp <= cbTimeframe) {
       this.consumedCBProc += 1;
        debug && console.log(`CB Proc Consumed / Timestamp: ${event.timestamp}`);
       this.lastCBProcTime = null;
      }
    }
  }

  get usedCBProcs() {
    return this.consumedCBProc / this.CBProcsTotal;
  }

  get suggestionThresholds() {
    return {
      actual: this.usedCBProcs,
      isLessThan: {
        minor: 0.9,
        average: 0.8,
        major: 0.7,
      },
      style: 'percentage',
    };
  }

  suggestions(when) {
    when(this.suggestionThresholds).addSuggestion((suggest, actual, recommended) => {
        return suggest(Your <SpellLink id={SPELLS.COMBO_BREAKER_BUFF.id} /> procs should be used before you tiger palm again so they are not overwritten. While some will be overwritten due to higher priority of getting Chi for spenders, wasting <SpellLink id={SPELLS.COMBO_BREAKER_BUFF.id} /> procs is not optimal.)
          .icon(SPELLS.COMBO_BREAKER_BUFF.icon)
          .actual(`${formatPercentage(actual)}% used Combo Breaker procs`)
          .recommended(`>${formatPercentage(recommended)}% used Combo Breaker Procs is recommended`);
    });
  }

  statistic() {
    const averageCBProcs = this.abilityTracker.getAbility(SPELLS.TIGER_PALM.id).casts * (this.selectedCombatant.hasTrait(SPELLS.PRESSURE_POINT.id) ? 0.1 : 0.08);
    return (
      <Statistic
        position={STATISTIC_ORDER.CORE(6)}
        size="flexible"
        tooltip={<>You got a total of {this.CBProcsTotal} Combo Breaker procs and used {this.consumedCBProc} of them. The average expected number of procs from your Tiger Palms this fight is {averageCBProcs.toFixed(2)}, and you got {this.CBProcsTotal}.</>}
      >
      <BoringSpellValueText spell={SPELLS.COMBO_BREAKER_BUFF}>
          {formatPercentage(this.usedCBProcs, 0)}% Proc utilization
        </BoringSpellValueText>
      </Statistic>
   );
  }
}

export default ComboBreaker;
<|endoftext|>