<commit_before>'use strict';

var assert = require('assert');
var Ably = require('../src/ably');

var ably;

assert.testsEqual = function deepDeepEqual(actual, expected) {
    assert.equal(actual.name, expected.name);
    assert.equal(actual.variants, expected.variants);
    if (typeof expected.sampler === 'string') {
        expected.sampler = ably.samplers[expected.sampler];
    }
    assert.equal(actual.sampler, expected.sampler);
};

assert.deepTestsEqual = function deepDeepEqual(actual, expected) {
    assert.equal(actual.length, expected.length);
    for (var i = 0; i < actual.length; i++) {
        assert.testsEqual(actual, expected);
    }
};

describe('Ably', function() {
    beforeEach(function() {
        ably = new Ably();
    });

    it('is an object', function() {
        assert.equal(typeof ably, 'object');
    });

    it('accepts namespace', function() {
        var namespace = 'just a test namespace in order to test namespaces';
        ably = new Ably(namespace);

        assert.equal(ably.namespace, namespace);
    });

    it('has an addTest method', function() {
        assert.equal(typeof ably.addTest, 'function');
    });

    it('has an addTests method', function() {
        assert.equal(typeof ably.addTests, 'function');
    });

    it('has a getTest method', function() {
        assert.equal(typeof ably.getTest, 'function');
    });

    it('has a getTests method', function() {
        assert.equal(typeof ably.getTests, 'function');
    });

    it('has a when method', function() {
        assert.equal(typeof ably.when, 'function');
    });

    var tests = [
        {
            name: 'button-color',
            variants: ['red', 'green'],
            sampler: function sampler(callback) {
                callback('red');
            },
            scope: 'pageview'
        },
        {
            name: 'button-text',
            variants: ['buy', 'subscribe'],
            sampler: function sampler(callback) {
                callback('buy');
            },
            scope: 'pageview'
        },
        {
            name: 'button-size',
            variants: ['large', 'small'],
            sampler: function sampler(callback) {
                callback('large');
            },
            scope: 'pageview'
        }
    ];

    describe('.getTest(name)', function() {
        it('retrieves test named \'name\'', function() {
            ably.addTest(tests[0]);
            ably.addTest(tests[1]);
            ably.addTest(tests[2]);

            assert.testsEqual(ably.getTest(tests[1].name), tests[1]);
        });

        it('throws exception if test not found', function() {
            ably.addTest(tests[0]);
            ably.addTest(tests[2]);

            assert.throws(function() {
                ably.getTest(tests[1].name);
            });
        });
    });

    describe('.addTest()', function() {
        it('adds tests', function() {
            ably.addTest(tests[0]);
            ably.addTest(tests[1]);
            ably.addTest(tests[2]);

            assert.deepTestsEqual(ably.getTests(), tests);
        });

        it('can be chained', function() {
            ably
                .addTest(tests[0])
                .addTest(tests[1])
                .addTest(tests[2]);

            assert.deepTestsEqual(ably.getTests(), tests);
        });

        it('creates a deep copy', function() {
            ably.addTest(tests[0]);

            var returnedTests = ably.getTests();

            assert.testsEqual(returnedTests[0], tests[0]);
            assert.notEqual(returnedTests[0], tests[0]);
        });

        it('does not call the sampler if no subscribers', function() {
            var samplerCalls = 0,
                test = {
                    name: 'button-color',
                    variants: ['red', 'green'],
                    sampler: function sampler() {
                        samplerCalls++;
                    },
                    scope: 'pageview'
                };

            ably.addTest(test);

            assert.equal(samplerCalls, 0);
        });

        it('adds a test with the default sampler', function(done) {
            var assignment,
                test = {
                    name: 'header-color',
                    variants: ['orange', 'yellow'],
                    sampler: 'default',
                    scope: 'pageview'
                };

            ably.addTest(test);

            ably.when('header-color', 'orange', function() {
                assignment = 'orange';
            });

            ably.when('header-color', 'yellow', function() {
                assignment = 'yellow';
            });

            setTimeout(function() {
                assert.equal(assignment === 'orange' || assignment === 'yellow', true);
                done();
            }, 10);
        });

        it('adds a test with the local sampler', function(done) {
            var assignment,
                test = {
                    name: 'header-color',
                    variants: ['orange', 'yellow'],
                    sampler: 'local',
                    scope: 'pageview'
                };

            ably.addTest(test);

            ably.when('header-color', 'orange', function() {
                assignment = 'orange';
            });

            ably.when('header-color', 'yellow', function() {
                assignment = 'yellow';
            });

            setTimeout(function() {
                assert.equal(assignment === 'orange' || assignment === 'yellow', true);
                done();
            }, 10);
        });

        it('throws exception if sampler not found', function() {
            var test = {
                    name: 'header-color',
                    variants: ['orange', 'yellow'],
                    sampler: 'nonExistentSamplerIJustMadeUp',
                    scope: 'pageview'
                };

            assert.throws(function() {
                ably.addTest(test);
            });
        });

        it('works if no sampler provided', function(done) {
            var assignment,
                test = {
                    name: 'header-color',
                    variants: ['orange', 'yellow'],
                    scope: 'pageview'
                };

            ably.addTest(test);

            ably.when('header-color', 'orange', function() {
                assignment = 'orange';
            });

            ably.when('header-color', 'yellow', function() {
                assignment = 'yellow';
            });

            setTimeout(function() {
                assert.equal(assignment === 'orange' || assignment === 'yellow', true);
                done();
            }, 10);
        });

        it('throws exception if scope not found', function() {
            var test = {
                    name: 'header-color',
                    variants: ['orange', 'yellow'],
                    scope: 'yeahLikeThatCouldBeTheNameOfAScope'
                };

            assert.throws(function() {
                ably.addTest(test);
            });
        });

        it('accepts no scope provided', function() {
            var test = {
                    name: 'header-color',
                    variants: ['orange', 'yellow'],
                    sampler: 'local'
                };

            ably.addTest(test);
        });
    });

    describe('scope', function() {
        it('is used to get and set assignment', function(done) {
            var ably1 = new Ably(),
                ably2 = new Ably(),
                realScopeStorage = {},
                makeupScopeStorage = {
                    'header-color': 'blue'
                },
                sampler = function (callback) {
                    callback('orange');
                },
                scope = {
                    hasItem: function(key) {
                        return realScopeStorage.hasOwnProperty(key);
                    },
                    getItem: function(key) {
                        return makeupScopeStorage[key];
                    },
                    setItem: function(key, value) {
                        realScopeStorage[key] = value;
                    }
                },
                test1 = {
                    name: 'header-color',
                    variants: ['orange', 'blue'],
                    sampler: sampler,
                    scope: scope
                },
                test2 = {
                    name: 'header-color',
                    variants: ['orange', 'blue'],
                    sampler: sampler,
                    scope: scope
                },
                assignment2;

            ably1.addTest(test1);
            ably1.when('header-color', 'orange', function() {
            });

            ably2.addTest(test2);
            ably2.when('header-color', 'blue', function() {
                assignment2 = 'blue';
            });

            setTimeout(function() {
                assert.equal(realScopeStorage['header-color'], 'orange');
                assert.equal(assignment2, 'blue');
                done();
            }, 10);
        });
    });

    describe('.addTests()', function() {
        it('adds tests', function() {
            ably.addTests(tests);

            assert.deepTestsEqual(ably.getTests(), tests);
        });

        it('can be chained', function() {
            ably
                .addTests([tests[0], tests[1]])
                .addTests([tests[2]]);

            var returnedTests = ably.getTests();

            assert.testsEqual(returnedTests[0], tests[0]);
        });

        it('creates deep copies', function() {
            ably.addTests(tests);

            var returnedTests = ably.getTests();

            assert.deepTestsEqual(returnedTests, tests);
            assert.notDeepEqual(returnedTests, tests);
        });

        it('does not call the sampler if no subscribers', function() {
            var samplerCalls = 0,
                test = {
                    name: 'button-color',
                    variants: ['red', 'green'],
                    sampler: function sampler() {
                        samplerCalls++;
                    },
                    scope: 'pageview'
                };

            ably.addTests([test]);

            assert.equal(samplerCalls, 0);
        });
    });

    describe('the sampler', function() {
        it('gets the test object as the second argument', function(done) {
            var assignment,
                expectedTest = {
                    name: 'header-color',
                    variants: ['orange', 'yellow'],
                    sampler: function(callback, actualTest) {
                        assert.testsEqual(actualTest, expectedTest);
                        done();
                    },
                    scope: 'pageview'
                };

            ably.addTest(expectedTest);

            ably.when('header-color', 'orange', function() {
                assignment = 'orange';
            });

            ably.when('header-color', 'yellow', function() {
                assignment = 'yellow';
            });
        });

        it('can be used for multiple tests', function(done) {
            var correctAssignments = 0,
                sampler = function(callback, test) {
                        if (test.name === 'header-color') {
                            callback('orange');
                        }
                        if (test.name === 'button-text') {
                            callback('buy');
                        }
                    },
                    tests = [
                    {
                        name: 'header-color',
                        variants: ['orange', 'yellow'],
                        sampler: sampler,
                        scope: 'pageview'
                    },
                    {
                        name: 'button-text',
                        variants: ['buy', 'subscribe'],
                        sampler: sampler,
                        scope: 'pageview'
                    }
                    ];

            ably.addTests(tests);

            ably.when('header-color', 'orange', function() {
                correctAssignments++;
            });

            ably.when('button-text', 'buy', function() {
                correctAssignments++;
            });

            setTimeout(function() {
                assert.equal(correctAssignments, 2);
                done();
            }, 10);
        });

        it('has uniform distribution', function(done) {
            var distributions = {
                    orange: 0,
                    yellow: 0
                },
                test = {
                    name: 'header-color',
                    variants: ['orange', 'yellow'],
                    sampler: 'local',
                    scope: 'pageview',
                    weights: {orange: 10, yellow: 90}
                },
                markOrange = function() {
                    distributions.orange++;
                },
                markYellow = function() {
                    distributions.yellow++;
                };

            for (var i = 0; i < 1000; i++) {
                test.name = 'header-color' + i;
                ably.addTest(test);
                ably.when('header-color' + i, 'orange', markOrange);
                ably.when('header-color' + i, 'yellow', markYellow);
            }

            setTimeout(function() {
                assert.equal(distributions.orange >= 80, true);
                assert.equal(distributions.orange <= 120, true);
                assert.equal(distributions.yellow >= 880, true);
                assert.equal(distributions.yellow <= 920, true);
                done();
            }, 100);
        });
    });

    describe('.when()', function() {
        var callbacksCalled,
            samplerCalls,
            test = {
                name: 'button-color',
                variants: ['red', 'green'],
                sampler: function sampler(callback) {
                    setTimeout(function () {
                        callback('red');
                    }, 5);
                    samplerCalls++;
                },
                scope: 'pageview'
            };

        beforeEach(function() {
            callbacksCalled = [];
            samplerCalls = 0;
        });

        it('passes test into callback', function(done) {
            ably
                .addTest(test)
                .when('button-color', 'red', function callback(passedTest) {
                    assert.testsEqual(passedTest, test);
                    done();
                });
        });

        it('can subscribe before adding test', function(done) {
            ably
                .when('button-color', 'green', function callback() {
                    callbacksCalled.push(1);
                })
                .when('button-color', 'red', function callback() {
                    callbacksCalled.push(2);
                })
                .when('label-text', 'red', function callback() {
                    callbacksCalled.push(3);
                })
                .when('button-color', 'red', function callback() {
                    callbacksCalled.push(4);
                })
                .when('label-text', 'green', function callback() {
                    callbacksCalled.push(5);
                })
                .addTest(test);

            setTimeout(function verify() {
                assert.deepEqual(callbacksCalled, [2, 4]);
                assert.equal(samplerCalls, 1);
                done();
            }, 10);
        });

        it('can subscribe after adding test', function(done) {
            ably
                .addTest(test)
                .when('button-color', 'green', function callback() {
                    callbacksCalled.push(6);
                })
                .when('button-color', 'red', function callback() {
                    callbacksCalled.push(7);
                })
                .when('label-text', 'red', function callback() {
                    callbacksCalled.push(8);
                })
                .when('button-color', 'red', function callback() {
                    callbacksCalled.push(9);
                })
                .when('label-text', 'green', function callback() {
                    callbacksCalled.push(10);
                });

            setTimeout(function() {
                ably
                    .when('button-color', 'green', function callback() {
                        callbacksCalled.push(11);
                    })
                    .when('button-color', 'red', function callback() {
                        callbacksCalled.push(12);
                    })
                    .when('label-text', 'red', function callback() {
                        callbacksCalled.push(13);
                    })
                    .when('button-color', 'red', function callback() {
                        callbacksCalled.push(14);
                    })
                    .when('label-text', 'green', function callback() {
                        callbacksCalled.push(15);
                    });
            }, 10);

            setTimeout(function verify() {
                assert.deepEqual(callbacksCalled, [7, 9, 12, 14]);
                assert.equal(samplerCalls, 1);
                done();
            }, 15);
        });

        it('can subscribe both before and after adding test', function(done) {
            ably
                .when('button-color', 'green', function callback() {
                    callbacksCalled.push(1);
                })
                .when('button-color', 'red', function callback() {
                    callbacksCalled.push(2);
                })
                .when('label-text', 'red', function callback() {
                    callbacksCalled.push(3);
                })
                .when('button-color', 'red', function callback() {
                    callbacksCalled.push(4);
                })
                .when('label-text', 'green', function callback() {
                    callbacksCalled.push(5);
                })
                .addTest(test)
                .when('button-color', 'green', function callback() {
                    callbacksCalled.push(6);
                })
                .when('button-color', 'red', function callback() {
                    callbacksCalled.push(7);
                })
                .when('label-text', 'red', function callback() {
                    callbacksCalled.push(8);
                })
                .when('button-color', 'red', function callback() {
                    callbacksCalled.push(9);
                })
                .when('label-text', 'green', function callback() {
                    callbacksCalled.push(10);
                });

            setTimeout(function() {
                ably
                    .when('button-color', 'green', function callback() {
                        callbacksCalled.push(11);
                    })
                    .when('button-color', 'red', function callback() {
                        callbacksCalled.push(12);
                    })
                    .when('label-text', 'red', function callback() {
                        callbacksCalled.push(13);
                    })
                    .when('button-color', 'red', function callback() {
                        callbacksCalled.push(14);
                    })
                    .when('label-text', 'green', function callback() {
                        callbacksCalled.push(15);
                    });
            }, 10);

            setTimeout(function verify() {
                assert.deepEqual(callbacksCalled, [2, 4, 7, 9, 12, 14]);
                assert.equal(samplerCalls, 1);
                done();
            }, 15);
        });

        it('can subscribe to all variants', function(done) {
            ably
                .addTest(test)
                .when('button-color', function callback(passedTest) {
                    assert.testsEqual(passedTest, test);
                    done();
                });
        });

        // if the subscriber is not defined or null or not a function
        // cannot add test twice
    });
});
<commit_msg>Fix Expected indentation of 16 space characters but found 20 (indent)<commit_after>'use strict';

