<commit_before>/**
* Copyright 2012-2019, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var isNumeric = require('fast-isnumeric');

var Axes = require('../../plots/cartesian/axes');
var Lib = require('../../lib');

var BADNUM = require('../../constants/numerical').BADNUM;
var _ = Lib._;

module.exports = function calc(gd, trace) {
    var fullLayout = gd._fullLayout;
    var xa = Axes.getFromId(gd, trace.xaxis || 'x');
    var ya = Axes.getFromId(gd, trace.yaxis || 'y');
    var cd = [];

    // N.B. violin reuses same Box.calc
    var numKey = trace.type === 'violin' ? '_numViolins' : '_numBoxes';

    var i, j;
    var valAxis, valLetter;
    var posAxis, posLetter;

    if(trace.orientation === 'h') {
        valAxis = xa;
        valLetter = 'x';
        posAxis = ya;
        posLetter = 'y';
    } else {
        valAxis = ya;
        valLetter = 'y';
        posAxis = xa;
        posLetter = 'x';
    }

    var posArray = getPos(trace, posLetter, posAxis, fullLayout[numKey]);
    var dv = Lib.distinctVals(posArray);
    var posDistinct = dv.vals;
    var dPos = dv.minDiff / 2;

    // item in trace calcdata
    var cdi;
    // array of {v: v, i, i} sample pts
    var pts;
    // values of the `pts` array of objects
    var boxVals;
    // length of sample
    var N;
    // single sample point
    var pt;
    // single sample value
    var v;

    // filter function for outlier pts
    // outlier definition based on http://www.physics.csbsju.edu/stats/box2.html
    var ptFilterFn = (trace.boxpoints || trace.points) === 'all' ?
        Lib.identity :
        function(pt) { return (pt.v < cdi.lf || pt.v > cdi.uf); };

    if(trace._hasPreCompStats) {
        var valArrayRaw = trace[valLetter];
        var d2c = function(k) { return valAxis.d2c((trace[k] || [])[i]); };
        var minVal = Infinity;
        var maxVal = -Infinity;

        for(i = 0; i < trace._length; i++) {
            var posi = posArray[i];
            if(!isNumeric(posi)) continue;

            cdi = {};
            cdi.pos = cdi[posLetter] = posi;

            cdi.q1 = d2c('q1');
            cdi.med = d2c('median');
            cdi.q3 = d2c('q3');

            pts = [];
            if(valArrayRaw && Lib.isArrayOrTypedArray(valArrayRaw[i])) {
                for(j = 0; j < valArrayRaw[i].length; j++) {
                    v = valAxis.d2c(valArrayRaw[i][j]);
                    if(v !== BADNUM) {
                        pt = {v: v, i: [i, j]};
                        arraysToCalcdata(pt, trace, [i, j]);
                        pts.push(pt);
                    }
                }
            }
            cdi.pts = pts.sort(sortByVal);
            boxVals = cdi[valLetter] = pts.map(extractVal);
            N = boxVals.length;

            if(cdi.med !== BADNUM && cdi.q1 !== BADNUM && cdi.q3 !== BADNUM &&
                cdi.med >= cdi.q1 && cdi.q3 >= cdi.med
            ) {
                var lf = d2c('lowerfence');
                cdi.lf = (lf !== BADNUM && lf <= cdi.q1) ?
                    lf :
                    computeLowerFence(cdi, boxVals, N);

                var uf = d2c('upperfence');
                cdi.uf = (uf !== BADNUM && uf >= cdi.q3) ?
                    uf :
                    computeUpperFence(cdi, boxVals, N);

                var mean = d2c('mean');
                cdi.mean = (mean !== BADNUM) ?
                    mean :
                    (N ? Lib.mean(boxVals, N) : (cdi.q1 + cdi.q3) / 2);

                var sd = d2c('sd');
                cdi.sd = (mean !== BADNUM && sd >= 0) ?
                    sd :
                    (N ? Lib.stdev(boxVals, N, cdi.mean) : (cdi.q3 - cdi.q1));

                cdi.lo = computeLowerOutlierBound(cdi);
                cdi.uo = computeUpperOutlierBound(cdi);

                var ns = d2c('notchspan');
                ns = (ns !== BADNUM && ns > 0) ? ns : computeNotchSpan(cdi, N);
                cdi.ln = cdi.med - ns;
                cdi.un = cdi.med + ns;

                var imin = cdi.lf;
                var imax = cdi.uf;
                if(trace.boxpoints && boxVals.length) {
                    imin = Math.min(imin, boxVals[0]);
                    imax = Math.max(imax, boxVals[N - 1]);
                }
                if(trace.notched) {
                    imin = Math.min(imin, cdi.ln);
                    imax = Math.max(imax, cdi.un);
                }
                cdi.min = imin;
                cdi.max = imax;
            } else {
                Lib.warn('Invalid input - make sure that q1 <= median <= q3');

                var v0;
                if(cdi.med !== BADNUM) {
                    v0 = cdi.med;
                } else if(cdi.q1 !== BADNUM) {
                    if(cdi.q3 !== BADNUM) v0 = (cdi.q1 + cdi.q3) / 2;
                    else v0 = cdi.q1;
                } else if(cdi.q3 !== BADNUM) {
                    v0 = cdi.q3;
                } else {
                    v0 = 0;
                }

                // draw box as line segment
                cdi.med = v0;
                cdi.q1 = cdi.q3 = v0;
                cdi.lf = cdi.uf = v0;
                cdi.mean = cdi.sd = v0;
                cdi.ln = cdi.un = v0;
                cdi.min = cdi.max = v0;
            }

            minVal = Math.min(minVal, cdi.min);
            maxVal = Math.max(maxVal, cdi.max);

            cdi.pts2 = pts.filter(ptFilterFn);

            cd.push(cdi);
        }

        trace._extremes[valAxis._id] = Axes.findExtremes(valAxis,
            [minVal, maxVal],
            {padded: true}
        );
    } else {
        var valArray = valAxis.makeCalcdata(trace, valLetter);
        var quartilemethod = trace.quartilemethod;
        var posBins = makeBins(posDistinct, dPos);
        var pLen = posDistinct.length;
        var ptsPerBin = initNestedArray(pLen);

        // bin pts info per position bins
        for(i = 0; i < trace._length; i++) {
            v = valArray[i];
            if(!isNumeric(v)) continue;

            var n = Lib.findBin(posArray[i], posBins);
            if(n >= 0 && n < pLen) {
                pt = {v: v, i: i};
                arraysToCalcdata(pt, trace, i);
                ptsPerBin[n].push(pt);
            }
        }

        var minLowerNotch = Infinity;
        var maxUpperNotch = -Infinity;

        // build calcdata trace items, one item per distinct position
        for(i = 0; i < pLen; i++) {
            if(ptsPerBin[i].length > 0) {
                cdi = {};
                cdi.pos = cdi[posLetter] = posDistinct[i];

                pts = cdi.pts = ptsPerBin[i].sort(sortByVal);
                boxVals = cdi[valLetter] = pts.map(extractVal);
                N = boxVals.length;

                cdi.min = boxVals[0];
                cdi.max = boxVals[N - 1];
                cdi.mean = Lib.mean(boxVals, N);
                cdi.sd = Lib.stdev(boxVals, N, cdi.mean);
                cdi.med = Lib.interp(boxVals, 0.5);

                if((N % 2) && (quartilemethod === 'exclusive' || quartilemethod === 'inclusive')) {
                    var lower;
                    var upper;

                    if(quartilemethod === 'exclusive') {
                        // do NOT include the median in either half
                        lower = boxVals.slice(0, N / 2);
                        upper = boxVals.slice(N / 2 + 1);
                    } else if(quartilemethod === 'inclusive') {
                        // include the median in either half
                        lower = boxVals.slice(0, N / 2 + 1);
                        upper = boxVals.slice(N / 2);
                    }

                    cdi.q1 = Lib.interp(lower, 0.5);
                    cdi.q3 = Lib.interp(upper, 0.5);
                } else {
                    cdi.q1 = Lib.interp(boxVals, 0.25);
                    cdi.q3 = Lib.interp(boxVals, 0.75);
                }

                // lower and upper fences
                cdi.lf = computeLowerFence(cdi, boxVals, N);
                cdi.uf = computeUpperFence(cdi, boxVals, N);

                // lower and upper outliers bounds
                cdi.lo = computeLowerOutlierBound(cdi);
                cdi.uo = computeUpperOutlierBound(cdi);

                // lower and upper notches
                var mci = computeNotchSpan(cdi, N);
                cdi.ln = cdi.med - mci;
                cdi.un = cdi.med + mci;
                minLowerNotch = Math.min(minLowerNotch, cdi.ln);
                maxUpperNotch = Math.max(maxUpperNotch, cdi.un);

                cdi.pts2 = pts.filter(ptFilterFn);

                cd.push(cdi);
            }
        }

        trace._extremes[valAxis._id] = Axes.findExtremes(valAxis,
            trace.notched ? valArray.concat([minLowerNotch, maxUpperNotch]) : valArray,
            {padded: true}
        );
    }

    calcSelection(cd, trace);

    if(cd.length > 0) {
        cd[0].t = {
            num: fullLayout[numKey],
            dPos: dPos,
            posLetter: posLetter,
            valLetter: valLetter,
            labels: {
                med: _(gd, 'median:'),
                min: _(gd, 'min:'),
                q1: _(gd, 'q1:'),
                q3: _(gd, 'q3:'),
                max: _(gd, 'max:'),
                mean: trace.boxmean === 'sd' ? _(gd, 'mean ± σ:') : _(gd, 'mean:'),
                lf: _(gd, 'lower fence:'),
                uf: _(gd, 'upper fence:')
            }
        };

        fullLayout[numKey]++;
        return cd;
    } else {
        return [{t: {empty: true}}];
    }
};

// In vertical (horizontal) box plots:
// if no x (y) data, use x0 (y0), or name
// so if you want one box
// per trace, set x0 (y0) to the x (y) value or category for this trace
// (or set x (y) to a constant array matching y (x))
function getPos(trace, posLetter, posAxis, num) {
    var hasPosArray = posLetter in trace;
    var hasPos0 = posLetter + '0' in trace;
    var hasPosStep = 'd' + posLetter in trace;

    if(hasPosArray || (hasPos0 && hasPosStep)) {
        return posAxis.makeCalcdata(trace, posLetter);
    }

    var pos0;
    if(hasPos0) {
        pos0 = trace[posLetter + '0'];
    } else if('name' in trace && (
        posAxis.type === 'category' || (
            isNumeric(trace.name) &&
            ['linear', 'log'].indexOf(posAxis.type) !== -1
        ) || (
            Lib.isDateTime(trace.name) &&
            posAxis.type === 'date'
        )
    )) {
        pos0 = trace.name;
    } else {
        pos0 = num;
    }

    var pos0c = posAxis.type === 'multicategory' ?
        posAxis.r2c_just_indices(pos0) :
        posAxis.d2c(pos0, 0, trace[posLetter + 'calendar']);

    var len = trace._length;
    var out = new Array(len);
    for(var i = 0; i < len; i++) out[i] = pos0c;

    return out;
}

function makeBins(x, dx) {
    var len = x.length;
    var bins = new Array(len + 1);

    for(var i = 0; i < len; i++) {
        bins[i] = x[i] - dx;
    }
    bins[len] = x[len - 1] + dx;

    return bins;
}

function initNestedArray(len) {
    var arr = new Array(len);
    for(var i = 0; i < len; i++) {
        arr[i] = [];
    }
    return arr;
}

var TRACE_TO_CALC = {
    text: 'tx',
    hovertext: 'htx'
};

function arraysToCalcdata(pt, trace, ptNumber) {
    for(var k in TRACE_TO_CALC) {
        if(Lib.isArrayOrTypedArray(trace[k])) {
            if(Array.isArray(ptNumber)) {
                if(Lib.isArrayOrTypedArray(trace[k][ptNumber[0]])) {
                    pt[TRACE_TO_CALC[k]] = trace[k][ptNumber[0]][ptNumber[1]];
                }
            } else {
                pt[TRACE_TO_CALC[k]] = trace[k][ptNumber];
            }
        }
    }
}

function calcSelection(cd, trace) {
    if(Lib.isArrayOrTypedArray(trace.selectedpoints)) {
        for(var i = 0; i < cd.length; i++) {
            var pts = cd[i].pts || [];
            var ptNumber2cdIndex = {};

            for(var j = 0; j < pts.length; j++) {
                ptNumber2cdIndex[pts[j].i] = j;
            }

            Lib.tagSelected(pts, trace, ptNumber2cdIndex);
        }
    }
}

function sortByVal(a, b) { return a.v - b.v; }

function extractVal(o) { return o.v; }

// last point below 1.5 * IQR
function computeLowerFence(cdi, boxVals, N) {
    if(N === 0) return cdi.q1;
    return Math.min(
        cdi.q1,
        boxVals[Math.min(
            Lib.findBin(2.5 * cdi.q1 - 1.5 * cdi.q3, boxVals, true) + 1,
            N - 1
        )]
    );
}

// last point above 1.5 * IQR
function computeUpperFence(cdi, boxVals, N) {
    if(N === 0) return cdi.q3;
    return Math.max(
        cdi.q3,
        boxVals[Math.max(
            Lib.findBin(2.5 * cdi.q3 - 1.5 * cdi.q1, boxVals),
            0
        )]
    );
}

// 3 IQR below (don't clip to max/min,
// this is only for discriminating suspected & far outliers)
function computeLowerOutlierBound(cdi) {
    return 4 * cdi.q1 - 3 * cdi.q3;
}

// 3 IQR above (don't clip to max/min,
// this is only for discriminating suspected & far outliers)
function computeUpperOutlierBound(cdi) {
    return 4 * cdi.q3 - 3 * cdi.q1;
}

// 95% confidence intervals for median
function computeNotchSpan(cdi, N) {
    if(N === 0) return 0;
    return 1.57 * (cdi.q3 - cdi.q1) / Math.sqrt(N);
}
<commit_msg>mv quartilemethod str comparisons out of pet-box loop<commit_after>/**
* Copyright 2012-2019, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var isNumeric = require('fast-isnumeric');

var Axes = require('../../plots/cartesian/axes');
var Lib = require('../../lib');

var BADNUM = require('../../constants/numerical').BADNUM;
var _ = Lib._;

module.exports = function calc(gd, trace) {
    var fullLayout = gd._fullLayout;
    var xa = Axes.getFromId(gd, trace.xaxis || 'x');
    var ya = Axes.getFromId(gd, trace.yaxis || 'y');
    var cd = [];

    // N.B. violin reuses same Box.calc
    var numKey = trace.type === 'violin' ? '_numViolins' : '_numBoxes';

    var i, j;
    var valAxis, valLetter;
    var posAxis, posLetter;

    if(trace.orientation === 'h') {
        valAxis = xa;
        valLetter = 'x';
        posAxis = ya;
        posLetter = 'y';
    } else {
        valAxis = ya;
        valLetter = 'y';
        posAxis = xa;
        posLetter = 'x';
    }

    var posArray = getPos(trace, posLetter, posAxis, fullLayout[numKey]);
    var dv = Lib.distinctVals(posArray);
    var posDistinct = dv.vals;
    var dPos = dv.minDiff / 2;

    // item in trace calcdata
    var cdi;
    // array of {v: v, i, i} sample pts
    var pts;
    // values of the `pts` array of objects
    var boxVals;
    // length of sample
    var N;
    // single sample point
    var pt;
    // single sample value
    var v;

    // filter function for outlier pts
    // outlier definition based on http://www.physics.csbsju.edu/stats/box2.html
    var ptFilterFn = (trace.boxpoints || trace.points) === 'all' ?
        Lib.identity :
        function(pt) { return (pt.v < cdi.lf || pt.v > cdi.uf); };

    if(trace._hasPreCompStats) {
        var valArrayRaw = trace[valLetter];
        var d2c = function(k) { return valAxis.d2c((trace[k] || [])[i]); };
        var minVal = Infinity;
        var maxVal = -Infinity;

        for(i = 0; i < trace._length; i++) {
            var posi = posArray[i];
            if(!isNumeric(posi)) continue;

            cdi = {};
            cdi.pos = cdi[posLetter] = posi;

            cdi.q1 = d2c('q1');
            cdi.med = d2c('median');
            cdi.q3 = d2c('q3');

            pts = [];
            if(valArrayRaw && Lib.isArrayOrTypedArray(valArrayRaw[i])) {
                for(j = 0; j < valArrayRaw[i].length; j++) {
                    v = valAxis.d2c(valArrayRaw[i][j]);
                    if(v !== BADNUM) {
                        pt = {v: v, i: [i, j]};
                        arraysToCalcdata(pt, trace, [i, j]);
                        pts.push(pt);
                    }
                }
            }
            cdi.pts = pts.sort(sortByVal);
            boxVals = cdi[valLetter] = pts.map(extractVal);
            N = boxVals.length;

            if(cdi.med !== BADNUM && cdi.q1 !== BADNUM && cdi.q3 !== BADNUM &&
                cdi.med >= cdi.q1 && cdi.q3 >= cdi.med
            ) {
                var lf = d2c('lowerfence');
                cdi.lf = (lf !== BADNUM && lf <= cdi.q1) ?
                    lf :
                    computeLowerFence(cdi, boxVals, N);

                var uf = d2c('upperfence');
                cdi.uf = (uf !== BADNUM && uf >= cdi.q3) ?
                    uf :
                    computeUpperFence(cdi, boxVals, N);

                var mean = d2c('mean');
                cdi.mean = (mean !== BADNUM) ?
                    mean :
                    (N ? Lib.mean(boxVals, N) : (cdi.q1 + cdi.q3) / 2);

                var sd = d2c('sd');
                cdi.sd = (mean !== BADNUM && sd >= 0) ?
                    sd :
                    (N ? Lib.stdev(boxVals, N, cdi.mean) : (cdi.q3 - cdi.q1));

                cdi.lo = computeLowerOutlierBound(cdi);
                cdi.uo = computeUpperOutlierBound(cdi);

                var ns = d2c('notchspan');
                ns = (ns !== BADNUM && ns > 0) ? ns : computeNotchSpan(cdi, N);
                cdi.ln = cdi.med - ns;
                cdi.un = cdi.med + ns;

                var imin = cdi.lf;
                var imax = cdi.uf;
                if(trace.boxpoints && boxVals.length) {
                    imin = Math.min(imin, boxVals[0]);
                    imax = Math.max(imax, boxVals[N - 1]);
                }
                if(trace.notched) {
                    imin = Math.min(imin, cdi.ln);
                    imax = Math.max(imax, cdi.un);
                }
                cdi.min = imin;
                cdi.max = imax;
            } else {
                Lib.warn('Invalid input - make sure that q1 <= median <= q3');

                var v0;
                if(cdi.med !== BADNUM) {
                    v0 = cdi.med;
                } else if(cdi.q1 !== BADNUM) {
                    if(cdi.q3 !== BADNUM) v0 = (cdi.q1 + cdi.q3) / 2;
                    else v0 = cdi.q1;
                } else if(cdi.q3 !== BADNUM) {
                    v0 = cdi.q3;
                } else {
                    v0 = 0;
                }

                // draw box as line segment
                cdi.med = v0;
                cdi.q1 = cdi.q3 = v0;
                cdi.lf = cdi.uf = v0;
                cdi.mean = cdi.sd = v0;
                cdi.ln = cdi.un = v0;
                cdi.min = cdi.max = v0;
            }

            minVal = Math.min(minVal, cdi.min);
            maxVal = Math.max(maxVal, cdi.max);

            cdi.pts2 = pts.filter(ptFilterFn);

            cd.push(cdi);
        }

        trace._extremes[valAxis._id] = Axes.findExtremes(valAxis,
            [minVal, maxVal],
            {padded: true}
        );
    } else {
        var valArray = valAxis.makeCalcdata(trace, valLetter);
        var posBins = makeBins(posDistinct, dPos);
        var pLen = posDistinct.length;
        var ptsPerBin = initNestedArray(pLen);

        // bin pts info per position bins
        for(i = 0; i < trace._length; i++) {
            v = valArray[i];
            if(!isNumeric(v)) continue;

            var n = Lib.findBin(posArray[i], posBins);
            if(n >= 0 && n < pLen) {
                pt = {v: v, i: i};
                arraysToCalcdata(pt, trace, i);
                ptsPerBin[n].push(pt);
            }
        }

        var minLowerNotch = Infinity;
        var maxUpperNotch = -Infinity;

        var quartilemethod = trace.quartilemethod;
        var usesExclusive = quartilemethod === 'exclusive';
        var usesInclusive = quartilemethod === 'inclusive';

        // build calcdata trace items, one item per distinct position
        for(i = 0; i < pLen; i++) {
            if(ptsPerBin[i].length > 0) {
                cdi = {};
                cdi.pos = cdi[posLetter] = posDistinct[i];

                pts = cdi.pts = ptsPerBin[i].sort(sortByVal);
                boxVals = cdi[valLetter] = pts.map(extractVal);
                N = boxVals.length;

                cdi.min = boxVals[0];
                cdi.max = boxVals[N - 1];
                cdi.mean = Lib.mean(boxVals, N);
                cdi.sd = Lib.stdev(boxVals, N, cdi.mean);
                cdi.med = Lib.interp(boxVals, 0.5);

                if((N % 2) && (usesExclusive || usesInclusive)) {
                    var lower;
                    var upper;

                    if(usesExclusive) {
                        // do NOT include the median in either half
                        lower = boxVals.slice(0, N / 2);
                        upper = boxVals.slice(N / 2 + 1);
                    } else if(usesInclusive) {
                        // include the median in either half
                        lower = boxVals.slice(0, N / 2 + 1);
                        upper = boxVals.slice(N / 2);
                    }

                    cdi.q1 = Lib.interp(lower, 0.5);
                    cdi.q3 = Lib.interp(upper, 0.5);
                } else {
                    cdi.q1 = Lib.interp(boxVals, 0.25);
                    cdi.q3 = Lib.interp(boxVals, 0.75);
                }

                // lower and upper fences
                cdi.lf = computeLowerFence(cdi, boxVals, N);
                cdi.uf = computeUpperFence(cdi, boxVals, N);

                // lower and upper outliers bounds
                cdi.lo = computeLowerOutlierBound(cdi);
                cdi.uo = computeUpperOutlierBound(cdi);

                // lower and upper notches
                var mci = computeNotchSpan(cdi, N);
                cdi.ln = cdi.med - mci;
                cdi.un = cdi.med + mci;
                minLowerNotch = Math.min(minLowerNotch, cdi.ln);
                maxUpperNotch = Math.max(maxUpperNotch, cdi.un);

                cdi.pts2 = pts.filter(ptFilterFn);

                cd.push(cdi);
            }
        }

        trace._extremes[valAxis._id] = Axes.findExtremes(valAxis,
            trace.notched ? valArray.concat([minLowerNotch, maxUpperNotch]) : valArray,
            {padded: true}
        );
    }

    calcSelection(cd, trace);

    if(cd.length > 0) {
        cd[0].t = {
            num: fullLayout[numKey],
            dPos: dPos,
            posLetter: posLetter,
            valLetter: valLetter,
            labels: {
                med: _(gd, 'median:'),
                min: _(gd, 'min:'),
                q1: _(gd, 'q1:'),
                q3: _(gd, 'q3:'),
                max: _(gd, 'max:'),
                mean: trace.boxmean === 'sd' ? _(gd, 'mean ± σ:') : _(gd, 'mean:'),
                lf: _(gd, 'lower fence:'),
                uf: _(gd, 'upper fence:')
            }
        };

        fullLayout[numKey]++;
        return cd;
    } else {
        return [{t: {empty: true}}];
    }
};

// In vertical (horizontal) box plots:
// if no x (y) data, use x0 (y0), or name
// so if you want one box
// per trace, set x0 (y0) to the x (y) value or category for this trace
// (or set x (y) to a constant array matching y (x))
function getPos(trace, posLetter, posAxis, num) {
    var hasPosArray = posLetter in trace;
    var hasPos0 = posLetter + '0' in trace;
    var hasPosStep = 'd' + posLetter in trace;

    if(hasPosArray || (hasPos0 && hasPosStep)) {
        return posAxis.makeCalcdata(trace, posLetter);
    }

    var pos0;
    if(hasPos0) {
        pos0 = trace[posLetter + '0'];
    } else if('name' in trace && (
        posAxis.type === 'category' || (
            isNumeric(trace.name) &&
            ['linear', 'log'].indexOf(posAxis.type) !== -1
        ) || (
            Lib.isDateTime(trace.name) &&
            posAxis.type === 'date'
        )
    )) {
        pos0 = trace.name;
    } else {
        pos0 = num;
    }

    var pos0c = posAxis.type === 'multicategory' ?
        posAxis.r2c_just_indices(pos0) :
        posAxis.d2c(pos0, 0, trace[posLetter + 'calendar']);

    var len = trace._length;
    var out = new Array(len);
    for(var i = 0; i < len; i++) out[i] = pos0c;

    return out;
}

function makeBins(x, dx) {
    var len = x.length;
    var bins = new Array(len + 1);

    for(var i = 0; i < len; i++) {
        bins[i] = x[i] - dx;
    }
    bins[len] = x[len - 1] + dx;

    return bins;
}

function initNestedArray(len) {
    var arr = new Array(len);
    for(var i = 0; i < len; i++) {
        arr[i] = [];
    }
    return arr;
}

var TRACE_TO_CALC = {
    text: 'tx',
    hovertext: 'htx'
};

function arraysToCalcdata(pt, trace, ptNumber) {
    for(var k in TRACE_TO_CALC) {
        if(Lib.isArrayOrTypedArray(trace[k])) {
            if(Array.isArray(ptNumber)) {
                if(Lib.isArrayOrTypedArray(trace[k][ptNumber[0]])) {
                    pt[TRACE_TO_CALC[k]] = trace[k][ptNumber[0]][ptNumber[1]];
                }
            } else {
                pt[TRACE_TO_CALC[k]] = trace[k][ptNumber];
            }
        }
    }
}

function calcSelection(cd, trace) {
    if(Lib.isArrayOrTypedArray(trace.selectedpoints)) {
        for(var i = 0; i < cd.length; i++) {
            var pts = cd[i].pts || [];
            var ptNumber2cdIndex = {};

            for(var j = 0; j < pts.length; j++) {
                ptNumber2cdIndex[pts[j].i] = j;
            }

            Lib.tagSelected(pts, trace, ptNumber2cdIndex);
        }
    }
}

function sortByVal(a, b) { return a.v - b.v; }

function extractVal(o) { return o.v; }

// last point below 1.5 * IQR
function computeLowerFence(cdi, boxVals, N) {
    if(N === 0) return cdi.q1;
    return Math.min(
        cdi.q1,
        boxVals[Math.min(
            Lib.findBin(2.5 * cdi.q1 - 1.5 * cdi.q3, boxVals, true) + 1,
            N - 1
        )]
    );
}

// last point above 1.5 * IQR
function computeUpperFence(cdi, boxVals, N) {
    if(N === 0) return cdi.q3;
    return Math.max(
        cdi.q3,
        boxVals[Math.max(
            Lib.findBin(2.5 * cdi.q3 - 1.5 * cdi.q1, boxVals),
            0
        )]
    );
}

// 3 IQR below (don't clip to max/min,
// this is only for discriminating suspected & far outliers)
function computeLowerOutlierBound(cdi) {
    return 4 * cdi.q1 - 3 * cdi.q3;
}

// 3 IQR above (don't clip to max/min,
// this is only for discriminating suspected & far outliers)
function computeUpperOutlierBound(cdi) {
    return 4 * cdi.q3 - 3 * cdi.q1;
}

// 95% confidence intervals for median
function computeNotchSpan(cdi, N) {
    if(N === 0) return 0;
    return 1.57 * (cdi.q3 - cdi.q1) / Math.sqrt(N);
}
<|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict';

const Chalk = require('chalk');
const log = console.log;
const QuickSearch = require('../handlers/quick_search');
const InfoTask = require('../tasks/info');
const Log = require('../utils/log_utils');
const Utils = require('../utils/utils');

// Main code //
const self = module.exports = {
  init: (input) => {
    const pair = input[0];

    QuickSearch.searchWithMatches(pair)
      .then(result => {
        if (result.bestMatch.rating === 1) {
          Log.title(`Found it!`);
          InfoTask.print(result.bestMatch.target);
        } else if (result.ratings.length > 0) {
          let response = [];
          result.ratings.forEach(item => {
            if (item.rating > 0.3) {
              response.push(Chalk.grey(`${Math.round(item.rating * 100)}% `)+`${item.target} `);
            }
          });

          if (response.length > 0) {
            Log.title(`Did you mean`);
            response.forEach(item => {
              log(item);
            })
          } else {
            Utils.suggestCreation(pair);
          }
        } else {
          Utils.suggestCreation(pair);
        }
      });
  }
};
<commit_msg>fixed search item<commit_after>#!/usr/bin/env node
'use strict';

const Chalk = require('chalk');
const log = console.log;
const QuickSearch = require('../handlers/quick_search');
const InfoTask = require('../tasks/info');
const Log = require('../utils/log_utils');
const Utils = require('../utils/utils');

// Main code //
const self = module.exports = {
  init: (input) => {

    if (input.length == 0) {
      Log.titleError(`You need to specify the pair`);
      return;
    }

    const pair = input[0];

    QuickSearch.searchWithMatches(pair)
      .then(result => {
        if (result.bestMatch.rating === 1) {
          Log.title(`Found it!`);
          InfoTask.print(result.bestMatch.target);
        } else if (result.ratings.length > 0) {
          let response = [];
          result.ratings.forEach(item => {
            if (item.rating > 0.3) {
              response.push(Chalk.grey(`${Math.round(item.rating * 100)}% `)+`${item.target} `);
            }
          });

          if (response.length > 0) {
            Log.title(`Did you mean`);
            response.forEach(item => {
              log(item);
            })
          } else {
            Utils.suggestCreation(pair);
          }
        } else {
          Utils.suggestCreation(pair);
        }
      });
  }
};
<|endoftext|>


<commit_before>
module.exports = function(gulp, config) {

	return function(done) {
		if(!config.static) return done()
		var c = require('better-console')
		c.info('~ static')

		var plumber = require('gulp-plumber')
		var rename = require('gulp-rename')

		var task = gulp.src(config.static, { base: config.dir })

		// Init plumber in devmode
		if(config.devmode){
			task = task.pipe(plumber({ errorHandler: require('../helpers/error_handler') }))
		}

		task = task.pipe(rename(function(path) {
			// Extract src_folder from file paths
			if(path.dirname.indexOf(config.src_folder) === 0){
				path.dirname = path.dirname.substr(config.src_folder.length)
			}
		}))

		return task.pipe(gulp.dest(config.dist_folder))
	}
}
<commit_msg>Fixed src_folder exclusion for windows paths<commit_after>
module.exports = function(gulp, config) {

	return function(done) {
		if(!config.static) return done()
		var c = require('better-console')
		c.info('~ static')

		var plumber = require('gulp-plumber')
		var rename = require('gulp-rename')
		var path = require('path')

		var task = gulp.src(config.static, { base: config.dir })

		// Init plumber in devmode
		if(config.devmode){
			task = task.pipe(plumber({ errorHandler: require('../helpers/error_handler') }))
		}

		var path_src = path.normalize(config.src_folder)

		task = task.pipe(rename(function(path) {
			// Extract src_folder from file paths
			if(path.dirname.indexOf(path_src) === 0){
				path.dirname = path.dirname.substr(path_src.length)
			}
		}))

		return task.pipe(gulp.dest(config.dist_folder))
	}
}
<|endoftext|>


<commit_before>(function($, obviel) {
    obviel.view({
        iface: 'todos',
        obvt_script: 'obvt-todos',
        object_events: {
            update: 'rerender',
            update_stats: 'update_stats'
        },
        render: function() {
            $('#new-todo', this.el).focus();
            this.update_stats();
        },
        update_stats: function() {
            var stats = get_stats(this.obj);
            if (stats.amount) {
                $('#toggle-all', this.el).get(0).checked = !stats.remaining;
                $('footer', this.el).render(stats);
                $('footer', this.el).show();
            } else {
                $('footer', this.el).hide();
            }
        },
        create_on_enter: function(ev) {
            if (ev.keyCode !== 13) {
                return;
            }
            var value = $('#new-todo').val();
            if (value === '') {
                return;
            }
            this.obj.items.push({iface: 'todo', done: false, title: value});
            $(this.obj).trigger('update');
        },
        toggle_all: function() {
            var done = $('#toggle-all', this.el).get(0).checked;
            $.each(this.obj.items, function(index, item) {
                item.done = done;
            });
            $(this.obj).trigger('update');
        }
    });

    var get_stats = function(todos) {
        var remaining = 0;
        var done = 0;
        var amount = 0;
        $.each(todos.items, function(index, todo) {
            if (todo.done) {
                done += 1;
            } else {
                remaining += 1;
            }
            amount += 1;
        });
        return {iface: 'stats', remaining: remaining, done: done,
                amount: amount};
    };

    obviel.view({
        iface: 'stats',
        obvt_script: 'obvt-todo-stats',
        clear_completed: function() {
            var new_items = [];
            $.each(todos.items, function(index, item) {
                if (!item.done) {
                    new_items.push(item);
                }
            });
            todos.items = new_items;
            $(todos).trigger('update');
        }
    });

    obviel.view({
        iface: 'todo',
        obvt_script: 'obvt-todo',
        object_events: {
            update: 'rerender'
        },
        render: function() {
            if (this.obj.done) {
                this.el.addClass('done');
            } else {
                this.el.removeClass('done');
            }
        },
        edit: function() {
            this.obj.iface = 'todo-editing';
            $(this.obj).trigger('update');
        },
        toggle: function() {
            this.obj.done = !this.obj.done;
            $(this.obj).trigger('update');
            $(todos).trigger('update_stats');
        },
        clear: function() {
            clear(this.obj);
            $(todos).trigger('update');
        }
    });

    obviel.view({
        iface: 'todo-editing',
        obvt_script: 'obvt-todo-editing',
        object_events: {
            update: 'rerender'
        },
        render: function() {
            $('input.edit', this.el).focus();
        },
        update_on_enter: function(ev) {
            if (ev.keyCode === 13) {
                this.close();
            }
        },
        close: function() {
            var value = $('input.edit', this.el).val();
            if (!value) {
                clear(this.obj);
                $(todos).trigger('update');
                return;
            }
            this.obj.title = value;
            this.obj.iface = 'todo';
            $(this.obj).trigger('update');
        }
    });

    var todos = {
        iface: 'todos',
        items: []
    };

    var clear = function(todo) {
        for (var i = 0; i < todos.items.length; i++) {
            if (todos.items[i] === todo) {
                todos.items.splice(i, 1);
                break;
            }
        }
    };

    $(document).ready(function() {
        $('#todoapp').render(todos);
    });
}(jQuery, obviel));<commit_msg>Reorganize and comment code a bit.<commit_after>(function($, obviel) {
    // the application model
    var todos = {
        iface: 'todos',
        items: []
    };

    // a clear function removing a todo from the application
    var clear = function(todo) {
        for (var i = 0; i < todos.items.length; i++) {
            if (todos.items[i] === todo) {
                todos.items.splice(i, 1);
                break;
            }
        }
    };

    // create a special stats model from the todos
    var get_stats = function(todos) {
        var remaining = 0;
        var done = 0;
        var amount = 0;
        $.each(todos.items, function(index, todo) {
            if (todo.done) {
                done += 1;
            } else {
                remaining += 1;
            }
            amount += 1;
        });
        return {iface: 'stats', remaining: remaining, done: done,
                amount: amount};
    };

    // a view for the whole todos application
    obviel.view({
        iface: 'todos',
        obvt_script: 'obvt-todos',
        object_events: {
            update: 'rerender',
            update_stats: 'update_stats'
        },
        render: function() {
            $('#new-todo', this.el).focus();
            this.update_stats();
        },
        update_stats: function() {
            var stats = get_stats(this.obj);
            if (stats.amount) {
                $('#toggle-all', this.el).get(0).checked = !stats.remaining;
                $('footer', this.el).render(stats);
                $('footer', this.el).show();
            } else {
                $('footer', this.el).hide();
            }
        },
        create_on_enter: function(ev) {
            if (ev.keyCode !== 13) {
                return;
            }
            var value = $('#new-todo').val();
            if (value === '') {
                return;
            }
            this.obj.items.push({iface: 'todo', done: false, title: value});
            $(this.obj).trigger('update');
        },
        toggle_all: function() {
            var done = $('#toggle-all', this.el).get(0).checked;
            $.each(this.obj.items, function(index, item) {
                item.done = done;
            });
            $(this.obj).trigger('update');
        }
    });

    // a view for the stats
    obviel.view({
        iface: 'stats',
        obvt_script: 'obvt-todo-stats',
        clear_completed: function() {
            var new_items = [];
            $.each(todos.items, function(index, item) {
                if (!item.done) {
                    new_items.push(item);
                }
            });
            todos.items = new_items;
            $(todos).trigger('update');
        }
    });

    // a view for an individual todo item, not editable
    obviel.view({
        iface: 'todo',
        obvt_script: 'obvt-todo',
        object_events: {
            update: 'rerender'
        },
        render: function() {
            if (this.obj.done) {
                this.el.addClass('done');
            } else {
                this.el.removeClass('done');
            }
        },
        edit: function() {
            this.obj.iface = 'todo-editing';
            $(this.obj).trigger('update');
        },
        toggle: function() {
            this.obj.done = !this.obj.done;
            $(this.obj).trigger('update');
            $(todos).trigger('update_stats');
        },
        clear: function() {
            clear(this.obj);
            $(todos).trigger('update');
        }
    });

    // a view for an editable todo item
    obviel.view({
        iface: 'todo-editing',
        obvt_script: 'obvt-todo-editing',
        object_events: {
            update: 'rerender'
        },
        render: function() {
            $('input.edit', this.el).focus();
        },
        update_on_enter: function(ev) {
            if (ev.keyCode === 13) {
                this.close();
            }
        },
        close: function() {
            var value = $('input.edit', this.el).val();
            if (!value) {
                clear(this.obj);
                $(todos).trigger('update');
                return;
            }
            this.obj.title = value;
            this.obj.iface = 'todo';
            $(this.obj).trigger('update');
        }
    });

    // when the document is ready, render the app model
    $(document).ready(function() {
        $('#todoapp').render(todos);
    });
}(jQuery, obviel));<|endoftext|>


<commit_before>const WEBSITE_URL = process.env.WEBSITE_URL || "http://localhost:3000" || "https://staging.opencollective.com";

describe("collective page", () => {

  before(() => {
    cy.visit(`${WEBSITE_URL}/apex`)
  });

  it ("loads the collective page", () => {
    cy.get('#contribute .TierCard').should('have.length', 2);
    cy.get("#contributors .CollectiveCard").first().find('.totalDonations').contains("$1,700");
    cy.get("#budget .subtitle").contains("Current balance: $4.71");
    cy.get(".Members.cardsList .Member").should('have.length', 26);
  });

  it ("loads the latest expenses", () => {
    cy.get("#expenses .itemsList .expense").should("have.length", 5);
  });

  it ("opens all expenses page", () => {
    cy.get("#expenses .ViewAllExpensesBtn").click();
    cy.get(".ExpensesPage .ExpensesStats").contains("Available balance");
    cy.get(".ExpensesPage .ExpensesStats").contains("Engineering ($3,808)");
    cy.get(".ExpensesPage .ExpensesStats").contains("TJ Holowaychuk ($3,391)");
    cy.get(".ExpensesPage .itemsList .expense").should("have.length", 6);
    cy.get(".ExpensesPage .desktopOnly .menu .item.budget").click();
  });

  it("opens new expense page", () => {
    cy.get(".desktopOnly button.submitExpense").click();
    cy.wait(500);
    cy.get(".ExpensesPage .CreateExpenseForm").contains("Sign up or login to submit an expense");
    cy.get(".ExpensesPage .desktopOnly .menu .item.budget").click();
  });

  it ("loads the latest transactions", () => {
    cy.get("#transactions .itemsList .transaction").should("have.length", 5);
    cy.get("#transactions .itemsList .transaction:first .amount").contains("$2");
  });

  it ("opens all transactions page", () => {
    cy.get("#transactions .ViewAllTransactionsBtn").click();
    cy.wait(500);
    cy.get(".TransactionsPage .itemsList .transaction").should("have.length", 20);
    cy.get(".TransactionsPage .loadMoreBtn");
    cy.get(".TransactionsPage .filterBtnGroup button").last().click();
    cy.get(".TransactionsPage .itemsList .transaction").should("have.length", 6);
    cy.get(".TransactionsPage .desktopOnly .menu .item.about").click();
  });
})
<commit_msg>fix e2e<commit_after>const WEBSITE_URL = process.env.WEBSITE_URL || "http://localhost:3000" || "https://staging.opencollective.com";

describe("collective page", () => {

  before(() => {
    cy.visit(`${WEBSITE_URL}/apex`)
  });

  it ("loads the collective page", () => {
    cy.get('#contribute .TierCard').should('have.length', 2);
    cy.get("#contributors .CollectiveCard").first().find('.totalDonations').contains("$1,700");
    cy.get("#budget .subtitle").contains("Current balance: $4.71");
    cy.get("#contributors .Members.cardsList .Member").should('have.length', 26);
  });

  it ("loads the latest expenses", () => {
    cy.get("#expenses .itemsList .expense").should("have.length", 5);
  });

  it ("opens all expenses page", () => {
    cy.get("#expenses .ViewAllExpensesBtn").click();
    cy.get(".ExpensesPage .ExpensesStats").contains("Available balance");
    cy.get(".ExpensesPage .ExpensesStats").contains("Engineering ($3,808)");
    cy.get(".ExpensesPage .ExpensesStats").contains("TJ Holowaychuk ($3,391)");
    cy.get(".ExpensesPage .itemsList .expense").should("have.length", 6);
    cy.get(".ExpensesPage .desktopOnly .menu .item.budget").click();
  });

  it("opens new expense page", () => {
    cy.get(".desktopOnly button.submitExpense").click();
    cy.wait(500);
    cy.get(".ExpensesPage .CreateExpenseForm").contains("Sign up or login to submit an expense");
    cy.get(".ExpensesPage .desktopOnly .menu .item.budget").click();
  });

  it ("loads the latest transactions", () => {
    cy.get("#transactions .itemsList .transaction").should("have.length", 5);
    cy.get("#transactions .itemsList .transaction:first .amount").contains("$2");
  });

  it ("opens all transactions page", () => {
    cy.get("#transactions .ViewAllTransactionsBtn").click();
    cy.wait(500);
    cy.get(".TransactionsPage .itemsList .transaction").should("have.length", 20);
    cy.get(".TransactionsPage .loadMoreBtn");
    cy.get(".TransactionsPage .filterBtnGroup button").last().click();
    cy.get(".TransactionsPage .itemsList .transaction").should("have.length", 6);
    cy.get(".TransactionsPage .desktopOnly .menu .item.about").click();
  });
})
<|endoftext|>


<commit_before>import decompose, {identity} from "./decompose";

var cssNode,
    cssRoot,
    cssView,
    svgNode;

export function parseCss(value) {
  if (value === "none") return identity;
  if (!cssNode) cssNode = document.createElement("DIV"), cssRoot = document.documentElement, cssView = document.defaultView;
  cssNode.style.transform = value;
  cssRoot.appendChild(cssNode);
  value = cssView.getComputedStyle(cssNode, null).getPropertyValue("transform");
  cssRoot.removeChild(cssNode);
  var m = value.slice(7, -1).split(",");
  return decompose(+m[0], +m[1], +m[2], +m[3], +m[4], +m[5]);
}

export function parseSvg(value) {
  if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
  svgNode.setAttribute("transform", value == null ? "" : value);
  var m = svgNode.transform.baseVal.consolidate().matrix;
  return decompose(m.a, m.b, m.c, m.d, m.e, m.f);
}
<commit_msg>Shorten slightly.<commit_after>import decompose, {identity} from "./decompose";

var cssNode,
    cssRoot,
    cssView,
    svgNode;

export function parseCss(value) {
  if (value === "none") return identity;
  if (!cssNode) cssNode = document.createElement("DIV"), cssRoot = document.documentElement, cssView = document.defaultView;
  cssNode.style.transform = value;
  value = cssView.getComputedStyle(cssRoot.appendChild(cssNode), null).getPropertyValue("transform");
  cssRoot.removeChild(cssNode);
  var m = value.slice(7, -1).split(",");
  return decompose(+m[0], +m[1], +m[2], +m[3], +m[4], +m[5]);
}

export function parseSvg(value) {
  if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
  svgNode.setAttribute("transform", value == null ? "" : value);
  var m = svgNode.transform.baseVal.consolidate().matrix;
  return decompose(m.a, m.b, m.c, m.d, m.e, m.f);
}
<|endoftext|>


<commit_before>// Google BSD license http://code.google.com/google_bsd_license.html
// Copyright 2013 Google Inc. johnjbarton@google.com

(function(){

  QuerypointPanel.OnPanelOpen = {

    onClick: function(event) {
      var target = event.target;
      var className = target.classList.item(0);
      if (className) {
        var objMethod = className.split('_');
        var obj = objMethod[0];
        var method = objMethod[1];
        if (obj && method) {
          this[obj][method].call(this, event);
        }
      }
    },

    initialize: function(panel) {
      this.panel = panel;          // TODO: should be this._panel
      var onPanelOpen = document.querySelector('div.onPanelOpen');
      onPanelOpen.addEventListener('click', this.onClick.bind(this));
    },

    close: function() {
      var logView = document.querySelector('div.logView');
      logView.classList.remove('initialView');
    },

    open: function() {
      var logView = document.querySelector('div.logView');
      logView.classList.add('initialView');
    },

    // Functions wired to eg hint_overview
    hint: {
      overview: function() {
        this.panel.toggleHelp();
      },
      documentation: function() {
        window.open("http://google.github.com/qpp/documentation.html");
      },
      feedback: function() {
        window.open("https://github.com/google/qpp/issues/new");
      }
    },
    initialOptions: {
      justReload: function () {
        this.panel.project.reload();
        this.close();
      },
      reloadAndTrace: function() {
        var fileViewModel = this.panel.fileViewModels()[0];
        var tree = fileViewModel.treeRoot();
        var panel = this.panel;
        var project = panel.project;
        var queires = project.querypoints.possibleQueries().forEach(function(possibleQuery) {
          var query = possibleQuery.ifAvailableFor(tree, project);
          if (query) {
            var queryVM = new QuerypointPanel.QueryViewModel(query, panel);
            queryVM.activateQuery(fileViewModel);
          }
        });
        this.close();
      },
      noReload: function() {
        this.close();
      }
    }
  }

}());<commit_msg>Remove reload-and-trace option from initial panel for now at least<commit_after>// Google BSD license http://code.google.com/google_bsd_license.html
// Copyright 2013 Google Inc. johnjbarton@google.com

(function(){

  QuerypointPanel.OnPanelOpen = {

    onClick: function(event) {
      var target = event.target;
      var className = target.classList.item(0);
      if (className) {
        var objMethod = className.split('_');
        var obj = objMethod[0];
        var method = objMethod[1];
        if (obj && method) {
          this[obj][method].call(this, event);
        }
      }
    },

    initialize: function(panel) {
      this.panel = panel;          // TODO: should be this._panel
      var onPanelOpen = document.querySelector('div.onPanelOpen');
      onPanelOpen.addEventListener('click', this.onClick.bind(this));
    },

    close: function() {
      var logView = document.querySelector('div.logView');
      logView.classList.remove('initialView');
    },

    open: function() {
      var logView = document.querySelector('div.logView');
      logView.classList.add('initialView');
    },

    // Functions wired to eg hint_overview
    hint: {
      overview: function() {
        this.panel.toggleHelp();
      },
      documentation: function() {
        window.open("http://google.github.com/qpp/documentation.html");
      },
      feedback: function() {
        window.open("https://github.com/google/qpp/issues/new");
      }
    },
    initialOptions: {
      justReload: function () {
        this.panel.project.reload();
        this.close();
      },
      noReload: function() {
        this.close();
      }
    }
  }

}());<|endoftext|>


<commit_before><commit_msg>Add empty dynamic translator. Fixes #13<commit_after>/** @constructor */
function DynamicTranslator()
{
    // TODO
    dbg_assert(false);
}
<|endoftext|>