var assert = require('assert');
var Ably = require('../src/ably');

var ably;

assert.testsEqual = function deepDeepEqual(actual, expected) {
    assert.equal(actual.name, expected.name);
    assert.equal(actual.variants, expected.variants);
    if (typeof expected.sampler === 'string') {
        expected.sampler = ably.samplers[expected.sampler];
    }
    assert.equal(actual.sampler, expected.sampler);
};

assert.deepTestsEqual = function deepDeepEqual(actual, expected) {
    assert.equal(actual.length, expected.length);
    for (var i = 0; i < actual.length; i++) {
        assert.testsEqual(actual, expected);
    }
};

describe('Ably', function() {
    beforeEach(function() {
        ably = new Ably();
    });

    it('is an object', function() {
        assert.equal(typeof ably, 'object');
    });

    it('accepts namespace', function() {
        var namespace = 'just a test namespace in order to test namespaces';
        ably = new Ably(namespace);

        assert.equal(ably.namespace, namespace);
    });

    it('has an addTest method', function() {
        assert.equal(typeof ably.addTest, 'function');
    });

    it('has an addTests method', function() {
        assert.equal(typeof ably.addTests, 'function');
    });

    it('has a getTest method', function() {
        assert.equal(typeof ably.getTest, 'function');
    });

    it('has a getTests method', function() {
        assert.equal(typeof ably.getTests, 'function');
    });

    it('has a when method', function() {
        assert.equal(typeof ably.when, 'function');
    });

    var tests = [
        {
            name: 'button-color',
            variants: ['red', 'green'],
            sampler: function sampler(callback) {
                callback('red');
            },
            scope: 'pageview'
        },
        {
            name: 'button-text',
            variants: ['buy', 'subscribe'],
            sampler: function sampler(callback) {
                callback('buy');
            },
            scope: 'pageview'
        },
        {
            name: 'button-size',
            variants: ['large', 'small'],
            sampler: function sampler(callback) {
                callback('large');
            },
            scope: 'pageview'
        }
    ];

    describe('.getTest(name)', function() {
        it('retrieves test named \'name\'', function() {
            ably.addTest(tests[0]);
            ably.addTest(tests[1]);
            ably.addTest(tests[2]);

            assert.testsEqual(ably.getTest(tests[1].name), tests[1]);
        });

        it('throws exception if test not found', function() {
            ably.addTest(tests[0]);
            ably.addTest(tests[2]);

            assert.throws(function() {
                ably.getTest(tests[1].name);
            });
        });
    });

    describe('.addTest()', function() {
        it('adds tests', function() {
            ably.addTest(tests[0]);
            ably.addTest(tests[1]);
            ably.addTest(tests[2]);

            assert.deepTestsEqual(ably.getTests(), tests);
        });

        it('can be chained', function() {
            ably
                .addTest(tests[0])
                .addTest(tests[1])
                .addTest(tests[2]);

            assert.deepTestsEqual(ably.getTests(), tests);
        });

        it('creates a deep copy', function() {
            ably.addTest(tests[0]);

            var returnedTests = ably.getTests();

            assert.testsEqual(returnedTests[0], tests[0]);
            assert.notEqual(returnedTests[0], tests[0]);
        });

        it('does not call the sampler if no subscribers', function() {
            var samplerCalls = 0,
                test = {
                    name: 'button-color',
                    variants: ['red', 'green'],
                    sampler: function sampler() {
                        samplerCalls++;
                    },
                    scope: 'pageview'
                };

            ably.addTest(test);

            assert.equal(samplerCalls, 0);
        });

        it('adds a test with the default sampler', function(done) {
            var assignment,
                test = {
                    name: 'header-color',
                    variants: ['orange', 'yellow'],
                    sampler: 'default',
                    scope: 'pageview'
                };

            ably.addTest(test);

            ably.when('header-color', 'orange', function() {
                assignment = 'orange';
            });

            ably.when('header-color', 'yellow', function() {
                assignment = 'yellow';
            });

            setTimeout(function() {
                assert.equal(assignment === 'orange' || assignment === 'yellow', true);
                done();
            }, 10);
        });

        it('adds a test with the local sampler', function(done) {
            var assignment,
                test = {
                    name: 'header-color',
                    variants: ['orange', 'yellow'],
                    sampler: 'local',
                    scope: 'pageview'
                };

            ably.addTest(test);

            ably.when('header-color', 'orange', function() {
                assignment = 'orange';
            });

            ably.when('header-color', 'yellow', function() {
                assignment = 'yellow';
            });

            setTimeout(function() {
                assert.equal(assignment === 'orange' || assignment === 'yellow', true);
                done();
            }, 10);
        });

        it('throws exception if sampler not found', function() {
            var test = {
                name: 'header-color',
                variants: ['orange', 'yellow'],
                sampler: 'nonExistentSamplerIJustMadeUp',
                scope: 'pageview'
            };

            assert.throws(function() {
                ably.addTest(test);
            });
        });

        it('works if no sampler provided', function(done) {
            var assignment,
                test = {
                    name: 'header-color',
                    variants: ['orange', 'yellow'],
                    scope: 'pageview'
                };

            ably.addTest(test);

            ably.when('header-color', 'orange', function() {
                assignment = 'orange';
            });

            ably.when('header-color', 'yellow', function() {
                assignment = 'yellow';
            });

            setTimeout(function() {
                assert.equal(assignment === 'orange' || assignment === 'yellow', true);
                done();
            }, 10);
        });

        it('throws exception if scope not found', function() {
            var test = {
                name: 'header-color',
                variants: ['orange', 'yellow'],
                scope: 'yeahLikeThatCouldBeTheNameOfAScope'
            };

            assert.throws(function() {
                ably.addTest(test);
            });
        });

        it('accepts no scope provided', function() {
            var test = {
                name: 'header-color',
                variants: ['orange', 'yellow'],
                sampler: 'local'
            };

            ably.addTest(test);
        });
    });

    describe('scope', function() {
        it('is used to get and set assignment', function(done) {
            var ably1 = new Ably(),
                ably2 = new Ably(),
                realScopeStorage = {},
                makeupScopeStorage = {
                    'header-color': 'blue'
                },
                sampler = function (callback) {
                    callback('orange');
                },
                scope = {
                    hasItem: function(key) {
                        return realScopeStorage.hasOwnProperty(key);
                    },
                    getItem: function(key) {
                        return makeupScopeStorage[key];
                    },
                    setItem: function(key, value) {
                        realScopeStorage[key] = value;
                    }
                },
                test1 = {
                    name: 'header-color',
                    variants: ['orange', 'blue'],
                    sampler: sampler,
                    scope: scope
                },
                test2 = {
                    name: 'header-color',
                    variants: ['orange', 'blue'],
                    sampler: sampler,
                    scope: scope
                },
                assignment2;

            ably1.addTest(test1);
            ably1.when('header-color', 'orange', function() {
            });

            ably2.addTest(test2);
            ably2.when('header-color', 'blue', function() {
                assignment2 = 'blue';
            });

            setTimeout(function() {
                assert.equal(realScopeStorage['header-color'], 'orange');
                assert.equal(assignment2, 'blue');
                done();
            }, 10);
        });
    });

    describe('.addTests()', function() {
        it('adds tests', function() {
            ably.addTests(tests);

            assert.deepTestsEqual(ably.getTests(), tests);
        });

        it('can be chained', function() {
            ably
                .addTests([tests[0], tests[1]])
                .addTests([tests[2]]);

            var returnedTests = ably.getTests();

            assert.testsEqual(returnedTests[0], tests[0]);
        });

        it('creates deep copies', function() {
            ably.addTests(tests);

            var returnedTests = ably.getTests();

            assert.deepTestsEqual(returnedTests, tests);
            assert.notDeepEqual(returnedTests, tests);
        });

        it('does not call the sampler if no subscribers', function() {
            var samplerCalls = 0,
                test = {
                    name: 'button-color',
                    variants: ['red', 'green'],
                    sampler: function sampler() {
                        samplerCalls++;
                    },
                    scope: 'pageview'
                };

            ably.addTests([test]);

            assert.equal(samplerCalls, 0);
        });
    });

    describe('the sampler', function() {
        it('gets the test object as the second argument', function(done) {
            var assignment,
                expectedTest = {
                    name: 'header-color',
                    variants: ['orange', 'yellow'],
                    sampler: function(callback, actualTest) {
                        assert.testsEqual(actualTest, expectedTest);
                        done();
                    },
                    scope: 'pageview'
                };

            ably.addTest(expectedTest);

            ably.when('header-color', 'orange', function() {
                assignment = 'orange';
            });

            ably.when('header-color', 'yellow', function() {
                assignment = 'yellow';
            });
        });

        it('can be used for multiple tests', function(done) {
            var correctAssignments = 0,
                sampler = function(callback, test) {
                    if (test.name === 'header-color') {
                        callback('orange');
                    }
                    if (test.name === 'button-text') {
                        callback('buy');
                    }
                },
                tests = [
                    {
                        name: 'header-color',
                        variants: ['orange', 'yellow'],
                        sampler: sampler,
                        scope: 'pageview'
                    },
                    {
                        name: 'button-text',
                        variants: ['buy', 'subscribe'],
                        sampler: sampler,
                        scope: 'pageview'
                    }
                ];

            ably.addTests(tests);

            ably.when('header-color', 'orange', function() {
                correctAssignments++;
            });

            ably.when('button-text', 'buy', function() {
                correctAssignments++;
            });

            setTimeout(function() {
                assert.equal(correctAssignments, 2);
                done();
            }, 10);
        });

        it('has uniform distribution', function(done) {
            var distributions = {
                    orange: 0,
                    yellow: 0
                },
                test = {
                    name: 'header-color',
                    variants: ['orange', 'yellow'],
                    sampler: 'local',
                    scope: 'pageview',
                    weights: {orange: 10, yellow: 90}
                },
                markOrange = function() {
                    distributions.orange++;
                },
                markYellow = function() {
                    distributions.yellow++;
                };

            for (var i = 0; i < 1000; i++) {
                test.name = 'header-color' + i;
                ably.addTest(test);
                ably.when('header-color' + i, 'orange', markOrange);
                ably.when('header-color' + i, 'yellow', markYellow);
            }

            setTimeout(function() {
                assert.equal(distributions.orange >= 80, true);
                assert.equal(distributions.orange <= 120, true);
                assert.equal(distributions.yellow >= 880, true);
                assert.equal(distributions.yellow <= 920, true);
                done();
            }, 100);
        });
    });

    describe('.when()', function() {
        var callbacksCalled,
            samplerCalls,
            test = {
                name: 'button-color',
                variants: ['red', 'green'],
                sampler: function sampler(callback) {
                    setTimeout(function () {
                        callback('red');
                    }, 5);
                    samplerCalls++;
                },
                scope: 'pageview'
            };

        beforeEach(function() {
            callbacksCalled = [];
            samplerCalls = 0;
        });

        it('passes test into callback', function(done) {
            ably
                .addTest(test)
                .when('button-color', 'red', function callback(passedTest) {
                    assert.testsEqual(passedTest, test);
                    done();
                });
        });

        it('can subscribe before adding test', function(done) {
            ably
                .when('button-color', 'green', function callback() {
                    callbacksCalled.push(1);
                })
                .when('button-color', 'red', function callback() {
                    callbacksCalled.push(2);
                })
                .when('label-text', 'red', function callback() {
                    callbacksCalled.push(3);
                })
                .when('button-color', 'red', function callback() {
                    callbacksCalled.push(4);
                })
                .when('label-text', 'green', function callback() {
                    callbacksCalled.push(5);
                })
                .addTest(test);

            setTimeout(function verify() {
                assert.deepEqual(callbacksCalled, [2, 4]);
                assert.equal(samplerCalls, 1);
                done();
            }, 10);
        });

        it('can subscribe after adding test', function(done) {
            ably
                .addTest(test)
                .when('button-color', 'green', function callback() {
                    callbacksCalled.push(6);
                })
                .when('button-color', 'red', function callback() {
                    callbacksCalled.push(7);
                })
                .when('label-text', 'red', function callback() {
                    callbacksCalled.push(8);
                })
                .when('button-color', 'red', function callback() {
                    callbacksCalled.push(9);
                })
                .when('label-text', 'green', function callback() {
                    callbacksCalled.push(10);
                });

            setTimeout(function() {
                ably
                    .when('button-color', 'green', function callback() {
                        callbacksCalled.push(11);
                    })
                    .when('button-color', 'red', function callback() {
                        callbacksCalled.push(12);
                    })
                    .when('label-text', 'red', function callback() {
                        callbacksCalled.push(13);
                    })
                    .when('button-color', 'red', function callback() {
                        callbacksCalled.push(14);
                    })
                    .when('label-text', 'green', function callback() {
                        callbacksCalled.push(15);
                    });
            }, 10);

            setTimeout(function verify() {
                assert.deepEqual(callbacksCalled, [7, 9, 12, 14]);
                assert.equal(samplerCalls, 1);
                done();
            }, 15);
        });

        it('can subscribe both before and after adding test', function(done) {
            ably
                .when('button-color', 'green', function callback() {
                    callbacksCalled.push(1);
                })
                .when('button-color', 'red', function callback() {
                    callbacksCalled.push(2);
                })
                .when('label-text', 'red', function callback() {
                    callbacksCalled.push(3);
                })
                .when('button-color', 'red', function callback() {
                    callbacksCalled.push(4);
                })
                .when('label-text', 'green', function callback() {
                    callbacksCalled.push(5);
                })
                .addTest(test)
                .when('button-color', 'green', function callback() {
                    callbacksCalled.push(6);
                })
                .when('button-color', 'red', function callback() {
                    callbacksCalled.push(7);
                })
                .when('label-text', 'red', function callback() {
                    callbacksCalled.push(8);
                })
                .when('button-color', 'red', function callback() {
                    callbacksCalled.push(9);
                })
                .when('label-text', 'green', function callback() {
                    callbacksCalled.push(10);
                });

            setTimeout(function() {
                ably
                    .when('button-color', 'green', function callback() {
                        callbacksCalled.push(11);
                    })
                    .when('button-color', 'red', function callback() {
                        callbacksCalled.push(12);
                    })
                    .when('label-text', 'red', function callback() {
                        callbacksCalled.push(13);
                    })
                    .when('button-color', 'red', function callback() {
                        callbacksCalled.push(14);
                    })
                    .when('label-text', 'green', function callback() {
                        callbacksCalled.push(15);
                    });
            }, 10);

            setTimeout(function verify() {
                assert.deepEqual(callbacksCalled, [2, 4, 7, 9, 12, 14]);
                assert.equal(samplerCalls, 1);
                done();
            }, 15);
        });

        it('can subscribe to all variants', function(done) {
            ably
                .addTest(test)
                .when('button-color', function callback(passedTest) {
                    assert.testsEqual(passedTest, test);
                    done();
                });
        });

        // if the subscriber is not defined or null or not a function
        // cannot add test twice
    });
});
<|endoftext|>