<commit_before>var Backbone = require('backbone')

var TestResults = Backbone.Model.extend({
  initialize: function(){
    this.reset()
  },
  reset: function(){
    this.set({
      topLevelError: null,
      failed: 0,
      passed: 0,
      pending: 0,
      total: 0,
      tests: new Backbone.Collection,
      all: false
    })
  },
  addResult: function(result){
    var total = this.get('total')
    var pending = this.get('pending')
    var passed = this.get('passed')
    var failed = this.get('failed')
    total++
    if (result.pending)
      pending++
    else if (result.failed == 0)
      passed++
    else
      failed++
    this.set({
      total: total,
      pending: pending,
      passed: passed,
      failed: failed,
      items: result.items
    })
    this.get('tests').push(result)
  }
})

module.exports = TestResults
<commit_msg>Push test result before calling `set`.<commit_after>var Backbone = require('backbone')

var TestResults = Backbone.Model.extend({
  initialize: function(){
    this.reset()
  },
  reset: function(){
    this.set({
      topLevelError: null,
      failed: 0,
      passed: 0,
      pending: 0,
      total: 0,
      tests: new Backbone.Collection,
      all: false
    })
  },
  addResult: function(result){
    var total = this.get('total')
    var pending = this.get('pending')
    var passed = this.get('passed')
    var failed = this.get('failed')
    total++
    if (result.pending)
      pending++
    else if (result.failed == 0)
      passed++
    else
      failed++
    this.get('tests').push(result)
    this.set({
      total: total,
      pending: pending,
      passed: passed,
      failed: failed,
      items: result.items
    })
  }
})

module.exports = TestResults
<|endoftext|>


<commit_before>/**
 * Returns token by range start. Ignores ()
 *
 * @param {JsFile} file
 * @param {Number} range
 * @param {Boolean} [backward=false] Direction
 * @returns {Object|null}
 */
exports.getTokenByRangeStart = function(file, range, backward) {
    var tokens = file.getTokens();

    // get next token
    var tokenPos = file.getTokenPosByRangeStart(range);
    var token = tokens[tokenPos];

    // if token is ")" -> get next token
    // for example (a) + (b)
    // next token ---^
    // we should find (a) + (b)
    // ------------------^
    if (this.isTokenParenthesis(file, range, backward)) {
        var pos = backward ? token.range[0] - 1 : token.range[1];
        tokenPos = file.getTokenPosByRangeStart(pos);
        token = tokens[tokenPos];
    }

    return token || null;
};

/**
 * Is next/previous token a parentheses?
 *
 * @param {JsFile} file
 * @param {Number} range
 * @param {Boolean} [backward=false] Direction
 * @returns {Boolean}
 */
exports.isTokenParenthesis = function(file, range, backward) {
    var tokens = file.getTokens();

    // get next token
    var tokenPos = file.getTokenPosByRangeStart(range);
    var token = tokens[tokenPos];

    // we should check for "(" if we go backward
    var parenthesis = backward ? '(' : ')';

    return token && token.type === 'Punctuator' && token.value === parenthesis;
};