<commit_before>'use strict';

var server = require('supertest').agent("http://localhost:8000");
var should = require('chai').should();

describe("api test", function () {

    it("returns json data", function (done) {
        server
            .get("/app/api/sample.json")
            .expect("Content-type", /json/)
            .expect(200)
            .end(function (err, res) {
                if (err) throw err;
                res.body.name.should.equal('Brady');
                done();
            });
    });

    it("attepts to redirect", function (done) {
        server
            .get("/dist")
            .expect(302)
            .end(function (err, res) {
                if (err) throw err;
                done();
            });
    });

    it("returns html", function (done) {
        server
            .get("/dist/index.html")
            .expect(200)
            .end(function (err, res) {
                if (err) throw err;
                done();
            });
    });
});<commit_msg>update tests<commit_after>'use strict';

var server = require('supertest').agent("http://localhost:8000");
var should = require('chai').should();

describe("api test", function () {

    it("returns json data", function (done) {
        server
            .get("/app/api/sample.json")
            .expect("Content-type", /json/)
            .expect(200)
            .end(function (err, res) {
                if (err) throw err;
                res.body.name.should.equal('Brady');
                done();
            });
    });

    it("attepts to redirect", function (done) {
        server
            .get("/dist")
            .expect(302)
            .end(function (err, res) {
                if (err) throw err;
                done();
            });
    });

    it("returns html", function (done) {
        server
            .get("/dist/index.html")
            .expect("Content-type", /html/)
            .expect(200)
            .end(function (err, res) {
                if (err) throw err;
                done();
            });
    });
});<|endoftext|>


<commit_before>var AnimateOnScroll = {
    active: false,
    window: null,
    elements: [],
    offsets: [],
    windowHeight: 0,
    windowInnerHeight: 0,
    zindex: 1,
    options: {},
    onLoadCallback: null,
    debug: true,
    initialize: function(onLoadCallback) {
        AnimateOnScroll.onLoadCallback = onLoadCallback;
        if (AnimateOnScroll.active) {
            AnimateOnScroll.runOnLoadCallback(onLoadCallback);
            return true;
        }

        var $window = $(window);
        AnimateOnScroll.window = $window;
        AnimateOnScroll.windowHeight = $window.height();
        AnimateOnScroll.windowInnerHeight = $window.innerHeight();

        AnimateOnScroll.options = {
            opacity: 1,
            top: 0,
            scale: 1,
            rotate: 0,
        };

        //Let content load before loading elements (Some element has no height at start)
        setTimeout(AnimateOnScroll.initializeElements, 400)
        AnimateOnScroll.active = true;
    },
    initializeElements: function() {
        if (AnimateOnScroll.setElements()) {
            AnimateOnScroll.listenForScroll();
        }
        $(document).trigger('AnimateOnScrollInitialized');
    },
    setElements: function() {
        var $elements = $('.animateOnScroll');
        var elementLength = $elements.length;
        if (elementLength > 0) {
            var $element;
            var visible;
            for (var i = 0; i < elementLength; i++) {
                $element = $($elements[i]);
                visible = AnimateOnScroll.isVisible($element);

                if (!visible) {
                    var topOffset = $element.offset().top;
                    var elementOffset = $element.data('offset') || 0;
                    AnimateOnScroll.elements[i] = $element;
                    AnimateOnScroll.offsets[i] = topOffset + elementOffset;
                    AnimateOnScroll.setElementStyles($element);
                }
            }
            return true;
        }
        return false;
    },
    isVisible: function($element) {
      var rect = $element[0].getBoundingClientRect();
      var viewHeight = Math.max(AnimateOnScroll.windowHeight, AnimateOnScroll.windowInnerHeight);
      var isVisible = !(rect.bottom < 0 || rect.top - viewHeight >= 0);
      return isVisible;
    },
    listenForScroll: function() {
        var elementLength = AnimateOnScroll.offsets.length;
        ScrollHandler.onScroll(function($this) {
            var currentScroll = $this.scrollTop();
            var collision = currentScroll + AnimateOnScroll.windowHeight;
            var $element;
            var offset = 0;
            for (i = 0; i < elementLength; i++) {
                offset = AnimateOnScroll.offsets[i];
                if (collision > offset) {
                    AnimateOnScroll.prepareAnimation(AnimateOnScroll.elements[i]);
                    delete AnimateOnScroll.elements[i];
                    delete AnimateOnScroll.offsets[i];
                }
            }
        });
    },
    getStyleProperty: function(option, optionValue, style) {;
        var webkitTransform = style['-webkit-transform'] || '';
        var msTransform = style['-ms-transform'] || '';
        var transform = style['transform'] || '';
        if (option == 'scale' || option == 'rotate' || option == 'translate') {
            webkitTransform += ' '+ option +'('+ optionValue +')';
            msTransform += ' '+ option +'('+ optionValue +')';
            transform += ' '+ option +'('+ optionValue +')';

            style['-webkit-transform'] = webkitTransform;
            style['-ms-transform'] = msTransform;
            style['transform'] = transform;
        } else {
            style[option] = optionValue;
        }

        return style;
    },
    setElementStyles: function($element) {
        var speed = $element.data('speed') || 400;

        var options = AnimateOnScroll.options;
        var style = {};
        var defaultStyle = {};
        $.each(options, function(option, defaultValue) {
            if (typeof $element.data(option) != 'undefined') {
                optionValue = $element.data(option);
                style = AnimateOnScroll.getStyleProperty(option, optionValue, style);
            }
            defaultStyle = AnimateOnScroll.getStyleProperty(option, defaultValue, defaultStyle);
        });

        $element.css(style);
        defaultStyle.transition = 'all '+ speed +'ms';
        $element.defaultStyle = defaultStyle;
    },
    prepareAnimation: function($element) {
        var delay = $element.data('delay') || 0;
        var noDelayBelow = $element.data('nodelaybelow') || 0;
            noDelayBelow = parseInt(noDelayBelow);
        var windowWidth = AnimateOnScroll.window.width();

        if (delay > 0 && (noDelayBelow == 0 || windowWidth > noDelayBelow)) {
            setTimeout(function() {
                AnimateOnScroll.runAnimation($element);
            }, delay);
            return true;
        }

        AnimateOnScroll.runAnimation($element);
    },
    runAnimation: function($element) {
        $.extend($element.defaultStyle, {'z-index': AnimateOnScroll.updateZindex()})
        $element.css( $element.defaultStyle ).addClass('animateOnScrollCompleted');
    },
    updateZindex: function() {
        return AnimateOnScroll.zindex++;
    },
    runOnLoadCallback: function(callback) {
        var callback = typeof callback == 'function' ? callback : AnimateOnScroll.onLoadCallback;
        if (typeof callback == 'function') {
            callback();
        }
    },
    debug: function(str) {
        if (AnimateOnScroll.debug) {
            console.log(str);
        }
    }
};
<commit_msg>Fix minus z-index<commit_after>var AnimateOnScroll = {
    active: false,
    window: null,
    elements: [],
    offsets: [],
    windowHeight: 0,
    windowInnerHeight: 0,
    zindex: 1,
    options: {},
    onLoadCallback: null,
    debug: true,
    initialize: function(onLoadCallback) {
        AnimateOnScroll.onLoadCallback = onLoadCallback;
        if (AnimateOnScroll.active) {
            AnimateOnScroll.runOnLoadCallback(onLoadCallback);
            return true;
        }

        var $window = $(window);
        AnimateOnScroll.window = $window;
        AnimateOnScroll.windowHeight = $window.height();
        AnimateOnScroll.windowInnerHeight = $window.innerHeight();

        AnimateOnScroll.options = {
            opacity: 1,
            top: 0,
            scale: 1,
            rotate: 0,
        };

        //Let content load before loading elements (Some element has no height at start)
        setTimeout(AnimateOnScroll.initializeElements, 400)
        AnimateOnScroll.active = true;
    },
    initializeElements: function() {
        if (AnimateOnScroll.setElements()) {
            AnimateOnScroll.listenForScroll();
        }
        $(document).trigger('AnimateOnScrollInitialized');
    },
    setElements: function() {
        var $elements = $('.animateOnScroll');
        var elementLength = $elements.length;
        if (elementLength > 0) {
            var $element;
            var visible;
            for (var i = 0; i < elementLength; i++) {
                $element = $($elements[i]);
                visible = AnimateOnScroll.isVisible($element);

                if (!visible) {
                    var topOffset = $element.offset().top;
                    var elementOffset = $element.data('offset') || 0;
                    AnimateOnScroll.elements[i] = $element;
                    AnimateOnScroll.offsets[i] = topOffset + elementOffset;
                    AnimateOnScroll.setElementStyles($element);
                } else {
                    AnimateOnScroll.setAnimatedClass($element);
                }
            }
            return true;
        }
        return false;
    },
    isVisible: function($element) {
      var rect = $element[0].getBoundingClientRect();
      var viewHeight = Math.max(AnimateOnScroll.windowHeight, AnimateOnScroll.windowInnerHeight);
      var isVisible = !(rect.bottom < 0 || rect.top - viewHeight >= 0);
      return isVisible;
    },
    listenForScroll: function() {
        var elementLength = AnimateOnScroll.offsets.length;
        ScrollHandler.onScroll(function($this) {
            var currentScroll = $this.scrollTop();
            console.log(currentScroll);
            var collision = currentScroll + AnimateOnScroll.windowHeight;
            var $element;
            var offset = 0;
            for (i = 0; i < elementLength; i++) {
                offset = AnimateOnScroll.offsets[i];
                if (collision > offset) {
                    AnimateOnScroll.prepareAnimation(AnimateOnScroll.elements[i]);
                    delete AnimateOnScroll.elements[i];
                    delete AnimateOnScroll.offsets[i];
                }
            }
        });
    },
    getStyleProperty: function(option, optionValue, style) {;
        var webkitTransform = style['-webkit-transform'] || '';
        var msTransform = style['-ms-transform'] || '';
        var transform = style['transform'] || '';
        if (option == 'scale' || option == 'rotate' || option == 'translate') {
            webkitTransform += ' '+ option +'('+ optionValue +')';
            msTransform += ' '+ option +'('+ optionValue +')';
            transform += ' '+ option +'('+ optionValue +')';

            style['-webkit-transform'] = webkitTransform;
            style['-ms-transform'] = msTransform;
            style['transform'] = transform;
        } else {
            style[option] = optionValue;
        }

        return style;
    },
    setElementStyles: function($element) {
        var speed = $element.data('speed') || 400;

        var options = AnimateOnScroll.options;
        var style = {};
        var defaultStyle = {};
        $.each(options, function(option, defaultValue) {
            if (typeof $element.data(option) != 'undefined') {
                optionValue = $element.data(option);
                style = AnimateOnScroll.getStyleProperty(option, optionValue, style);
            }
            defaultStyle = AnimateOnScroll.getStyleProperty(option, defaultValue, defaultStyle);
        });

        $element.css(style);
        defaultStyle.transition = 'all '+ speed +'ms';
        $element.defaultStyle = defaultStyle;
        AnimateOnScroll.setAnimatedClass($element);
    },
    prepareAnimation: function($element) {
        var delay = $element.data('delay') || 0;
        var noDelayBelow = $element.data('nodelaybelow') || 0;
            noDelayBelow = parseInt(noDelayBelow);
        var windowWidth = AnimateOnScroll.window.width();

        if (delay > 0 && (noDelayBelow == 0 || windowWidth > noDelayBelow)) {
            setTimeout(function() {
                AnimateOnScroll.runAnimation($element);
            }, delay);
            return true;
        }

        AnimateOnScroll.runAnimation($element);
    },
    runAnimation: function($element) {
        $.extend($element.defaultStyle, {'z-index': AnimateOnScroll.updateZindex()})
        $element.css( $element.defaultStyle ).addClass('animateOnScrollCompleted');
    },
    setAnimatedClass: function($element) {
        $element.addClass('animateOnScrollAnimated');
    },
    updateZindex: function() {
        return AnimateOnScroll.zindex++;
    },
    runOnLoadCallback: function(callback) {
        var callback = typeof callback == 'function' ? callback : AnimateOnScroll.onLoadCallback;
        if (typeof callback == 'function') {
            callback();
        }
    },
    debug: function(str) {
        if (AnimateOnScroll.debug) {
            console.log(str);
        }
    }
};
<|endoftext|>


<commit_before>/*globals describe it beforeEach afterEach */
require("should");
var path = require("path");
var fs = require("fs");
var TestHelper = require("./helpers/TestHelper");
var Watchpack = require("../lib/watchpack");

var fixtures = path.join(__dirname, "fixtures");
var testHelper = new TestHelper(fixtures);