/**
 * Returns true if token is punctuator
 *
 * @param {Object} token
 * @param {String} punctuator
 * @returns {Boolean}
 */
exports.tokenIsPunctuator = function(token, punctuator) {
    return token && token.type === 'Punctuator' && token.value === punctuator;
};

/**
 * Find next/previous operator by range start
 *
 * @param {JsFile} file
 * @param {Number} range
 * @param {String} operator
 * @param {Boolean} [backward=false] Direction
 * @returns {Object|null}
 */
exports.findOperatorByRangeStart = function(file, range, operator, backward) {
    var tokens = file.getTokens();
    var index = file.getTokenPosByRangeStart(range);

    while (tokens[index]) {
        if (tokens[index].value === operator) {
            return tokens[index];
        }

        if (backward) {
            index--;
        } else {
            index++;
        }
    }

    return null;
};

/**
 * Returns token or false if there is a punctuator in a given range
 *
 * @param {JsFile} file
 * @param {Number} range
 * @param {String} operator
 * @param {Boolean} [backward=false] Direction
 * @returns {Object|null}
 */
exports.getTokenByRangeStartIfPunctuator = function(file, range, operator, backward) {
    var part = this.getTokenByRangeStart(file, range, backward);

    if (this.tokenIsPunctuator(part, operator)) {
        return part;
    }

    return null;
};
<commit_msg>cleanup: remove lib/token-helper<commit_after><|endoftext|>