describe("Assumtion", function() {
	this.timeout(10000);
	beforeEach(testHelper.before);
	afterEach(testHelper.after);

	it("should have a file system with correct mtime behavior", function(done) {
		var i = 10;
		testHelper.tick(100, function checkMtime() {
			var before = Date.now();
			testHelper.file("a");
			var after = Date.now();
			var s = fs.statSync(path.join(fixtures, "a"));
			(+s.mtime).should.be.aboveOrEqual(before);
			(+s.mtime).should.be.below(after + 2000);
			if(i-- === 0)
				done();
			else
				testHelper.tick(100, checkMtime);
		});
	});
});

<commit_msg>linux seem to round down a bit<commit_after>/*globals describe it beforeEach afterEach */
require("should");
var path = require("path");
var fs = require("fs");
var TestHelper = require("./helpers/TestHelper");
var Watchpack = require("../lib/watchpack");

var fixtures = path.join(__dirname, "fixtures");
var testHelper = new TestHelper(fixtures);

describe("Assumtion", function() {
	this.timeout(10000);
	beforeEach(testHelper.before);
	afterEach(testHelper.after);

	it("should have a file system with correct mtime behavior", function(done) {
		var i = 10;
		testHelper.tick(100, function checkMtime() {
			var before = Date.now();
			testHelper.file("a");
			var after = Date.now();
			var s = fs.statSync(path.join(fixtures, "a"));
			(+s.mtime).should.be.aboveOrEqual(before - 2000);
			(+s.mtime).should.be.below(after + 2000);
			if(i-- === 0)
				done();
			else
				testHelper.tick(100, checkMtime);
		});
	});
});

<|endoftext|>


<commit_before>import configService from '../../shared/ConfigService';
import { close } from '../actions/parent';
import { toggleFavouriteInWindow } from '../../child/actions/favourites';
import { willBeInitialOpen } from '../../child/actions/initialOpen';

class ParentService {

    constructor(store) {
        this.store = store;
        this.parentClosing = false;
        this.onChildClosed = this.onChildClosed.bind(this);
        this.onCloseRequested = this.onCloseRequested.bind(this);

        fin.desktop.InterApplicationBus.subscribe(
            fin.desktop.Application.getCurrent().uuid,
            'createChildWindow',
            (config) => this.createChildWindow(config)
        );
    }

    getChildWindowCount() {
        return Object.keys(this.store.getState().childWindows).length;
    }

    getWindowDragOutCount() {
        return Object.keys(this.store.getState().dragOut).length;
    }

    onChildClosed({ name }) {
        if (this.parentClosing) {
            return;
        }

        const isFinalChildWindowClosing = this.getChildWindowCount() <= 1;

        if (isFinalChildWindowClosing && this.getWindowDragOutCount() === 0) {
            fin.desktop.Window.getCurrent().close();
        } else {
            this.store.dispatch(close(name, Date.now()));
        }
    }

    onCloseRequested() {
        this.parentClosing = true;
        fin.desktop.Window.getCurrent().close(true);
    }

    createChildWindowSuccess(childWindow, position, defaultStocks) {
        if (position) {
            childWindow.setBounds(position[0], position[1]);
        }

        if (defaultStocks) {
            const childWindowName = childWindow.name;
            this.store.dispatch(willBeInitialOpen(childWindowName));
            defaultStocks.forEach((code) => {
                this.store.dispatch(toggleFavouriteInWindow(code, childWindowName));
            });
        }

        childWindow.show();
        childWindow.addEventListener('closed', this.onChildClosed);
    }

    createChildWindow(config = {}) {
        const { windowName, position, initialState, defaultStocks } = config;
        const windowConfig = this.getChildWindowConfigOrDefault(windowName, initialState);
        const childWindow = new fin.desktop.Window(
            windowConfig,
            () => this.createChildWindowSuccess(childWindow, position, defaultStocks)
        );
    }

    getChildWindowConfigOrDefault(windowName, initialState) {
        let windowConfig;
        if (windowName && initialState) {
            if (initialState.windowState.isCompact) {
                windowConfig = configService.getCompactWindowConfig(windowName);
            } else if (initialState.windowState.isMaximized) {
                windowConfig = configService.getMaximizedWindowConfig(windowName);
            } else {
                windowConfig = configService.getWindowConfig(windowName);
            }
        } else if (windowName) {
            windowConfig = configService.getWindowConfig(windowName);
        } else {
            windowConfig = configService.getWindowConfig();
        }
        return windowConfig;
    }

    start() {
        fin.desktop.Window.getCurrent().contentWindow.store = this.store;

        fin.desktop.Window.getCurrent().addEventListener('close-requested', this.onCloseRequested);

        if (this.getChildWindowCount() === 0) {
            this.createChildWindow({ defaultStocks: configService.getDefaultStocks() });
        } else {
            const childWindows = this.store.getState().childWindows;
            Object.keys(childWindows).forEach((windowName) => {
                const newWindowName = windowName === 'undefined' ? null : windowName;
                this.createChildWindow({ windowName: newWindowName, initialState: childWindows[newWindowName] });
            });
        }
    }

}

export default ParentService;
<commit_msg>fix: don't close application if close event is triggered for penultimate window twice (#947)<commit_after>import configService from '../../shared/ConfigService';
import { close } from '../actions/parent';
import { toggleFavouriteInWindow } from '../../child/actions/favourites';
import { willBeInitialOpen } from '../../child/actions/initialOpen';

class ParentService {

    constructor(store) {
        this.store = store;
        this.parentClosing = false;
        this.onChildClosed = this.onChildClosed.bind(this);
        this.onCloseRequested = this.onCloseRequested.bind(this);

        fin.desktop.InterApplicationBus.subscribe(
            fin.desktop.Application.getCurrent().uuid,
            'createChildWindow',
            (config) => this.createChildWindow(config)
        );
    }

    getChildWindowCount() {
        return Object.keys(this.store.getState().childWindows).length;
    }

    getWindowDragOutCount() {
        return Object.keys(this.store.getState().dragOut).length;
    }

    onChildClosed({ name }) {
        if (this.parentClosing) {
            return;
        }

        const isFinalChildWindowClosing = this.getChildWindowCount() === 0 || (this.getChildWindowCount() === 1 && this.store.getState().childWindows[name]);

        if (isFinalChildWindowClosing && this.getWindowDragOutCount() === 0) {
            fin.desktop.Window.getCurrent().close();
        } else {
            this.store.dispatch(close(name, Date.now()));
        }
    }

    onCloseRequested() {
        this.parentClosing = true;
        fin.desktop.Window.getCurrent().close(true);
    }

    createChildWindowSuccess(childWindow, position, defaultStocks) {
        if (position) {
            childWindow.setBounds(position[0], position[1]);
        }

        if (defaultStocks) {
            const childWindowName = childWindow.name;
            this.store.dispatch(willBeInitialOpen(childWindowName));
            defaultStocks.forEach((code) => {
                this.store.dispatch(toggleFavouriteInWindow(code, childWindowName));
            });
        }

        childWindow.show();
        childWindow.addEventListener('closed', this.onChildClosed);
    }

    createChildWindow(config = {}) {
        const { windowName, position, initialState, defaultStocks } = config;
        const windowConfig = this.getChildWindowConfigOrDefault(windowName, initialState);
        const childWindow = new fin.desktop.Window(
            windowConfig,
            () => this.createChildWindowSuccess(childWindow, position, defaultStocks)
        );
    }

    getChildWindowConfigOrDefault(windowName, initialState) {
        let windowConfig;
        if (windowName && initialState) {
            if (initialState.windowState.isCompact) {
                windowConfig = configService.getCompactWindowConfig(windowName);
            } else if (initialState.windowState.isMaximized) {
                windowConfig = configService.getMaximizedWindowConfig(windowName);
            } else {
                windowConfig = configService.getWindowConfig(windowName);
            }
        } else if (windowName) {
            windowConfig = configService.getWindowConfig(windowName);
        } else {
            windowConfig = configService.getWindowConfig();
        }
        return windowConfig;
    }

    start() {
        fin.desktop.Window.getCurrent().contentWindow.store = this.store;

        fin.desktop.Window.getCurrent().addEventListener('close-requested', this.onCloseRequested);

        if (this.getChildWindowCount() === 0) {
            this.createChildWindow({ defaultStocks: configService.getDefaultStocks() });
        } else {
            const childWindows = this.store.getState().childWindows;
            Object.keys(childWindows).forEach((windowName) => {
                const newWindowName = windowName === 'undefined' ? null : windowName;
                this.createChildWindow({ windowName: newWindowName, initialState: childWindows[newWindowName] });
            });
        }
    }

}

export default ParentService;
<|endoftext|>


<commit_before>import React from 'react';

import { Abelito75, Zeboot } from 'CONTRIBUTORS';
import { change, date } from 'common/changelog';

// prettier-ignore
export default [
  change(date(2020, 12, 10), <>Fixed a bug that made devo aura inaccurate.</>, Abelito75),
  change(date(2020, 12, 10), <>Fixed bug where Light of the Martyr's ineffiecent tooltip would crash the page.</>, Abelito75),
  change(date(2020, 12, 9), <>Re-enabled stat weights :).</>, Abelito75),
  change(date(2020, 10, 18), <>Updating wording and translation tags.</>, Abelito75),
  change(date(2020, 10, 18), 'Converted legacy listeners to new event filters', Zeboot),
  change(date(2020, 10, 15), <>Removed Light Of Dawn from Crusaders Might statistic box and fixed beacon uptime for glimmer players. </>, Abelito75),
  change(date(2020, 10, 14), <>Added nice graphic for DP to show how lucky or unlucky you were. </>, Abelito75),
  change(date(2020, 10, 13), <>Updated stat weight scaling. </>, Abelito75),
  change(date(2020, 8, 27), <>Updated core Holy Paladin for prepatch. </>, Abelito75),
];
<commit_msg>changy<commit_after>import React from 'react';

import { Abelito75, Zeboot } from 'CONTRIBUTORS';
import { change, date } from 'common/changelog';

export default [
  change(date(2020, 12, 12), <>Add Shock Barrier!</>, Abelito75),
  change(date(2020, 12, 10), <>Fixed a bug that made devo aura inaccurate.</>, Abelito75),
  change(date(2020, 12, 10), <>Fixed bug where Light of the Martyr's ineffiecent tooltip would crash the page.</>, Abelito75),
  change(date(2020, 12, 9), <>Re-enabled stat weights :).</>, Abelito75),
  change(date(2020, 10, 18), <>Updating wording and translation tags.</>, Abelito75),
  change(date(2020, 10, 18), 'Converted legacy listeners to new event filters', Zeboot),
  change(date(2020, 10, 15), <>Removed Light Of Dawn from Crusaders Might statistic box and fixed beacon uptime for glimmer players. </>, Abelito75),
  change(date(2020, 10, 14), <>Added nice graphic for DP to show how lucky or unlucky you were. </>, Abelito75),
  change(date(2020, 10, 13), <>Updated stat weight scaling. </>, Abelito75),
  change(date(2020, 8, 27), <>Updated core Holy Paladin for prepatch. </>, Abelito75),
];
<|endoftext|>