<commit_before>
/*

  Knockout Else --- Tests

 */

mocha.setup('bdd')
assert = chai.assert;

var view = {
  test_items: ko.observableArray()
};

var i = 60;
while(i--) {
  view.test_items.push(i);
}

var startTime = performance.now();
ko.applyBindings(view, document.getElementById("FFfixture"))
console.log("FF: " + (performance.now() - startTime) + "ms")

startTime = performance.now();
ko.applyBindings(view, document.getElementById("Ofixture"))
console.log("Original: " + (performance.now() - startTime) + "ms")

mocha.run();<commit_msg>bigger test size.<commit_after>
/*

  Knockout Else --- Tests

 */

mocha.setup('bdd')
assert = chai.assert;

var view = {
  test_items: ko.observableArray()
};

var i = 600;
while(i--) {
  view.test_items.push(i);
}

var startTime = performance.now();
ko.applyBindings(view, document.getElementById("FFfixture"))
console.log("FF: " + (performance.now() - startTime) + "ms")

startTime = performance.now();
ko.applyBindings(view, document.getElementById("Ofixture"))
console.log("Original: " + (performance.now() - startTime) + "ms")

mocha.run();<|endoftext|>


<commit_before>/*! sprintf.js | Copyright (c) 2007-2013 Alexandru Marasteanu <hello at alexei dot ro> | 3 clause BSD license */

(function(ctx) {
	var re = {
		not_string: /[^s]/,
		number: /[def]/,
		text: /^[^\x25]+/,
		modulo: /^\x25{2}/,
		placeholder: /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/,
		key: /^([a-z_][a-z_\d]*)/i,
		key_access: /^\.([a-z_][a-z_\d]*)/i,
		index_access: /^\[(\d+)\]/
	}

	var sprintf = function() {
		if (!sprintf.cache.hasOwnProperty(arguments[0])) {
			sprintf.cache[arguments[0]] = sprintf.parse(arguments[0])
		}
		return sprintf.format.call(null, sprintf.cache[arguments[0]], arguments)
	}

	sprintf.format = function(parse_tree, argv) {
		var cursor = 1, tree_length = parse_tree.length, node_type = "", arg, output = [], i, k, match, pad, pad_character, pad_length
		for (i = 0; i < tree_length; i++) {
			node_type = get_type(parse_tree[i])
			if (node_type === "string") {
				output.push(parse_tree[i])
			}
			else if (node_type === "array") {
				match = parse_tree[i] // convenience purposes only
				if (match[2]) { // keyword argument
					arg = argv[cursor]
					for (k = 0; k < match[2].length; k++) {
						if (!arg.hasOwnProperty(match[2][k])) {
							throw new Error(sprintf("[sprintf] property '%s' does not exist", match[2][k]))
						}
						arg = arg[match[2][k]]
					}
				}
				else if (match[1]) { // positional argument (explicit)
					arg = argv[match[1]]
				}
				else { // positional argument (implicit)
					arg = argv[cursor++]
				}

				if (re.not_string.test(match[8]) && (get_type(arg) != "number")) {
					throw new TypeError(sprintf("[sprintf] expecting number but found %s", get_type(arg)))
				}
				switch (match[8]) {
					case "b":
						arg = arg.toString(2)
					break
					case "c":
						arg = String.fromCharCode(arg)
					break
					case "d":
						arg = parseInt(arg, 10)
					break
					case "e":
						arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential()
					break
					case "f":
						arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg)
					break
					case "o":
						arg = arg.toString(8)
					break
					case "s":
						arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg)
					break
					case "u":
						arg = arg >>> 0
					break
					case "x":
						arg = arg.toString(16)
					break
					case "X":
						arg = arg.toString(16).toUpperCase()
					break
				}
				arg = (re.number.test(match[8]) && match[3] && arg >= 0 ? "+"+ arg : arg)
				pad_character = match[4] ? match[4] == "0" ? "0" : match[4].charAt(1) : " "
				pad_length = match[6] - String(arg).length
				pad = match[6] ? str_repeat(pad_character, pad_length) : ""
				output.push(match[5] ? arg + pad : pad + arg)
			}
		}
		return output.join("")
	}

	sprintf.cache = {}

	sprintf.parse = function(fmt) {
		var _fmt = fmt, match = [], parse_tree = [], arg_names = 0
		while (_fmt) {
			if ((match = re.text.exec(_fmt)) !== null) {
				parse_tree.push(match[0])
			}
			else if ((match = re.modulo.exec(_fmt)) !== null) {
				parse_tree.push("%")
			}
			else if ((match = re.placeholder.exec(_fmt)) !== null) {
				if (match[2]) {
					arg_names |= 1
					var field_list = [], replacement_field = match[2], field_match = []
					if ((field_match = re.key.exec(replacement_field)) !== null) {
						field_list.push(field_match[1])
						while ((replacement_field = replacement_field.substring(field_match[0].length)) !== "") {
							if ((field_match = re.key_access.exec(replacement_field)) !== null) {
								field_list.push(field_match[1])
							}
							else if ((field_match = re.index_access.exec(replacement_field)) !== null) {
								field_list.push(field_match[1])
							}
							else {
								throw new SyntaxError("[sprintf] failed to parse named argument key")
							}
						}
					}
					else {
						throw new SyntaxError("[sprintf] failed to parse named argument key")
					}
					match[2] = field_list
				}
				else {
					arg_names |= 2
				}
				if (arg_names === 3) {
					throw new Error("[sprintf] mixing positional and named placeholders is not (yet) supported")
				}
				parse_tree.push(match)
			}
			else {
				throw new SyntaxError("[sprintf] unexpected placeholder")
			}
			_fmt = _fmt.substring(match[0].length)
		}
		return parse_tree
	}

	var vsprintf = function(fmt, argv, _argv) {
		_argv = (argv || []).slice(0)
		_argv.splice(0, 0, fmt)
		return sprintf.apply(null, _argv)
	}

	/**
	 * helpers
	 */
	function get_type(variable) {
		return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase()
	}

	function str_repeat(input, multiplier) {
		return Array(multiplier + 1).join(input)
	}

	/**
	 * export to either browser or node.js
	 */
	ctx.sprintf = sprintf
	ctx.vsprintf = vsprintf
})(typeof exports != "undefined" ? exports : window)
<commit_msg>improve cache lookup<commit_after>/*! sprintf.js | Copyright (c) 2007-2013 Alexandru Marasteanu <hello at alexei dot ro> | 3 clause BSD license */

(function(ctx) {
	var re = {
		not_string: /[^s]/,
		number: /[def]/,
		text: /^[^\x25]+/,
		modulo: /^\x25{2}/,
		placeholder: /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/,
		key: /^([a-z_][a-z_\d]*)/i,
		key_access: /^\.([a-z_][a-z_\d]*)/i,
		index_access: /^\[(\d+)\]/
	}

	function sprintf() {
		var key = arguments[0], cache = sprintf.cache
		if (!(cache[key] && cache.hasOwnProperty(key))) {
			cache[key] = sprintf.parse(key)
		}
		return sprintf.format.call(null, cache[key], arguments)
	}

	sprintf.format = function(parse_tree, argv) {
		var cursor = 1, tree_length = parse_tree.length, node_type = "", arg, output = [], i, k, match, pad, pad_character, pad_length
		for (i = 0; i < tree_length; i++) {
			node_type = get_type(parse_tree[i])
			if (node_type === "string") {
				output.push(parse_tree[i])
			}
			else if (node_type === "array") {
				match = parse_tree[i] // convenience purposes only
				if (match[2]) { // keyword argument
					arg = argv[cursor]
					for (k = 0; k < match[2].length; k++) {
						if (!arg.hasOwnProperty(match[2][k])) {
							throw new Error(sprintf("[sprintf] property '%s' does not exist", match[2][k]))
						}
						arg = arg[match[2][k]]
					}
				}
				else if (match[1]) { // positional argument (explicit)
					arg = argv[match[1]]
				}
				else { // positional argument (implicit)
					arg = argv[cursor++]
				}

				if (re.not_string.test(match[8]) && (get_type(arg) != "number")) {
					throw new TypeError(sprintf("[sprintf] expecting number but found %s", get_type(arg)))
				}
				switch (match[8]) {
					case "b":
						arg = arg.toString(2)
					break
					case "c":
						arg = String.fromCharCode(arg)
					break
					case "d":
						arg = parseInt(arg, 10)
					break
					case "e":
						arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential()
					break
					case "f":
						arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg)
					break
					case "o":
						arg = arg.toString(8)
					break
					case "s":
						arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg)
					break
					case "u":
						arg = arg >>> 0
					break
					case "x":
						arg = arg.toString(16)
					break
					case "X":
						arg = arg.toString(16).toUpperCase()
					break
				}
				arg = (re.number.test(match[8]) && match[3] && arg >= 0 ? "+"+ arg : arg)
				pad_character = match[4] ? match[4] == "0" ? "0" : match[4].charAt(1) : " "
				pad_length = match[6] - String(arg).length
				pad = match[6] ? str_repeat(pad_character, pad_length) : ""
				output.push(match[5] ? arg + pad : pad + arg)
			}
		}
		return output.join("")
	}

	sprintf.cache = {}

	sprintf.parse = function(fmt) {
		var _fmt = fmt, match = [], parse_tree = [], arg_names = 0
		while (_fmt) {
			if ((match = re.text.exec(_fmt)) !== null) {
				parse_tree.push(match[0])
			}
			else if ((match = re.modulo.exec(_fmt)) !== null) {
				parse_tree.push("%")
			}
			else if ((match = re.placeholder.exec(_fmt)) !== null) {
				if (match[2]) {
					arg_names |= 1
					var field_list = [], replacement_field = match[2], field_match = []
					if ((field_match = re.key.exec(replacement_field)) !== null) {
						field_list.push(field_match[1])
						while ((replacement_field = replacement_field.substring(field_match[0].length)) !== "") {
							if ((field_match = re.key_access.exec(replacement_field)) !== null) {
								field_list.push(field_match[1])
							}
							else if ((field_match = re.index_access.exec(replacement_field)) !== null) {
								field_list.push(field_match[1])
							}
							else {
								throw new SyntaxError("[sprintf] failed to parse named argument key")
							}
						}
					}
					else {
						throw new SyntaxError("[sprintf] failed to parse named argument key")
					}
					match[2] = field_list
				}
				else {
					arg_names |= 2
				}
				if (arg_names === 3) {
					throw new Error("[sprintf] mixing positional and named placeholders is not (yet) supported")
				}
				parse_tree.push(match)
			}
			else {
				throw new SyntaxError("[sprintf] unexpected placeholder")
			}
			_fmt = _fmt.substring(match[0].length)
		}
		return parse_tree
	}

	var vsprintf = function(fmt, argv, _argv) {
		_argv = (argv || []).slice(0)
		_argv.splice(0, 0, fmt)
		return sprintf.apply(null, _argv)
	}

	/**
	 * helpers
	 */
	function get_type(variable) {
		return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase()
	}

	function str_repeat(input, multiplier) {
		return Array(multiplier + 1).join(input)
	}

	/**
	 * export to either browser or node.js
	 */
	ctx.sprintf = sprintf
	ctx.vsprintf = vsprintf
})(typeof exports != "undefined" ? exports : window)
<|endoftext|>


<commit_before>(function($) {

    /**
     * setup JQuery's AJAX methods to setup CSRF token in the request before sending it off.
     * http://stackoverflow.com/questions/5100539/django-csrf-check-failing-with-an-ajax-post-request
     */

    // Document READY
    $(function() {

        console.log($("#cs_host_attributes-group"));
        /*$("#cs_host_attributes-group").hide();*/

        if ($("#id_cs_host_attributes-0-vm_id").val() == null){
            $("#cs_host_attributes-group").hide();
        }else{
            $("#cs_host_attributes-group").show();
        }

    });

})(django.jQuery);<commit_msg>Improves javascript'<commit_after>(function($) {

    /**
     * setup JQuery's AJAX methods to setup CSRF token in the request before sending it off.
     * http://stackoverflow.com/questions/5100539/django-csrf-check-failing-with-an-ajax-post-request
     */

    // Document READY
    $(function() {

        if ($("#id_cs_host_attributes-0-vm_id").val() == null){
            $("#cs_host_attributes-group").hide();
        }else{
            $("#cs_host_attributes-group").show();
        }

    });

})(django.jQuery);<|endoftext|>


<commit_before>import * as cosets      from '../fpgroups/cosets';
import * as delaney     from './delaney';
import * as properties  from './properties';
import * as derived     from './derived';
import * as delaney2d   from './delaney2d';
import * as delaney3d   from './delaney3d';
import * as fundamental from './fundamental';
import * as covers      from './covers';
import * as periodic    from '../pgraphs/periodic';

import * as seq from '../common/lazyseq';
import * as util from '../common/util';

import {
  rationalLinearAlgebraModular,
  numericalLinearAlgebra
} from '../arithmetic/types';

const opsR = rationalLinearAlgebraModular;
const opsF = numericalLinearAlgebra;

const _remainingIndices = (ds, i) => ds.indices().filter(j => j != i);

const _edgeTranslations = cov => {
  const fg  = fundamental.fundamentalGroup(cov);
  const n   = fg.nrGenerators;
  const nul = opsR.nullSpace(cosets.relatorMatrix(n, fg.relators).toJS());
  const vec = rel => cosets.relatorAsVector(rel, n).toJS();

  return fg.edge2word.map(a => a.map(b => opsR.times(vec(b), nul)));
};

const _cornerShifts = (cov, e2t) => {
  const dim = delaney.dim(cov);
  const zero = opsR.vector(dim);

  const result = new Array(cov.size + 1).fill(0).map(_ => []);

  for (const i of cov.indices()) {
    const idcs = _remainingIndices(cov, i);
    for (const [Dk, k, D] of properties.traversal(cov, idcs, cov.elements())) {
      if (k == properties.traversal.root)
        result[D][i] = zero;
      else
        result[D][i] = opsR.minus(result[Dk][i], e2t[Dk][k] || zero);
    }
  }

  return result;
};

export const skeleton = cov => {
  const e2t = _edgeTranslations(cov);
  const c2s = _cornerShifts(cov, e2t);

  const chamber2node = {};
  let node = 1;
  for (const orb of properties.orbits(cov, _remainingIndices(cov, 0))) {
    for (const D of orb)
      chamber2node[D] = node;
    node += 1;
  }

  const zero = opsR.vector(delaney.dim(cov));
  const edges = properties.orbitReps(cov, _remainingIndices(cov, 1))
    .map(D => {
      const E = cov.s(0, D);
      const v = chamber2node[D];
      const w = chamber2node[E];
      const t = e2t[D][0] || zero;
      const sD = c2s[D][0];
      const sE = c2s[E][0];
      const s = opsR.minus(opsR.plus(t, sE), sD);

      return [v, w, s];
    })
    .toArray();

  return {
    graph: periodic.make(edges),
    chamber2node: chamber2node,
    edgeTranslations: e2t,
    cornerShifts: c2s
  };
};

const _sum = v => v.reduce((x, y) => x == null ? y : opsF.plus(x, y));

const chamberPositions = (cov, skel, pos, basis) => {
  const result = {};

  for (const D of cov.elements()) {
    const p = pos[skel.chamber2node[D]];
    const t = skel.cornerShifts[D][0];
    result[D] = [opsF.plus(p, t)];
  }

  for (let i = 1; i <= delaney.dim(cov); ++i) {
    const idcs = seq.range(0, i).toArray();

    for (const orb of properties.orbits(cov, idcs, cov.elements())) {
      const s = opsF.div(
        _sum(orb.map(E => opsF.minus(result[E][0], skel.cornerShifts[E][i]))),
        orb.length);

      for (const E of orb) {
        const t = skel.cornerShifts[E][i];
        result[E].push(opsF.plus(s, t));
      }
    }
  }

  for (const D of cov.elements())
    result[D] = result[D].map(p => opsF.times(p, basis));

  return result;
};

const chamberBasis = (pos, D) => {
  const t = pos[D];
  return t.slice(1).map(v => opsF.minus(v, t[0]));
};

const determinant = M => {
  if (M.length == 2)
    return M[0][0] * M[1][1] - M[0][1] * M[1][0];
  else if (M.length == 3)
    return (+ M[0][0] * M[1][1] * M[2][2]
            + M[0][1] * M[1][2] * M[2][0]
            + M[0][2] * M[1][0] * M[2][1]
            - M[0][2] * M[1][1] * M[2][0]
            - M[0][1] * M[1][0] * M[2][2]
            - M[0][0] * M[1][2] * M[2][1]);
  else
    return opsF.determinant(M);
};

export const symmetries = (ds, cov, pos) => {
  const D0 = cov.elements()
    .find(D => opsF.ne(determinant(chamberBasis(pos, D)), 0));
  const A = opsF.inverse(chamberBasis(pos, D0));

  const phi = properties.morphism(cov, 1, ds, 1);
  const E0 = phi[D0];

  return cov.elements()
    .filter(D => phi[D] == E0)
    .map(D => opsF.times(A, chamberBasis(pos, D)));
};

export const makeCover = ds =>
  delaney.dim(ds) == 3 ?
  delaney3d.pseudoToroidalCover(ds) :
  delaney2d.toroidalCover(ds);

const interpolate = (f, v, w) => opsF.plus(w, opsF.times(f, opsF.minus(v, w)));

const tileSurface3D = (corners, faces) => {
  const pos = corners.map(p => interpolate(0.8, p[0], p[3]));

  return { pos, faces };
};

const tileSurface2D = (corners, faces) => {
  const pos = [];
  for (const [p] of corners) {
    pos.push(p.concat(0));
    pos.push(p.concat(0.1));
  }

  const f = faces[0].map(i => 2 * i);

  faces = [f, f.map(x => x + 1).reverse()]
    .concat(f.map((x, i) => {
      const y = f[(i + 1) % f.length];
      return [y, x, x + 1, y + 1];
    }));

  return { pos, faces };
};

const adjustedOrientation = (cov, pos) => {
  const bas = D => chamberBasis(pos, D);
  const D0 = cov.elements().find(D => opsF.ne(determinant(bas(D)), 0));
  const sgn = opsF.sgn(determinant(bas(D0)));

  const ori = properties.partialOrientation(cov);
  if (sgn * ori[D0] < 0) {
    for (const D of cov.elements())
      ori[D] = -ori[D];
  }

  return ori;
};

const tileSurface = (cov, pos, ori, elms, idcs) => {
  const cOrbs = properties.orbits(cov, idcs.slice(1), elms);
  const cPos = cOrbs.map(orb => pos[orb[0]]);

  const cIdcs = [];
  cOrbs.forEach((orb, i) => {
    for (const D of orb)
      cIdcs[D] = i;
  });

  const faces = properties.orbits(cov, [0, 1], elms)
    .map(orb => ori[orb[0]] > 0 ? orb.reverse() : orb)
    .map(orb => orb.filter((D, i) => i % 2 == 0).map(D => cIdcs[D]));

  if (delaney.dim(cov) == 3)
    return tileSurface3D(cPos, faces);
  else
    return tileSurface2D(cPos, faces);
};

const affineSymmetry = (D0, D1, pos) => {
  const bas = D => chamberBasis(pos, D);
  const linear = opsF.times(opsF.inverse(bas(D0)), bas(D1));
  const shift = opsF.minus(pos[D1][0], opsF.times(pos[D0][0], linear));

  return linear.map(r => r.concat(0)).concat([shift.concat([1])]);
};