<commit_before>(function($, window, document, undefined) {
/*
 * INSTRUCCIONES:
 * 1. Al principio de cada caso de prueba se explica qué hay que hacer
 * 2. Solo se permite añadir código entre los comentarios "Edit from here" hasta "To here"
 * 3.
 */

/*
 * Imagina que existe un "div" con la id "content", utilizando jQuery:
 * 1. Inserta dentro de este elemento un
 con id "testDiv", con las medidas 100x50px de ancho y con el color de fondo "#cccccc"
 * 2. Dentro del nuevo "testDiv" inserta un
 con cualquier texto
 * 3. Por último inserta un  con otro texto diferente ANTES del
 anterior
 */
function testjQuery(){
	/*
	 * Edit from here
	 */
	var $div = $('
', {
		css: {
			backgroundColor: '#ccc'
		}
	});

	$('#content').append($div);

	$div.append('
Soy un parrafo
');

	$div.prepend('Soy un span');
	/*
	 * To here
	 */
}

/*
 * Ahora haz el mismo ejercicio pero utilizando javascript nativo, nada de jQuery
 */
function testVanilaJS(){
	/*
	 * Edit from here
	 */
	var div = document.createElement("div");
	div.style.backgroundColor = '#cccccc';

	var content = document.getElementById('content');
	content.appendChild(div);

	var p = document.createElement("p");
	p.innerHTML = 'Soy un parrafo';
	div.appendChild(p);

	var span = document.createElement("span");
	span.innerHTML = 'Soy un span';
	div.insertBefore(span, p);
	/*
	 * To here
	 */
}

/*
 * Crea una función "add(n)" que devuelva una función que añada n a un número, ejemplos:
 * 1. add(1) === function
 * 2. add(2)(3) === 5
 * 3. add(5)(3) === 8
 */
/*
 * Edit from here
 */
function add(n){
	return function(m){
		return n + m;
	}
}
/*
 * To here
 */

/*
 * Averigua por qué la miel no está incrementando en la colmena.
 * Para ello corrige las partes que sean necesarias, el código que se ejecutará es:
 * 	1. var theHive = new Hive();
 * 	2. var theBee = new Bee(theHive);
 * 	3. theBee.unloadHoney();
 * En este punto la miel total de la colmena debe ser igual a 111 (100 + 11)
 */
function Hive(){
	this.honey = 100;
}
Hive.prototype.addHoney = function(honey) {
  return this.honey += honey;
};
/*
 * Edit from here
 */
function Bee(hive){
	this.capacity = 11;
	this.hive = hive;
}
Bee.prototype.unloadHoney = function() {
	this.hive.addHoney(this.capacity);
};
/*
 * To here
 */

/*
 * Crea una función "once(function)" que devuelva una función que solo pueda ser llamada una vez, ejemplos:
 * 1. var logOnce = once(console.log);
 * 	  logOnce("foo") // -> "foo"
 *    logOnce("bar") // -> no effect
 *
 * 2. var logOnce = once(alert);
 * 	  logOnce("a") // -> "a"
 *    logOnce("b") // -> no effect
 */
/*
 * Edit from here
 */
function once(fn){
	var callable = true;
	return function(){
		if(callable){
			callable = false;
			return fn.apply(this, arguments);
		}
	}
}
/*
 * To here
 */

window.testjQuery = testjQuery;
window.testVanilaJS = testVanilaJS;
window.Hive = Hive;
window.Bee = Bee;
window.add = add;
window.once = once;

})(jQuery, window, document);<commit_msg>Updated<commit_after>(function($, window, document, undefined) {
/*
 * INSTRUCCIONES:
 * 1. Al principio de cada caso de prueba se explica qué hay que hacer
 * 2. Solo se permite añadir código entre los comentarios "Edit from here" hasta "To here"
 * 3.
 */

/*
 * Imagina que existe un "div" con la id "content", utilizando jQuery:
 * 1. Inserta dentro de este elemento un
 con id "testDiv", con las medidas 100x50px de ancho y con el color de fondo "#cccccc"
 * 2. Dentro del nuevo "testDiv" inserta un
 con cualquier texto
 * 3. Por último inserta un  con otro texto diferente ANTES del
 anterior
 */
function testjQuery(){
	/*
	 * Edit from here
	 */
	var $div = $('
', {
		css: {
			backgroundColor: '#ccc'
		}
	});

	$('#content').append($div);

	$div.append('
Soy un parrafo
');

	$div.prepend('Soy un span');
	/*
	 * To here
	 */
}

/*
 * Ahora haz el mismo ejercicio pero utilizando javascript nativo, nada de jQuery
 */
function testVanilaJS(){
	/*
	 * Edit from here
	 */
	var div = document.createElement("div");
	div.style.backgroundColor = '#cccccc';

	var content = document.getElementById('content');
	content.appendChild(div);

	var p = document.createElement("p");
	p.innerHTML = 'Soy un parrafo';
	div.appendChild(p);

	var span = document.createElement("span");
	span.innerHTML = 'Soy un span';
	div.insertBefore(span, p);
	/*
	 * To here
	 */
}

/*
 * Crea una función "add(n)" que devuelva una función que añada n a un número, ejemplos:
 * 1. add(1) === function
 * 2. add(2)(3) === 5
 * 3. add(5)(3) === 8
 */
function add(n){
	/*
	 * Edit from here
	 */
	return function(m){
		return n + m;
	}
	/*
	 * To here
	 */
}

/*
 * Averigua por qué la miel no está incrementando en la colmena.
 * Para ello corrige las partes que sean necesarias, el código que se ejecutará es:
 * 	1. var theHive = new Hive();
 * 	2. var theBee = new Bee(theHive);
 * 	3. theBee.unloadHoney();
 * En este punto la miel total de la colmena debe ser igual a 111 (100 + 11)
 */
function Hive(){
	this.honey = 100;
}
Hive.prototype.addHoney = function(honey) {
  return this.honey += honey;
};
/*
 * Edit from here
 */
function Bee(hive){
	this.capacity = 11;
	this.hive = hive;
}
Bee.prototype.unloadHoney = function() {
	this.hive.addHoney(this.capacity);
};
/*
 * To here
 */

/*
 * Crea una función "once(function)" que devuelva una función que solo pueda ser llamada una vez, ejemplos:
 * 1. var logOnce = once(console.log);
 * 	  logOnce("foo") // -> "foo"
 *    logOnce("bar") // -> no effect
 *
 * 2. var logOnce = once(alert);
 * 	  logOnce("a") // -> "a"
 *    logOnce("b") // -> no effect
 */
function once(fn){
	/*
	 * Edit from here
	 */
	var callable = true;
	return function(){
		if(callable){
			callable = false;
			return fn.apply(this, arguments);
		}
	}
	/*
	 * To here
	 */
}

window.testjQuery = testjQuery;
window.testVanilaJS = testVanilaJS;
window.Hive = Hive;
window.Bee = Bee;
window.add = add;
window.once = once;

})(jQuery, window, document);<|endoftext|>


<commit_before>/**
* Copyright 2012-2020, 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 Registry = require('../../registry');
var Lib = require('../../lib');

var handleArrayContainerDefaults = require('../array_container_defaults');

var layoutAttributes = require('./layout_attributes');
var handleTickValueDefaults = require('./tick_value_defaults');
var handleTickMarkDefaults = require('./tick_mark_defaults');
var handleTickLabelDefaults = require('./tick_label_defaults');
var handleCategoryOrderDefaults = require('./category_order_defaults');
var handleLineGridDefaults = require('./line_grid_defaults');
var setConvert = require('./set_convert');

var DAY_OF_WEEK = require('./constants').WEEKDAY_PATTERN;
var HOUR = require('./constants').HOUR_PATTERN;

/**
 * options: object containing:
 *
 *  letter: 'x' or 'y'
 *  title: name of the axis (ie 'Colorbar') to go in default title
 *  font: the default font to inherit
 *  outerTicks: boolean, should ticks default to outside?
 *  showGrid: boolean, should gridlines be shown by default?
 *  noHover: boolean, this axis doesn't support hover effects?
 *  noTickson: boolean, this axis doesn't support 'tickson'
 *  data: the plot data, used to manage categories
 *  bgColor: the plot background color, to calculate default gridline colors
 *  calendar:
 *  splomStash:
 *  visibleDflt: boolean
 *  reverseDflt: boolean
 *  automargin: boolean
 */