export const tileSurfaces = (ds, cov, skel, vertexPos, basis) => {
  const dim = delaney.dim(cov);
  const pos = chamberPositions(cov, skel, vertexPos, basis);
  const dso = derived.orientedCover(ds);
  const phi = properties.morphism(cov, 1, dso, 1);
  const bas = D => chamberBasis(pos, D);
  const ori = adjustedOrientation(cov, pos);
  const idcs = seq.range(0, dim).toArray();
  const tileOrbits = properties.orbits(cov, idcs);

  const templates = [];
  const tileOrbitReps = [];
  const dsChamberToTemplateIndex = {};
  const tiles = [];

  for (const elms of tileOrbits) {
    const D0 = elms.find(D => opsF.ne(determinant(bas(D)), 0));
    const E0 = phi[D0];

    let templateIndex = dsChamberToTemplateIndex[E0];
    let symmetry = opsF.identityMatrix(dim + 1);

    if (templateIndex == null) {
      templateIndex = templates.length;

      for (const E of properties.orbit(dso, idcs, E0))
        dsChamberToTemplateIndex[E] = templateIndex;

      templates.push(tileSurface(cov, pos, ori, elms, idcs));
      tileOrbitReps.push(D0);
    }
    else {
      const D0 = tileOrbitReps[templateIndex];
      const D1 = elms.find(D => phi[D] == phi[D0]);
      symmetry = affineSymmetry(D0, D1, pos);
    }

    const center = pos[elms[0]][dim];
    tiles.push({ templateIndex, symmetry, center });
  }

  return { templates, tiles };
};

if (require.main == module) {
  Array.prototype.toString = function() {
    return '[ ' + this.map(x => x && x.toString()).join(', ') + ' ]';
  };

  const delaney = require('./delaney');
  const embed = require('../pgraphs/embedding').default;

  const invariantBasis = gram => {
    const dot = (v, w) => opsF.times(opsF.times(v, gram), w);

    const vs = opsF.identityMatrix(gram.length);
    const ortho = [];

    for (let v of vs) {
      for (const w of ortho)
        v = opsF.minus(v, opsF.times(w, dot(v, w)));
      ortho.push(opsF.div(v, opsF.sqrt(dot(v, v))))
    }

    return opsF.times(gram, opsF.transposed(ortho));
  };

  const test = ds => {
    console.log(`ds = ${ds}`);

    const cov = makeCover(ds);
    console.log(`cover = ${cov}`);

    const skel = skeleton(cov);
    console.log(`skeleton = ${skel.graph}`);

    const embedding = embed(skel.graph, false);
    const pos = embedding.positions;
    console.log(`vertex positions: ${JSON.stringify(pos)}`);

    const basis = invariantBasis(embedding.gram);
    console.log(`invariant basis: ${basis}`);

    const surf = tileSurfaces(ds, cov, skel, pos, basis);
    console.log(`tile surfaces: ${JSON.stringify(surf)}`);

    console.log();
  }

  test(delaney.parse('<1.1:1 3:1,1,1,1:4,3,4>'));
  test(delaney.parse('<1.1:2 3:2,1 2,1 2,2:6,3 2,6>'));
  test(delaney.parse('<1.1:2 3:1 2,1 2,1 2,2:3 3,3 4,4>'));
  test(delaney.parse('<1.1:8:2 4 6 8,8 3 5 7,6 5 8 7:4,4>'));
  test(delaney.parse('<1.1:8:2 4 6 8,8 3 5 7,5 6 8 7:4,4>'));
}
<commit_msg>some refactorings in tilings.js<commit_after>import * as cosets      from '../fpgroups/cosets';
import * as delaney     from './delaney';
import * as properties  from './properties';
import * as derived     from './derived';
import * as delaney2d   from './delaney2d';
import * as delaney3d   from './delaney3d';
import * as fundamental from './fundamental';
import * as covers      from './covers';
import * as periodic    from '../pgraphs/periodic';

import * as seq from '../common/lazyseq';
import * as util from '../common/util';

import {
  rationalLinearAlgebraModular,
  numericalLinearAlgebra
} from '../arithmetic/types';

const opsR = rationalLinearAlgebraModular;
const opsF = numericalLinearAlgebra;

const _remainingIndices = (ds, i) => ds.indices().filter(j => j != i);

const _edgeTranslations = cov => {
  const fg  = fundamental.fundamentalGroup(cov);
  const n   = fg.nrGenerators;
  const nul = opsR.nullSpace(cosets.relatorMatrix(n, fg.relators).toJS());
  const vec = rel => cosets.relatorAsVector(rel, n).toJS();

  return fg.edge2word.map(a => a.map(b => opsR.times(vec(b), nul)));
};

const _cornerShifts = (cov, e2t) => {
  const dim = delaney.dim(cov);
  const zero = opsR.vector(dim);

  const result = new Array(cov.size + 1).fill(0).map(_ => []);

  for (const i of cov.indices()) {
    const idcs = _remainingIndices(cov, i);
    for (const [Dk, k, D] of properties.traversal(cov, idcs, cov.elements())) {
      if (k == properties.traversal.root)
        result[D][i] = zero;
      else
        result[D][i] = opsR.minus(result[Dk][i], e2t[Dk][k] || zero);
    }
  }

  return result;
};

export const skeleton = cov => {
  const e2t = _edgeTranslations(cov);
  const c2s = _cornerShifts(cov, e2t);

  const chamber2node = {};
  let node = 1;
  for (const orb of properties.orbits(cov, _remainingIndices(cov, 0))) {
    for (const D of orb)
      chamber2node[D] = node;
    node += 1;
  }

  const zero = opsR.vector(delaney.dim(cov));
  const edges = properties.orbitReps(cov, _remainingIndices(cov, 1))
    .map(D => {
      const E = cov.s(0, D);
      const v = chamber2node[D];
      const w = chamber2node[E];
      const t = e2t[D][0] || zero;
      const sD = c2s[D][0];
      const sE = c2s[E][0];
      const s = opsR.minus(opsR.plus(t, sE), sD);

      return [v, w, s];
    })
    .toArray();

  return {
    graph: periodic.make(edges),
    chamber2node: chamber2node,
    edgeTranslations: e2t,
    cornerShifts: c2s
  };
};

const _sum = v => v.reduce((x, y) => x == null ? y : opsF.plus(x, y));

const chamberPositions = (cov, skel, pos, basis) => {
  const result = {};

  for (const D of cov.elements()) {
    const p = pos[skel.chamber2node[D]];
    const t = skel.cornerShifts[D][0];
    result[D] = [opsF.plus(p, t)];
  }

  for (let i = 1; i <= delaney.dim(cov); ++i) {
    const idcs = seq.range(0, i).toArray();

    for (const orb of properties.orbits(cov, idcs, cov.elements())) {
      const s = opsF.div(
        _sum(orb.map(E => opsF.minus(result[E][0], skel.cornerShifts[E][i]))),
        orb.length);

      for (const E of orb)
        result[E].push(opsF.plus(s, skel.cornerShifts[E][i]));
    }
  }

  for (const D of cov.elements())
    result[D] = result[D].map(p => opsF.times(p, basis));

  return result;
};

const chamberBasis = (pos, D) => {
  const t = pos[D];
  return t.slice(1).map(v => opsF.minus(v, t[0]));
};

const determinant = M => {
  if (M.length == 2)
    return M[0][0] * M[1][1] - M[0][1] * M[1][0];
  else if (M.length == 3)
    return (+ M[0][0] * M[1][1] * M[2][2]
            + M[0][1] * M[1][2] * M[2][0]
            + M[0][2] * M[1][0] * M[2][1]
            - M[0][2] * M[1][1] * M[2][0]
            - M[0][1] * M[1][0] * M[2][2]
            - M[0][0] * M[1][2] * M[2][1]);
  else
    return opsF.determinant(M);
};

const chamberDeterminant = (pos, D) => determinant(chamberBasis(pos, D));

const nonDegenerateChamber = (elms, pos) =>
  elms.find(D => opsF.ne(chamberDeterminant(pos, D), 0));

export const symmetries = (ds, cov, pos) => {
  const D0 = nonDegenerateChamber(cov.elements(), pos);
  const A = opsF.inverse(chamberBasis(pos, D0));

  const phi = properties.morphism(cov, 1, ds, 1);
  const E0 = phi[D0];

  return cov.elements()
    .filter(D => phi[D] == E0)
    .map(D => opsF.times(A, chamberBasis(pos, D)));
};

export const makeCover = ds =>
  delaney.dim(ds) == 3 ?
  delaney3d.pseudoToroidalCover(ds) :
  delaney2d.toroidalCover(ds);

const interpolate = (f, v, w) => opsF.plus(w, opsF.times(f, opsF.minus(v, w)));

const tileSurface3D = (corners, faces) => {
  const pos = corners.map(p => interpolate(0.8, p[0], p[3]));

  return { pos, faces };
};

const tileSurface2D = (corners, faces) => {
  const pos = [];
  for (const [p] of corners) {
    pos.push(p.concat(0));
    pos.push(p.concat(0.1));
  }

  const f = faces[0].map(i => 2 * i);

  faces = [f, f.map(x => x + 1).reverse()]
    .concat(f.map((x, i) => {
      const y = f[(i + 1) % f.length];
      return [y, x, x + 1, y + 1];
    }));

  return { pos, faces };
};

const adjustedOrientation = (cov, pos) => {
  const D0 = nonDegenerateChamber(cov.elements(), pos);
  const sgn = opsF.sgn(chamberDeterminant(pos, D0));

  const ori = properties.partialOrientation(cov);
  if (sgn * ori[D0] < 0) {
    for (const D of cov.elements())
      ori[D] = -ori[D];
  }

  return ori;
};

const tileSurface = (cov, pos, ori, elms, idcs) => {
  const cOrbs = properties.orbits(cov, idcs.slice(1), elms);
  const cPos = cOrbs.map(orb => pos[orb[0]]);

  const cIdcs = [];
  cOrbs.forEach((orb, i) => {
    for (const D of orb)
      cIdcs[D] = i;
  });

  const faces = properties.orbits(cov, [0, 1], elms)
    .map(orb => ori[orb[0]] > 0 ? orb.reverse() : orb)
    .map(orb => orb.filter((D, i) => i % 2 == 0).map(D => cIdcs[D]));

  if (delaney.dim(cov) == 3)
    return tileSurface3D(cPos, faces);
  else
    return tileSurface2D(cPos, faces);
};

const affineSymmetry = (D0, D1, pos) => {
  const bas = D => chamberBasis(pos, D);
  const linear = opsF.solve(bas(D0), bas(D1));
  const shift = opsF.minus(pos[D1][0], opsF.times(pos[D0][0], linear));

  return linear.map(r => r.concat(0)).concat([shift.concat([1])]);
};

export const tileSurfaces = (ds, cov, skel, vertexPos, basis) => {
  const dim = delaney.dim(cov);
  const pos = chamberPositions(cov, skel, vertexPos, basis);
  const dso = derived.orientedCover(ds);
  const phi = properties.morphism(cov, 1, dso, 1);
  const ori = adjustedOrientation(cov, pos);
  const idcs = seq.range(0, dim).toArray();
  const tileOrbits = properties.orbits(cov, idcs);

  const templates = [];
  const tileOrbitReps = [];
  const dsChamberToTemplateIndex = {};
  const tiles = [];

  for (const elms of tileOrbits) {
    const D0 = nonDegenerateChamber(elms, pos);
    const E0 = phi[D0];

    let templateIndex = dsChamberToTemplateIndex[E0];
    let symmetry = opsF.identityMatrix(dim + 1);

    if (templateIndex == null) {
      templateIndex = templates.length;

      for (const E of properties.orbit(dso, idcs, E0))
        dsChamberToTemplateIndex[E] = templateIndex;

      templates.push(tileSurface(cov, pos, ori, elms, idcs));
      tileOrbitReps.push(D0);
    }
    else {
      const D0 = tileOrbitReps[templateIndex];
      const D1 = elms.find(D => phi[D] == phi[D0]);
      symmetry = affineSymmetry(D0, D1, pos);
    }

    const center = pos[elms[0]][dim];
    tiles.push({ templateIndex, symmetry, center });
  }

  return { templates, tiles };
};

if (require.main == module) {
  Array.prototype.toString = function() {
    return '[ ' + this.map(x => x && x.toString()).join(', ') + ' ]';
  };

  const delaney = require('./delaney');
  const embed = require('../pgraphs/embedding').default;

  const invariantBasis = gram => {
    const dot = (v, w) => opsF.times(opsF.times(v, gram), w);

    const vs = opsF.identityMatrix(gram.length);
    const ortho = [];

    for (let v of vs) {
      for (const w of ortho)
        v = opsF.minus(v, opsF.times(w, dot(v, w)));
      ortho.push(opsF.div(v, opsF.sqrt(dot(v, v))))
    }

    return opsF.times(gram, opsF.transposed(ortho));
  };

  const test = ds => {
    console.log(`ds = ${ds}`);

    const cov = makeCover(ds);
    console.log(`cover = ${cov}`);

    const skel = skeleton(cov);
    console.log(`skeleton = ${skel.graph}`);

    const embedding = embed(skel.graph, false);
    const pos = embedding.positions;
    console.log(`vertex positions: ${JSON.stringify(pos)}`);

    const basis = invariantBasis(embedding.gram);
    console.log(`invariant basis: ${basis}`);

    const surf = tileSurfaces(ds, cov, skel, pos, basis);
    console.log(`tile surfaces: ${JSON.stringify(surf)}`);

    console.log();
  }

  test(delaney.parse('<1.1:1 3:1,1,1,1:4,3,4>'));
  test(delaney.parse('<1.1:2 3:2,1 2,1 2,2:6,3 2,6>'));
  test(delaney.parse('<1.1:2 3:1 2,1 2,1 2,2:3 3,3 4,4>'));
  test(delaney.parse('<1.1:8:2 4 6 8,8 3 5 7,6 5 8 7:4,4>'));
  test(delaney.parse('<1.1:8:2 4 6 8,8 3 5 7,5 6 8 7:4,4>'));
}
<|endoftext|>


<commit_before>'use strict';
const MongoError = require('./error').MongoError;

let TxnState;
let stateMachine;

(() => {
  const NO_TRANSACTION = 'NO_TRANSACTION';
  const STARTING_TRANSACTION = 'STARTING_TRANSACTION';
  const TRANSACTION_IN_PROGRESS = 'TRANSACTION_IN_PROGRESS';
  const TRANSACTION_COMMITTED = 'TRANSACTION_COMMITTED';
  const TRANSACTION_COMMITTED_EMPTY = 'TRANSACTION_COMMITTED_EMPTY';
  const TRANSACTION_ABORTED = 'TRANSACTION_ABORTED';

  TxnState = {
    NO_TRANSACTION,
    STARTING_TRANSACTION,
    TRANSACTION_IN_PROGRESS,
    TRANSACTION_COMMITTED,
    TRANSACTION_COMMITTED_EMPTY,
    TRANSACTION_ABORTED
  };

  stateMachine = {
    [NO_TRANSACTION]: [NO_TRANSACTION, STARTING_TRANSACTION],
    [STARTING_TRANSACTION]: [
      TRANSACTION_IN_PROGRESS,
      TRANSACTION_COMMITTED,
      TRANSACTION_COMMITTED_EMPTY,
      TRANSACTION_ABORTED
    ],
    [TRANSACTION_IN_PROGRESS]: [
      TRANSACTION_IN_PROGRESS,
      TRANSACTION_COMMITTED,
      TRANSACTION_ABORTED
    ],
    [TRANSACTION_COMMITTED]: [
      TRANSACTION_COMMITTED,
      TRANSACTION_COMMITTED_EMPTY,
      STARTING_TRANSACTION,
      NO_TRANSACTION
    ],
    [TRANSACTION_ABORTED]: [STARTING_TRANSACTION, NO_TRANSACTION],
    [TRANSACTION_COMMITTED_EMPTY]: [TRANSACTION_COMMITTED_EMPTY, NO_TRANSACTION]
  };
})();

/**
 * The MongoDB ReadConcern, which allows for control of the consistency and isolation properties
 * of the data read from replica sets and replica set shards.
 * @typedef {Object} ReadConcern
 * @property {'local'|'available'|'majority'|'linearizable'|'snapshot'} level The readConcern Level
 * @see https://docs.mongodb.com/manual/reference/read-concern/
 */

/**
 * A MongoDB WriteConcern, which describes the level of acknowledgement
 * requested from MongoDB for write operations.
 * @typedef {Object} WriteConcern
 * @property {number|'majority'|string} [w=1] requests acknowledgement that the write operation has
 * propagated to a specified number of mongod hosts
 * @property {boolean} [j=false] requests acknowledgement from MongoDB that the write operation has
 * been written to the journal
 * @property {number} [wtimeout] a time limit, in milliseconds, for the write concern
 * @see https://docs.mongodb.com/manual/reference/write-concern/
 */

/**
 * Configuration options for a transaction.
 * @typedef {Object} TransactionOptions
 * @property {ReadConcern} [readConcern] A default read concern for commands in this transaction
 * @property {WriteConcern} [writeConcern] A default writeConcern for commands in this transaction
 * @property {ReadPreference} [readPreference] A default read preference for commands in this transaction
 */

/**
 * A class maintaining state related to a server transaction. Internal Only
 * @ignore
 */
class Transaction {
  /**
   * Create a transaction
   *
   * @ignore
   * @param {TransactionOptions} [options] Optional settings
   */
  constructor(options) {
    options = options || {};

    this.state = TxnState.NO_TRANSACTION;
    this.options = {};

    if (options.writeConcern || typeof options.w !== 'undefined') {
      const w = options.writeConcern ? options.writeConcern.w : options.w;
      if (w <= 0) {
        throw new MongoError('Transactions do not support unacknowledged write concern');
      }

      this.options.writeConcern = options.writeConcern ? options.writeConcern : { w: options.w };
    }

    if (options.readConcern) this.options.readConcern = options.readConcern;
    if (options.readPreference) this.options.readPreference = options.readPreference;

    // TODO: This isn't technically necessary
    this._pinnedServer = undefined;
    this._recoveryToken = undefined;
  }

  get isPinned() {
    return this._pinnedServer != null;
  }

  get server() {
    return this._pinnedServer;
  }

  get recoveryToken() {
    return this._recoveryToken;
  }

  /**
   * @ignore
   * @return Whether this session is presently in a transaction
   */
  get isActive() {
    return (
      [TxnState.STARTING_TRANSACTION, TxnState.TRANSACTION_IN_PROGRESS].indexOf(this.state) !== -1
    );
  }

  /**
   * Transition the transaction in the state machine
   * @ignore
   * @param {TxnState} state The new state to transition to
   */
  transition(nextState) {
    const nextStates = stateMachine[this.state];
    if (nextStates && nextStates.indexOf(nextState) !== -1) {
      this.state = nextState;
      if (this.state === TxnState.NO_TRANSACTION || this.state === TxnState.STARTING_TRANSACTION) {
        this.unpinServer();
      }
      return;
    }

    throw new MongoError(
      `Attempted illegal state transition from [${this.state}] to [${nextState}]`
    );
  }

  get isPinned() {
    return this._pinnedServer != null;
  }

  pinServer(server) {
    if (this.isActive) {
      this._pinnedServer = server;
    }
  }

  unpinServer() {
    this._pinnedServer = undefined;
  }
}

module.exports = { TxnState, Transaction };
<commit_msg>chore(transactions): remove unused code<commit_after>'use strict';
const MongoError = require('./error').MongoError;

let TxnState;
let stateMachine;

(() => {
  const NO_TRANSACTION = 'NO_TRANSACTION';
  const STARTING_TRANSACTION = 'STARTING_TRANSACTION';
  const TRANSACTION_IN_PROGRESS = 'TRANSACTION_IN_PROGRESS';
  const TRANSACTION_COMMITTED = 'TRANSACTION_COMMITTED';
  const TRANSACTION_COMMITTED_EMPTY = 'TRANSACTION_COMMITTED_EMPTY';
  const TRANSACTION_ABORTED = 'TRANSACTION_ABORTED';

  TxnState = {
    NO_TRANSACTION,
    STARTING_TRANSACTION,
    TRANSACTION_IN_PROGRESS,
    TRANSACTION_COMMITTED,
    TRANSACTION_COMMITTED_EMPTY,
    TRANSACTION_ABORTED
  };

  stateMachine = {
    [NO_TRANSACTION]: [NO_TRANSACTION, STARTING_TRANSACTION],
    [STARTING_TRANSACTION]: [
      TRANSACTION_IN_PROGRESS,
      TRANSACTION_COMMITTED,
      TRANSACTION_COMMITTED_EMPTY,
      TRANSACTION_ABORTED
    ],
    [TRANSACTION_IN_PROGRESS]: [
      TRANSACTION_IN_PROGRESS,
      TRANSACTION_COMMITTED,
      TRANSACTION_ABORTED
    ],
    [TRANSACTION_COMMITTED]: [
      TRANSACTION_COMMITTED,
      TRANSACTION_COMMITTED_EMPTY,
      STARTING_TRANSACTION,
      NO_TRANSACTION
    ],
    [TRANSACTION_ABORTED]: [STARTING_TRANSACTION, NO_TRANSACTION],
    [TRANSACTION_COMMITTED_EMPTY]: [TRANSACTION_COMMITTED_EMPTY, NO_TRANSACTION]
  };
})();

/**
 * The MongoDB ReadConcern, which allows for control of the consistency and isolation properties
 * of the data read from replica sets and replica set shards.
 * @typedef {Object} ReadConcern
 * @property {'local'|'available'|'majority'|'linearizable'|'snapshot'} level The readConcern Level
 * @see https://docs.mongodb.com/manual/reference/read-concern/
 */

/**
 * A MongoDB WriteConcern, which describes the level of acknowledgement
 * requested from MongoDB for write operations.
 * @typedef {Object} WriteConcern
 * @property {number|'majority'|string} [w=1] requests acknowledgement that the write operation has
 * propagated to a specified number of mongod hosts
 * @property {boolean} [j=false] requests acknowledgement from MongoDB that the write operation has
 * been written to the journal
 * @property {number} [wtimeout] a time limit, in milliseconds, for the write concern
 * @see https://docs.mongodb.com/manual/reference/write-concern/
 */

/**
 * Configuration options for a transaction.
 * @typedef {Object} TransactionOptions
 * @property {ReadConcern} [readConcern] A default read concern for commands in this transaction
 * @property {WriteConcern} [writeConcern] A default writeConcern for commands in this transaction
 * @property {ReadPreference} [readPreference] A default read preference for commands in this transaction
 */

/**
 * A class maintaining state related to a server transaction. Internal Only
 * @ignore
 */
class Transaction {
  /**
   * Create a transaction
   *
   * @ignore
   * @param {TransactionOptions} [options] Optional settings
   */
  constructor(options) {
    options = options || {};

    this.state = TxnState.NO_TRANSACTION;
    this.options = {};

    if (options.writeConcern || typeof options.w !== 'undefined') {
      const w = options.writeConcern ? options.writeConcern.w : options.w;
      if (w <= 0) {
        throw new MongoError('Transactions do not support unacknowledged write concern');
      }

      this.options.writeConcern = options.writeConcern ? options.writeConcern : { w: options.w };
    }

    if (options.readConcern) this.options.readConcern = options.readConcern;
    if (options.readPreference) this.options.readPreference = options.readPreference;

    // TODO: This isn't technically necessary
    this._pinnedServer = undefined;
    this._recoveryToken = undefined;
  }

  get server() {
    return this._pinnedServer;
  }

  get recoveryToken() {
    return this._recoveryToken;
  }

  /**
   * @ignore
   * @return Whether this session is presently in a transaction
   */
  get isActive() {
    return (
      [TxnState.STARTING_TRANSACTION, TxnState.TRANSACTION_IN_PROGRESS].indexOf(this.state) !== -1
    );
  }

  /**
   * Transition the transaction in the state machine
   * @ignore
   * @param {TxnState} state The new state to transition to
   */
  transition(nextState) {
    const nextStates = stateMachine[this.state];
    if (nextStates && nextStates.indexOf(nextState) !== -1) {
      this.state = nextState;
      if (this.state === TxnState.NO_TRANSACTION || this.state === TxnState.STARTING_TRANSACTION) {
        this.unpinServer();
      }
      return;
    }

    throw new MongoError(
      `Attempted illegal state transition from [${this.state}] to [${nextState}]`
    );
  }

  pinServer(server) {
    if (this.isActive) {
      this._pinnedServer = server;
    }
  }

  unpinServer() {
    this._pinnedServer = undefined;
  }
}

module.exports = { TxnState, Transaction };
<|endoftext|>