module.exports = function handleAxisDefaults(containerIn, containerOut, coerce, options, layoutOut) {
    var letter = options.letter;
    var font = options.font || {};
    var splomStash = options.splomStash || {};

    var visible = coerce('visible', !options.visibleDflt);

    var axTemplate = containerOut._template || {};
    var axType = containerOut.type || axTemplate.type || '-';

    if(axType === 'date') {
        var handleCalendarDefaults = Registry.getComponentMethod('calendars', 'handleDefaults');
        handleCalendarDefaults(containerIn, containerOut, 'calendar', options.calendar);
    }

    setConvert(containerOut, layoutOut);

    var autorangeDflt = !containerOut.isValidRange(containerIn.range);
    if(autorangeDflt && options.reverseDflt) autorangeDflt = 'reversed';
    var autoRange = coerce('autorange', autorangeDflt);
    if(autoRange && (axType === 'linear' || axType === '-')) coerce('rangemode');

    coerce('range');
    containerOut.cleanRange();

    handleCategoryOrderDefaults(containerIn, containerOut, coerce, options);

    if(axType !== 'category' && !options.noHover) coerce('hoverformat');

    var dfltColor = coerce('color');
    // if axis.color was provided, use it for fonts too; otherwise,
    // inherit from global font color in case that was provided.
    // Compare to dflt rather than to containerIn, so we can provide color via
    // template too.
    var dfltFontColor = (dfltColor !== layoutAttributes.color.dflt) ? dfltColor : font.color;
    // try to get default title from splom trace, fallback to graph-wide value
    var dfltTitle = splomStash.label || layoutOut._dfltTitle[letter];

    handleTickLabelDefaults(containerIn, containerOut, coerce, axType, options, {pass: 1});
    if(!visible) return containerOut;

    coerce('title.text', dfltTitle);
    Lib.coerceFont(coerce, 'title.font', {
        family: font.family,
        size: Math.round(font.size * 1.2),
        color: dfltFontColor
    });

    handleTickValueDefaults(containerIn, containerOut, coerce, axType);
    handleTickLabelDefaults(containerIn, containerOut, coerce, axType, options, {pass: 2});
    handleTickMarkDefaults(containerIn, containerOut, coerce, options);
    handleLineGridDefaults(containerIn, containerOut, coerce, {
        dfltColor: dfltColor,
        bgColor: options.bgColor,
        showGrid: options.showGrid,
        attributes: layoutAttributes
    });

    if(containerOut.showline || containerOut.ticks) coerce('mirror');

    if(options.automargin) coerce('automargin');

    var isMultiCategory = axType === 'multicategory';

    if(!options.noTickson &&
        (axType === 'category' || isMultiCategory) &&
        (containerOut.ticks || containerOut.showgrid)
    ) {
        var ticksonDflt;
        if(isMultiCategory) ticksonDflt = 'boundaries';
        coerce('tickson', ticksonDflt);
    }

    if(isMultiCategory) {
        var showDividers = coerce('showdividers');
        if(showDividers) {
            coerce('dividercolor');
            coerce('dividerwidth');
        }
    }

    if(axType === 'date') {
        handleArrayContainerDefaults(containerIn, containerOut, {
            name: 'rangebreaks',
            inclusionAttr: 'enabled',
            handleItemDefaults: rangebreaksDefaults
        });

        if(!containerOut.rangebreaks.length) {
            delete containerOut.rangebreaks;
        } else {
            for(var k = 0; k < containerOut.rangebreaks.length; k++) {
                var brk = containerOut.rangebreaks[k];
                if(brk.pattern === DAY_OF_WEEK) {
                    containerOut._hasDayOfWeekBreaks = true;
                }

                if(brk.pattern === HOUR) {
                    containerOut._hasHourBreaks = true;

                    var dayHours = (brk.bounds[1] - brk.bounds[0] + 24) % 24;
                    if(containerOut._dayHours === undefined) {
                        containerOut._dayHours = dayHours;
                    } else {
                        containerOut._dayHours += dayHours;
                    }
                }
            }
            if(containerOut._dayHours !== undefined) {
                containerOut._dayHours = Math.ceil(containerOut._dayHours);
            }

            setConvert(containerOut, layoutOut);

            if(layoutOut._has('scattergl') || layoutOut._has('splom')) {
                for(var i = 0; i < options.data.length; i++) {
                    var trace = options.data[i];
                    if(trace.type === 'scattergl' || trace.type === 'splom') {
                        trace.visible = false;
                        Lib.warn(trace.type +
                            ' traces do not work on axes with rangebreaks.' +
                            ' Setting trace ' + trace.index + ' to `visible: false`.');
                    }
                }
            }
        }
    }

    return containerOut;
};

function rangebreaksDefaults(itemIn, itemOut, containerOut) {
    function coerce(attr, dflt) {
        return Lib.coerce(itemIn, itemOut, layoutAttributes.rangebreaks, attr, dflt);
    }

    var enabled = coerce('enabled');

    if(enabled) {
        var bnds = coerce('bounds');
        if(bnds && bnds.length >= 2) {
            var dfltPattern = '';
            var i, q;
            if(bnds.length === 2) {
                for(i = 0; i < 2; i++) {
                    q = indexOfDay(bnds[i]);
                    if(q) {
                        dfltPattern = DAY_OF_WEEK;
                        break;
                    }
                }
            }
            var pattern = coerce('pattern', dfltPattern);
            if(pattern === DAY_OF_WEEK) {
                for(i = 0; i < 2; i++) {
                    q = indexOfDay(bnds[i]);
                    if(q) {
                        // convert to integers i.e 'Sunday' --> 0
                        itemOut.bounds[i] = bnds[i] = q - 1;
                    }
                }
            }
            if(pattern) {
                // ensure types and ranges
                for(i = 0; i < 2; i++) {
                    q = bnds[i];
                    switch(pattern) {
                        case DAY_OF_WEEK :
                            if(!isNumeric(q)) {
                                itemOut.enabled = false;
                                return;
                            }
                            q = +q;

                            if(
                                q !== Math.floor(q) || // don't accept fractional days for mow
                                q < 0 || q >= 7
                            ) {
                                itemOut.enabled = false;
                                return;
                            }
                            // use number
                            itemOut.bounds[i] = bnds[i] = q;
                            break;

                        case HOUR :
                            if(!isNumeric(q)) {
                                itemOut.enabled = false;
                                return;
                            }
                            q = +q;

                            if(q < 0 || q > 24) { // accept 24
                                itemOut.enabled = false;
                                return;
                            }
                            // use number
                            itemOut.bounds[i] = bnds[i] = q;
                            break;
                    }
                }
            }

            if(containerOut.autorange === false) {
                var rng = containerOut.range;

                // if bounds are bigger than the (set) range, disable break
                if(rng[0] < rng[1]) {
                    if(bnds[0] < rng[0] && bnds[1] > rng[1]) {
                        itemOut.enabled = false;
                        return;
                    }
                } else if(bnds[0] > rng[0] && bnds[1] < rng[1]) {
                    itemOut.enabled = false;
                    return;
                }
            }
        } else {
            var values = coerce('values');

            if(values && values.length) {
                coerce('dvalue');
            } else {
                itemOut.enabled = false;
                return;
            }
        }
    }
}

// these numbers are one more than what bounds would be mapped to
var dayStrToNum = {
    sun: 1,
    mon: 2,
    tue: 3,
    wed: 4,
    thu: 5,
    fri: 6,
    sat: 7
};

function indexOfDay(v) {
    if(typeof v !== 'string') return;
    return dayStrToNum[
        v.substr(0, 3).toLowerCase()
    ];
}
<commit_msg>drop extra logic for dayHours<commit_after>/**
* Copyright 2012-2020, 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 Registry = require('../../registry');
var Lib = require('../../lib');

var handleArrayContainerDefaults = require('../array_container_defaults');

var layoutAttributes = require('./layout_attributes');
var handleTickValueDefaults = require('./tick_value_defaults');
var handleTickMarkDefaults = require('./tick_mark_defaults');
var handleTickLabelDefaults = require('./tick_label_defaults');
var handleCategoryOrderDefaults = require('./category_order_defaults');
var handleLineGridDefaults = require('./line_grid_defaults');
var setConvert = require('./set_convert');

var DAY_OF_WEEK = require('./constants').WEEKDAY_PATTERN;
var HOUR = require('./constants').HOUR_PATTERN;

/**
 * options: object containing:
 *
 *  letter: 'x' or 'y'
 *  title: name of the axis (ie 'Colorbar') to go in default title
 *  font: the default font to inherit
 *  outerTicks: boolean, should ticks default to outside?
 *  showGrid: boolean, should gridlines be shown by default?
 *  noHover: boolean, this axis doesn't support hover effects?
 *  noTickson: boolean, this axis doesn't support 'tickson'
 *  data: the plot data, used to manage categories
 *  bgColor: the plot background color, to calculate default gridline colors
 *  calendar:
 *  splomStash:
 *  visibleDflt: boolean
 *  reverseDflt: boolean
 *  automargin: boolean
 */
module.exports = function handleAxisDefaults(containerIn, containerOut, coerce, options, layoutOut) {
    var letter = options.letter;
    var font = options.font || {};
    var splomStash = options.splomStash || {};

    var visible = coerce('visible', !options.visibleDflt);

    var axTemplate = containerOut._template || {};
    var axType = containerOut.type || axTemplate.type || '-';

    if(axType === 'date') {
        var handleCalendarDefaults = Registry.getComponentMethod('calendars', 'handleDefaults');
        handleCalendarDefaults(containerIn, containerOut, 'calendar', options.calendar);
    }

    setConvert(containerOut, layoutOut);

    var autorangeDflt = !containerOut.isValidRange(containerIn.range);
    if(autorangeDflt && options.reverseDflt) autorangeDflt = 'reversed';
    var autoRange = coerce('autorange', autorangeDflt);
    if(autoRange && (axType === 'linear' || axType === '-')) coerce('rangemode');

    coerce('range');
    containerOut.cleanRange();

    handleCategoryOrderDefaults(containerIn, containerOut, coerce, options);

    if(axType !== 'category' && !options.noHover) coerce('hoverformat');

    var dfltColor = coerce('color');
    // if axis.color was provided, use it for fonts too; otherwise,
    // inherit from global font color in case that was provided.
    // Compare to dflt rather than to containerIn, so we can provide color via
    // template too.
    var dfltFontColor = (dfltColor !== layoutAttributes.color.dflt) ? dfltColor : font.color;
    // try to get default title from splom trace, fallback to graph-wide value
    var dfltTitle = splomStash.label || layoutOut._dfltTitle[letter];

    handleTickLabelDefaults(containerIn, containerOut, coerce, axType, options, {pass: 1});
    if(!visible) return containerOut;

    coerce('title.text', dfltTitle);
    Lib.coerceFont(coerce, 'title.font', {
        family: font.family,
        size: Math.round(font.size * 1.2),
        color: dfltFontColor
    });

    handleTickValueDefaults(containerIn, containerOut, coerce, axType);
    handleTickLabelDefaults(containerIn, containerOut, coerce, axType, options, {pass: 2});
    handleTickMarkDefaults(containerIn, containerOut, coerce, options);
    handleLineGridDefaults(containerIn, containerOut, coerce, {
        dfltColor: dfltColor,
        bgColor: options.bgColor,
        showGrid: options.showGrid,
        attributes: layoutAttributes
    });

    if(containerOut.showline || containerOut.ticks) coerce('mirror');

    if(options.automargin) coerce('automargin');

    var isMultiCategory = axType === 'multicategory';

    if(!options.noTickson &&
        (axType === 'category' || isMultiCategory) &&
        (containerOut.ticks || containerOut.showgrid)
    ) {
        var ticksonDflt;
        if(isMultiCategory) ticksonDflt = 'boundaries';
        coerce('tickson', ticksonDflt);
    }

    if(isMultiCategory) {
        var showDividers = coerce('showdividers');
        if(showDividers) {
            coerce('dividercolor');
            coerce('dividerwidth');
        }
    }

    if(axType === 'date') {
        handleArrayContainerDefaults(containerIn, containerOut, {
            name: 'rangebreaks',
            inclusionAttr: 'enabled',
            handleItemDefaults: rangebreaksDefaults
        });

        if(!containerOut.rangebreaks.length) {
            delete containerOut.rangebreaks;
        } else {
            for(var k = 0; k < containerOut.rangebreaks.length; k++) {
                if(containerOut.rangebreaks[k].pattern === DAY_OF_WEEK) {
                    containerOut._hasDayOfWeekBreaks = true;
                    break;
                }
            }

            setConvert(containerOut, layoutOut);

            if(layoutOut._has('scattergl') || layoutOut._has('splom')) {
                for(var i = 0; i < options.data.length; i++) {
                    var trace = options.data[i];
                    if(trace.type === 'scattergl' || trace.type === 'splom') {
                        trace.visible = false;
                        Lib.warn(trace.type +
                            ' traces do not work on axes with rangebreaks.' +
                            ' Setting trace ' + trace.index + ' to `visible: false`.');
                    }
                }
            }
        }
    }

    return containerOut;
};

function rangebreaksDefaults(itemIn, itemOut, containerOut) {
    function coerce(attr, dflt) {
        return Lib.coerce(itemIn, itemOut, layoutAttributes.rangebreaks, attr, dflt);
    }

    var enabled = coerce('enabled');

    if(enabled) {
        var bnds = coerce('bounds');
        if(bnds && bnds.length >= 2) {
            var dfltPattern = '';
            var i, q;
            if(bnds.length === 2) {
                for(i = 0; i < 2; i++) {
                    q = indexOfDay(bnds[i]);
                    if(q) {
                        dfltPattern = DAY_OF_WEEK;
                        break;
                    }
                }
            }
            var pattern = coerce('pattern', dfltPattern);
            if(pattern === DAY_OF_WEEK) {
                for(i = 0; i < 2; i++) {
                    q = indexOfDay(bnds[i]);
                    if(q) {
                        // convert to integers i.e 'Sunday' --> 0
                        itemOut.bounds[i] = bnds[i] = q - 1;
                    }
                }
            }
            if(pattern) {
                // ensure types and ranges
                for(i = 0; i < 2; i++) {
                    q = bnds[i];
                    switch(pattern) {
                        case DAY_OF_WEEK :
                            if(!isNumeric(q)) {
                                itemOut.enabled = false;
                                return;
                            }
                            q = +q;

                            if(
                                q !== Math.floor(q) || // don't accept fractional days for mow
                                q < 0 || q >= 7
                            ) {
                                itemOut.enabled = false;
                                return;
                            }
                            // use number
                            itemOut.bounds[i] = bnds[i] = q;
                            break;

                        case HOUR :
                            if(!isNumeric(q)) {
                                itemOut.enabled = false;
                                return;
                            }
                            q = +q;

                            if(q < 0 || q > 24) { // accept 24
                                itemOut.enabled = false;
                                return;
                            }
                            // use number
                            itemOut.bounds[i] = bnds[i] = q;
                            break;
                    }
                }
            }

            if(containerOut.autorange === false) {
                var rng = containerOut.range;

                // if bounds are bigger than the (set) range, disable break
                if(rng[0] < rng[1]) {
                    if(bnds[0] < rng[0] && bnds[1] > rng[1]) {
                        itemOut.enabled = false;
                        return;
                    }
                } else if(bnds[0] > rng[0] && bnds[1] < rng[1]) {
                    itemOut.enabled = false;
                    return;
                }
            }
        } else {
            var values = coerce('values');

            if(values && values.length) {
                coerce('dvalue');
            } else {
                itemOut.enabled = false;
                return;
            }
        }
    }
}

// these numbers are one more than what bounds would be mapped to
var dayStrToNum = {
    sun: 1,
    mon: 2,
    tue: 3,
    wed: 4,
    thu: 5,
    fri: 6,
    sat: 7
};

function indexOfDay(v) {
    if(typeof v !== 'string') return;
    return dayStrToNum[
        v.substr(0, 3).toLowerCase()
    ];
}
<|endoftext|>


<commit_before>import {
  escapeEnvQuotes,
  getImagePrefix,
  getNodeVersion,
  runCommand
} from './utils';
import fs from 'fs';

export function prepareBundleSupported(dockerConfig) {
  const supportedImages = ['abernix/meteord', 'zodern/meteor'];

  if ('prepareBundle' in dockerConfig) {
    return dockerConfig.prepareBundle;
  }

  return supportedImages.find(
    supportedImage => dockerConfig.image.indexOf(supportedImage) === 0
  ) || false;
}

export function createDockerFile(appConfig) {
  const {
    env,
    docker: {
      useBuildKit,
      image
    } = {}
  } = appConfig;
  const escapedEnv = escapeEnvQuotes(env);

  const syntax = useBuildKit ? '# syntax=docker/dockerfile:1-experimental' : '';
  const args = Object.entries(escapedEnv).map(([key, value]) => `ARG ${key}="${value}"`).join('\n');
  const copy = useBuildKit ?
    'RUN --mount=type=bind,target=/tmp/__mup-bundle tar -xzf /tmp/__mup-bundle/bundle.tar.gz -C /built_app --strip-components=1' :
    'COPY ./ /built_app';

  return `
    ${syntax}
    FROM ${image}
    RUN mkdir /built_app || true
    ${args}
    # TODO: build instructions
    ${copy}
    RUN cd /built_app/programs/server && \
      npm install --unsafe-perm
  `.trim();
}

export async function prepareBundleLocally(
  buildLocation, api
) {
  const {
    app: appConfig,
    privateDockerRegistry
  } = api.getConfig();
  const startTime = new Date();

  if (!appConfig.docker.useBuildKit) {
    const error = new Error('useBuildKit must be enabled when using prepareBundleLocally');
    error.solution = 'Set app.docker.useBuildKit to true in your config.';
    throw error;
  }

  const nodeVersion = getNodeVersion(api, buildLocation);
  const image = `${getImagePrefix(privateDockerRegistry)}${appConfig.name}`;
  const dockerFile = createDockerFile(appConfig);
  const dockerIgnoreContent = `
  *
  !bundle.tar.gz
  `;

  console.log('=> Writing Dockerfile');
  fs.writeFileSync(api.resolvePath(buildLocation, 'Dockerfile'), dockerFile);
  fs.writeFileSync(api.resolvePath(buildLocation, 'dockerignore'), dockerIgnoreContent);

  console.log('');
  console.log('=> Updating base image');
  await runCommand('docker', ['login', '--password-stdin', '--username', privateDockerRegistry.username, privateDockerRegistry.host], { stdin: privateDockerRegistry.password });
  await runCommand('docker', ['pull', appConfig.docker.image]);

  console.log('');
  console.log('=> Build image');

  if (appConfig.docker.useBuildKit) {
    process.env.DOCKER_BUILDKIT = '1';
  }

  await runCommand('docker', [
    'build',
    '-t', `${image}:build`,
    '.',
    '--build-arg', `NODE_VERSION=${nodeVersion}`
  ], { cwd: buildLocation });

  console.log('');
  console.log('=> Updating tags');

  // Pull latest image so we can tag is as previous
  // TODO: use docker registry api instead
  await runCommand('docker', ['pull', `${image}:latest`]);
  await runCommand('docker', [
    'tag',
    `${image}:latest`,
    `${image}:previous`
  ]);
  await runCommand('docker', [
    'tag',
    `${image}:build`,
    `${image}:latest`
  ]);
  await runCommand('docker', [
    'push',
    `${image}:previous`
  ]);
  await runCommand('docker', [
    'push',
    `${image}:latest`
  ]);

  const endTime = new Date();
  const durationText = `in ${endTime.getTime() - startTime.getTime()}ms`;

  console.log('=> Finished preparing bundle', durationText);
}
<commit_msg>Fix node version when building image locally<commit_after>import {
  escapeEnvQuotes,
  getImagePrefix,
  getNodeVersion,
  runCommand
} from './utils';
import fs from 'fs';

export function prepareBundleSupported(dockerConfig) {
  const supportedImages = ['abernix/meteord', 'zodern/meteor'];

  if ('prepareBundle' in dockerConfig) {
    return dockerConfig.prepareBundle;
  }

  return supportedImages.find(
    supportedImage => dockerConfig.image.indexOf(supportedImage) === 0
  ) || false;
}

export function createDockerFile(appConfig) {
  const {
    env,
    docker: {
      useBuildKit,
      image
    } = {}
  } = appConfig;
  const escapedEnv = escapeEnvQuotes(env);

  const syntax = useBuildKit ? '# syntax=docker/dockerfile:1-experimental' : '';
  const args = Object.entries(escapedEnv).map(([key, value]) => `ARG ${key}="${value}"`).join('\n');
  const copy = useBuildKit ?
    'RUN --mount=type=bind,target=/tmp/__mup-bundle tar -xzf /tmp/__mup-bundle/bundle.tar.gz -C /built_app --strip-components=1' :
    'COPY ./ /built_app';

  return `
    ${syntax}
    FROM ${image}
    RUN mkdir /built_app || true
    ${args}
    # TODO: build instructions
    ${copy}
    RUN cd /built_app/programs/server && \
      npm install --unsafe-perm
  `.trim();
}

export async function prepareBundleLocally(
  buildLocation, api
) {
  const {
    app: appConfig,
    privateDockerRegistry
  } = api.getConfig();
  const startTime = new Date();

  if (!appConfig.docker.useBuildKit) {
    const error = new Error('useBuildKit must be enabled when using prepareBundleLocally');
    error.solution = 'Set app.docker.useBuildKit to true in your config.';
    throw error;
  }

  const nodeVersion = await getNodeVersion(api, buildLocation);
  const image = `${getImagePrefix(privateDockerRegistry)}${appConfig.name}`;
  const dockerFile = createDockerFile(appConfig);
  const dockerIgnoreContent = `
  *
  !bundle.tar.gz
  `;

  console.log('=> Writing Dockerfile');
  fs.writeFileSync(api.resolvePath(buildLocation, 'Dockerfile'), dockerFile);
  fs.writeFileSync(api.resolvePath(buildLocation, 'dockerignore'), dockerIgnoreContent);

  console.log('');
  console.log('=> Updating base image');
  await runCommand('docker', ['login', '--password-stdin', '--username', privateDockerRegistry.username, privateDockerRegistry.host], { stdin: privateDockerRegistry.password });
  await runCommand('docker', ['pull', appConfig.docker.image]);

  console.log('');
  console.log('=> Build image');

  if (appConfig.docker.useBuildKit) {
    process.env.DOCKER_BUILDKIT = '1';
  }

  await runCommand('docker', [
    'build',
    '-t', `${image}:build`,
    '.',
    '--build-arg', `NODE_VERSION=${nodeVersion}`
  ], { cwd: buildLocation });

  console.log('');
  console.log('=> Updating tags');

  // Pull latest image so we can tag is as previous
  // TODO: use docker registry api instead
  await runCommand('docker', ['pull', `${image}:latest`]);
  await runCommand('docker', [
    'tag',
    `${image}:latest`,
    `${image}:previous`
  ]);
  await runCommand('docker', [
    'tag',
    `${image}:build`,
    `${image}:latest`
  ]);
  await runCommand('docker', [
    'push',
    `${image}:previous`
  ]);
  await runCommand('docker', [
    'push',
    `${image}:latest`
  ]);

  const endTime = new Date();
  const durationText = `in ${endTime.getTime() - startTime.getTime()}ms`;

  console.log('=> Finished preparing bundle', durationText);
}
<|endoftext|>