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

const expect = require('chai').expect;
const os = require('os');

const RC = require('../RC');
const { Client } = require('../../');
const { BuildInfo } = require('../../lib/BuildInfo');
const { Statistics } = require("../../lib/statistics/Statistics");
const TestUtil = require('../Util');

function getClientStatisticsFromServer(cluster, client) {
    const clientUuid = client.getConnectionManager().getClientUuid();
    const script =
        'stats = instance_0.getOriginal().node.getClientEngine().getClientStatistics()\n' +
        'keys = stats.keySet().toArray()\n' +
        'for(i=0; i < keys.length; i++) {\n' +
        '  if (keys[i].toString().equals("'+ clientUuid + '")) {\n' +
        '    result = stats.get(keys[i]).clientAttributes()\n' +
        '    break\n' +
        '  }\n' +
        '}\n';
    return RC.executeOnController(cluster.id, script, 1).then(function (response) {
        if (response.result != null) {
            return response.result.toString();
        }
        return null;
    });
}

function extractStringStatValue(stats, statName) {
    const re = new RegExp(statName + '=(.*?)(?:,|$)');
    const matches = stats.match(re);
    return matches[1];
}

function extractFloatStatValue(stats, statName) {
    return Number.parseFloat(extractStringStatValue(stats, statName));
}

function extractBooleanStatValue(stats, statName) {
    return 'true' === extractStringStatValue(stats, statName);
}

function extractIntStatValue(stats, statName) {
    return Number.parseInt(extractStringStatValue(stats, statName));
}

describe('StatisticsTest (default period)', function () {

    let cluster;
    let client;
    let map;

    before(function () {
        return RC.createCluster(null, null).then(function (res) {
            cluster = res;
        }).then(function () {
            return RC.startMember(cluster.id);
        }).then(function () {
            return Client.newHazelcastClient({
                clusterName: cluster.id,
                nearCaches: {
                    'nearCachedMap*': {
                        invalidateOnChange: false
                    }
                },
                properties: {
                    'hazelcast.client.statistics.enabled': true
                }
            }).then(function (cl) {
                client = cl;
            })
        });
    });

    after(function () {
        return client.shutdown()
            .then(() => RC.terminateCluster(cluster.id));
    });

    beforeEach(function () {
        return client.getMap('nearCachedMap' + Math.random()).then(function (mp) {
            map = mp;
        });
    });

    afterEach(function () {
        return map.destroy();
    });

    function contains(base, search) {
        const firstIndex = base.indexOf(search);
        return firstIndex > -1 && firstIndex == base.lastIndexOf(search);
    }

    it('should be enabled via configuration', function () {
        return TestUtil.promiseWaitMilliseconds(1000).then(function () {
            return getClientStatisticsFromServer(cluster, client);
        }).then(function (stats) {
            expect(stats).to.not.null;
            expect(stats).to.not.equal('');
        });
    });

    it('should contain statistics content', function () {
        return TestUtil.promiseWaitMilliseconds(1000).then(function () {
            return getClientStatisticsFromServer(cluster, client);
        }).then(function (stats) {
            expect(stats).to.not.be.null;
            expect(extractStringStatValue(stats, 'clientName')).to.equal(client.getName());
            expect(extractIntStatValue(stats, 'lastStatisticsCollectionTime')).to.be
                .within(Date.now() - Statistics.PERIOD_SECONDS_DEFAULT_VALUE * 2000, Date.now());
            expect(extractBooleanStatValue(stats, 'enterprise')).to.be.false;
            expect(extractStringStatValue(stats, 'clientType')).to.equal('NodeJS');
            expect(extractStringStatValue(stats, 'clientVersion')).to.equal(BuildInfo.getClientVersion());
            const connection = client.getConnectionManager().getRandomConnection();
            expect(extractIntStatValue(stats, 'clusterConnectionTimestamp')).to.equal(connection.getStartTime());
            expect(extractStringStatValue(stats, 'clientAddress')).to.equal(connection.getLocalAddress().toString());
            expect(extractStringStatValue(stats, 'os.committedVirtualMemorySize')).to.equal('');
            expect(extractStringStatValue(stats, 'os.freeSwapSpaceSize')).to.equal('');
            expect(extractStringStatValue(stats, 'os.maxFileDescriptorCount')).to.equal('');
            expect(extractStringStatValue(stats, 'os.openFileDescriptorCount')).to.equal('');
            expect(extractIntStatValue(stats, 'os.processCpuTime')).to.greaterThan(1000);
            expect(extractFloatStatValue(stats, 'os.systemLoadAverage')).to.be.greaterThan(0);
            expect(extractIntStatValue(stats, 'os.totalPhysicalMemorySize')).to.equal(os.totalmem());
            expect(extractStringStatValue(stats, 'os.totalSwapSpaceSize')).to.equal('');
            expect(extractIntStatValue(stats, 'runtime.availableProcessors')).to.equal(os.cpus().length);
            expect(extractStringStatValue(stats, 'runtime.freeMemory')).to.equal('');
            expect(extractStringStatValue(stats, 'runtime.maxMemory')).to.equal('');
            expect(extractIntStatValue(stats, 'runtime.totalMemory')).to.greaterThan(0);
            expect(extractIntStatValue(stats, 'runtime.uptime')).to.greaterThan(0);
            expect(extractIntStatValue(stats, 'runtime.usedMemory')).to.greaterThan(0);
            expect(extractStringStatValue(stats, 'executionService.userExecutorQueueSize')).to.equal('');
        });
    });

    it('should contain near cache statistics content', function () {
        return map.put('key', 'value').then(function () {
            return map.get('key');
        }).then(function () {
            return map.get('key');
        }).then(function () {
            return TestUtil.promiseWaitMilliseconds(5000);
        }).then(function () {
            return getClientStatisticsFromServer(cluster, client);
        }).then(function (stats) {
            const nearCacheStats = 'nc.' + map.getName();
            expect(contains(stats, nearCacheStats + '.hits=1')).to.be.true;
            expect(contains(stats, nearCacheStats + '.creationTime=')).to.be.true;
            expect(contains(stats, nearCacheStats + '.misses=1')).to.be.true;
            expect(contains(stats, nearCacheStats + '.ownedEntryCount=1')).to.be.true;
        });
    });
});

describe('StatisticsTest (non-default period)', function () {

    let cluster;
    let client;

    before(function () {
        return RC.createCluster(null, null).then(function (res) {
            cluster = res;
        }).then(function () {
            return RC.startMember(cluster.id);
        }).then(function () {
            return Client.newHazelcastClient({
                clusterName: cluster.id,
                properties: {
                    'hazelcast.client.statistics.enabled': true,
                    'hazelcast.client.statistics.period.seconds': 2
                }
            }).then(function (cl) {
                client = cl;
            });
        });
    });

    after(function () {
        return client.shutdown()
            .then(() => RC.terminateCluster(cluster.id));
    });

    it('should not change before period', function () {
        let stats1;
        return TestUtil.promiseWaitMilliseconds(1000).then(function () {
            return getClientStatisticsFromServer(cluster, client);
        }).then(function (st) {
            stats1 = st;
            return getClientStatisticsFromServer(cluster, client)
        }).then(function (stats2) {
            expect(stats1).to.be.equal(stats2);
        });
    });

    it('should change after period', function () {
        let stats1;
        return TestUtil.promiseWaitMilliseconds(1000).then(function () {
            return getClientStatisticsFromServer(cluster, client);
        }).then(function (st) {
            stats1 = st;
            return TestUtil.promiseWaitMilliseconds(2000)
        }).then(function () {
            return getClientStatisticsFromServer(cluster, client);
        }).then(function (stats2) {
            expect(stats1).not.to.be.equal(stats2);
        });
    });
});

describe('StatisticsTest (negative period)', function () {

    let client;
    let cluster;

    before(function () {
        return RC.createCluster(null, null).then(function (res) {
            cluster = res;
        }).then(function () {
            return RC.startMember(cluster.id);
        }).then(function () {
            return Client.newHazelcastClient({
                clusterName: cluster.id,
                properties: {
                    'hazelcast.client.statistics.enabled': true,
                    'hazelcast.client.statistics.period.seconds': -2
                }
            });
        }).then(function (cl) {
            client = cl;
        });
    });

    after(function () {
        return client.shutdown()
            .then(() => RC.terminateCluster(cluster.id));
    });

    it('should be enabled via configuration', function () {
        return TestUtil.promiseWaitMilliseconds(1000).then(function () {
            return getClientStatisticsFromServer(cluster, client);
        }).then(function (stats) {
            expect(stats).to.not.equal('');
        });
    });
});
<commit_msg>Fix StatisticsTest on windows (#597)<commit_after>/*
 * Copyright (c) 2008-2020, Hazelcast, Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

const expect = require('chai').expect;
const os = require('os');

const RC = require('../RC');
const { Client } = require('../../');
const { BuildInfo } = require('../../lib/BuildInfo');
const { Statistics } = require("../../lib/statistics/Statistics");
const TestUtil = require('../Util');

function getClientStatisticsFromServer(cluster, client) {
    const clientUuid = client.getConnectionManager().getClientUuid();
    const script =
        'stats = instance_0.getOriginal().node.getClientEngine().getClientStatistics()\n' +
        'keys = stats.keySet().toArray()\n' +
        'for(i=0; i < keys.length; i++) {\n' +
        '  if (keys[i].toString().equals("'+ clientUuid + '")) {\n' +
        '    result = stats.get(keys[i]).clientAttributes()\n' +
        '    break\n' +
        '  }\n' +
        '}\n';
    return RC.executeOnController(cluster.id, script, 1).then(function (response) {
        if (response.result != null) {
            return response.result.toString();
        }
        return null;
    });
}

function extractStringStatValue(stats, statName) {
    const re = new RegExp(statName + '=(.*?)(?:,|$)');
    const matches = stats.match(re);
    return matches[1];
}

function extractFloatStatValue(stats, statName) {
    return Number.parseFloat(extractStringStatValue(stats, statName));
}

function extractBooleanStatValue(stats, statName) {
    return 'true' === extractStringStatValue(stats, statName);
}

function extractIntStatValue(stats, statName) {
    return Number.parseInt(extractStringStatValue(stats, statName));
}

describe('StatisticsTest (default period)', function () {

    let cluster;
    let client;
    let map;

    before(function () {
        return RC.createCluster(null, null).then(function (res) {
            cluster = res;
        }).then(function () {
            return RC.startMember(cluster.id);
        }).then(function () {
            return Client.newHazelcastClient({
                clusterName: cluster.id,
                nearCaches: {
                    'nearCachedMap*': {
                        invalidateOnChange: false
                    }
                },
                properties: {
                    'hazelcast.client.statistics.enabled': true
                }
            }).then(function (cl) {
                client = cl;
            })
        });
    });

    after(function () {
        return client.shutdown()
            .then(() => RC.terminateCluster(cluster.id));
    });

    beforeEach(function () {
        return client.getMap('nearCachedMap' + Math.random()).then(function (mp) {
            map = mp;
        });
    });

    afterEach(function () {
        return map.destroy();
    });

    function contains(base, search) {
        const firstIndex = base.indexOf(search);
        return firstIndex > -1 && firstIndex == base.lastIndexOf(search);
    }

    it('should be enabled via configuration', function () {
        return TestUtil.promiseWaitMilliseconds(1000).then(function () {
            return getClientStatisticsFromServer(cluster, client);
        }).then(function (stats) {
            expect(stats).to.not.null;
            expect(stats).to.not.equal('');
        });
    });

    it('should contain statistics content', function () {
        return TestUtil.promiseWaitMilliseconds(1000).then(function () {
            return getClientStatisticsFromServer(cluster, client);
        }).then(function (stats) {
            expect(stats).to.not.be.null;
            expect(extractStringStatValue(stats, 'clientName')).to.equal(client.getName());
            expect(extractIntStatValue(stats, 'lastStatisticsCollectionTime')).to.be
                .within(Date.now() - Statistics.PERIOD_SECONDS_DEFAULT_VALUE * 2000, Date.now());
            expect(extractBooleanStatValue(stats, 'enterprise')).to.be.false;
            expect(extractStringStatValue(stats, 'clientType')).to.equal('NodeJS');
            expect(extractStringStatValue(stats, 'clientVersion')).to.equal(BuildInfo.getClientVersion());
            const connection = client.getConnectionManager().getRandomConnection();
            expect(extractIntStatValue(stats, 'clusterConnectionTimestamp')).to.equal(connection.getStartTime());
            expect(extractStringStatValue(stats, 'clientAddress')).to.equal(connection.getLocalAddress().toString());
            expect(extractStringStatValue(stats, 'os.committedVirtualMemorySize')).to.equal('');
            expect(extractStringStatValue(stats, 'os.freeSwapSpaceSize')).to.equal('');
            expect(extractStringStatValue(stats, 'os.maxFileDescriptorCount')).to.equal('');
            expect(extractStringStatValue(stats, 'os.openFileDescriptorCount')).to.equal('');
            expect(extractIntStatValue(stats, 'os.processCpuTime')).to.greaterThan(1000);
            expect(extractFloatStatValue(stats, 'os.systemLoadAverage')).to.be.at.least(0);
            expect(extractIntStatValue(stats, 'os.totalPhysicalMemorySize')).to.equal(os.totalmem());
            expect(extractStringStatValue(stats, 'os.totalSwapSpaceSize')).to.equal('');
            expect(extractIntStatValue(stats, 'runtime.availableProcessors')).to.equal(os.cpus().length);
            expect(extractStringStatValue(stats, 'runtime.freeMemory')).to.equal('');
            expect(extractStringStatValue(stats, 'runtime.maxMemory')).to.equal('');
            expect(extractIntStatValue(stats, 'runtime.totalMemory')).to.greaterThan(0);
            expect(extractIntStatValue(stats, 'runtime.uptime')).to.greaterThan(0);
            expect(extractIntStatValue(stats, 'runtime.usedMemory')).to.greaterThan(0);
            expect(extractStringStatValue(stats, 'executionService.userExecutorQueueSize')).to.equal('');
        });
    });

    it('should contain near cache statistics content', function () {
        return map.put('key', 'value').then(function () {
            return map.get('key');
        }).then(function () {
            return map.get('key');
        }).then(function () {
            return TestUtil.promiseWaitMilliseconds(5000);
        }).then(function () {
            return getClientStatisticsFromServer(cluster, client);
        }).then(function (stats) {
            const nearCacheStats = 'nc.' + map.getName();
            expect(contains(stats, nearCacheStats + '.hits=1')).to.be.true;
            expect(contains(stats, nearCacheStats + '.creationTime=')).to.be.true;
            expect(contains(stats, nearCacheStats + '.misses=1')).to.be.true;
            expect(contains(stats, nearCacheStats + '.ownedEntryCount=1')).to.be.true;
        });
    });
});

describe('StatisticsTest (non-default period)', function () {

    let cluster;
    let client;

    before(function () {
        return RC.createCluster(null, null).then(function (res) {
            cluster = res;
        }).then(function () {
            return RC.startMember(cluster.id);
        }).then(function () {
            return Client.newHazelcastClient({
                clusterName: cluster.id,
                properties: {
                    'hazelcast.client.statistics.enabled': true,
                    'hazelcast.client.statistics.period.seconds': 2
                }
            }).then(function (cl) {
                client = cl;
            });
        });
    });

    after(function () {
        return client.shutdown()
            .then(() => RC.terminateCluster(cluster.id));
    });

    it('should not change before period', function () {
        let stats1;
        return TestUtil.promiseWaitMilliseconds(1000).then(function () {
            return getClientStatisticsFromServer(cluster, client);
        }).then(function (st) {
            stats1 = st;
            return getClientStatisticsFromServer(cluster, client)
        }).then(function (stats2) {
            expect(stats1).to.be.equal(stats2);
        });
    });

    it('should change after period', function () {
        let stats1;
        return TestUtil.promiseWaitMilliseconds(1000).then(function () {
            return getClientStatisticsFromServer(cluster, client);
        }).then(function (st) {
            stats1 = st;
            return TestUtil.promiseWaitMilliseconds(2000)
        }).then(function () {
            return getClientStatisticsFromServer(cluster, client);
        }).then(function (stats2) {
            expect(stats1).not.to.be.equal(stats2);
        });
    });
});

describe('StatisticsTest (negative period)', function () {

    let client;
    let cluster;

    before(function () {
        return RC.createCluster(null, null).then(function (res) {
            cluster = res;
        }).then(function () {
            return RC.startMember(cluster.id);
        }).then(function () {
            return Client.newHazelcastClient({
                clusterName: cluster.id,
                properties: {
                    'hazelcast.client.statistics.enabled': true,
                    'hazelcast.client.statistics.period.seconds': -2
                }
            });
        }).then(function (cl) {
            client = cl;
        });
    });

    after(function () {
        return client.shutdown()
            .then(() => RC.terminateCluster(cluster.id));
    });

    it('should be enabled via configuration', function () {
        return TestUtil.promiseWaitMilliseconds(1000).then(function () {
            return getClientStatisticsFromServer(cluster, client);
        }).then(function (stats) {
            expect(stats).to.not.equal('');
        });
    });
});
<|endoftext|>


<commit_before>/**
 * @module echarts/chart/helper/LineDraw
 */

import * as graphic from '../../util/graphic';
import LineGroup from './Line';
import Polyline from './Polyline';
import IncrementalDisplayable from 'zrender/src/graphic/IncrementalDisplayable';

/**
 * @alias module:echarts/component/marker/LineDraw
 * @constructor
 */
function LineDraw(ctor) {
    this._ctor = ctor || LineGroup;

    // ??? The third mode: largeLineDraw?
    this._incremental;

    this.group = new graphic.Group();
}

var lineDrawProto = LineDraw.prototype;

/**
 * @param {module:echarts/data/List} lineData
 */
lineDrawProto.updateData = function (lineData) {
    var lineDraw = this;
    var group = lineDraw.group;

    var oldLineData = lineDraw._lineData;
    lineDraw._lineData = lineData;

    var seriesScope = makeSeriesScope(lineData);

    // Check and change mode.
    var streamRendering = seriesScope.streamRendering;
    if (this._incremental ^ streamRendering) {
        this.remove();
        streamRendering && group.add(lineDraw._incremental = new IncrementalDisplayable());
    }

    // ??? Process that switch from stream to non-stream.
    if (streamRendering) {
        this._incremental.clearDisplaybles();
    }
    else {
        lineData.diff(oldLineData)
            .add(function (idx) {
                doAdd(lineDraw, lineData, idx, seriesScope);
            })
            .update(function (newIdx, oldIdx) {
                doUpdate(lineDraw, oldLineData, lineData, oldIdx, newIdx, seriesScope);
            })
            .remove(function (idx) {
                group.remove(oldLineData.getItemGraphicEl(idx));
            })
            .execute();
    }

    // ??? set task start index.
    createRenderTask(lineDraw, lineData, seriesScope);
};

// ??? remove?
// lineDrawProto.updateLayout = function () {
//     var lineData = this._lineData;
//     lineData.eachItemGraphicEl(function (el, idx) {
//         el.updateLayout(lineData, idx);
//     }, this);
// };

lineDrawProto.updateView = function () {
    var lineData = this._lineData;
    var lineDraw = this;
    var seriesScope = makeSeriesScope(lineData);

    if (seriesScope.streamRendering) {
        this._incremental.clearDisplaybles();
    }
    else {
        lineData.each(function (item, idx) {
            doUpdate(lineDraw, lineData, lineData, idx, idx, seriesScope);
        });
    }

    // ??? set task start index.
    createRenderTask(lineDraw, lineData, seriesScope);
};

function doAdd(lineDraw, lineData, idx, seriesScope) {
    if (!lineNeedsDraw(lineData.getItemLayout(idx))) {
        return;
    }
    var itemEl = createItemEl(lineDraw, lineData, idx, seriesScope);

    lineData.setItemGraphicEl(idx, itemEl);

    seriesScope.streamRendering
        ? lineDraw._incremental.addDisplayable(itemEl, true)
        : lineDraw.group.add(itemEl);
}

function doUpdate(lineDraw, oldLineData, newLineData, oldIdx, newIdx, seriesScope) {
    var itemEl = oldLineData.getItemGraphicEl(oldIdx);
    if (!lineNeedsDraw(newLineData.getItemLayout(newIdx))) {
        lineDraw.group.remove(itemEl);
        return;
    }

    if (!itemEl) {
        itemEl = createItemEl(lineDraw, newLineData, newIdx, seriesScope);
    }
    else {
        itemEl.updateData(newLineData, newIdx, seriesScope);
    }

    newLineData.setItemGraphicEl(newIdx, itemEl);

    lineDraw.group.add(itemEl);
}

function createRenderTask(lineDraw, lineData, seriesScope) {
    var hostModel = lineData.hostModel;
    hostModel.pipeTask && hostModel.pipeTask(lineData.createEachTask(function (idx) {
        doAdd(lineDraw, lineData, idx, seriesScope);
    }), 'render');
}

// ??? Modify Polyline, Line.js to support IncrementalDisplable?
function createItemEl(lineDraw, newLineData, newIdx, seriesScope) {
    if (seriesScope.streamRendering) {
        var el = new Polyline(newLineData, newIdx, seriesScope);
        return el.childAt(0);
    }
    else {
        return new lineDraw._ctor(newLineData, newIdx, seriesScope);
    }
}

function makeSeriesScope(lineData) {
    var hostModel = lineData.hostModel;
    var streamSetting = hostModel.getStreamSetting();
    return {
        lineStyle: hostModel.getModel('lineStyle.normal').getLineStyle(),
        hoverLineStyle: hostModel.getModel('lineStyle.emphasis').getLineStyle(),
        labelModel: hostModel.getModel('label.normal'),
        hoverLabelModel: hostModel.getModel('label.emphasis'),
        streamRendering: streamSetting && streamSetting.threshold < lineData.count()
    };
}

lineDrawProto.remove = function () {
    this._incremental && this._incremental.clearDisplaybles();
    this._incremental = null;
    this.group.removeAll();
};

function isPointNaN(pt) {
    return isNaN(pt[0]) || isNaN(pt[1]);
}

function lineNeedsDraw(pts) {
    return !isPointNaN(pts[0]) && !isPointNaN(pts[1]);
}

export default LineDraw;
<commit_msg>tweak<commit_after>/**
 * @module echarts/chart/helper/LineDraw
 */

import * as graphic from '../../util/graphic';
import LineGroup from './Line';
import Polyline from './Polyline';
import IncrementalDisplayable from 'zrender/src/graphic/IncrementalDisplayable';

/**
 * @alias module:echarts/component/marker/LineDraw
 * @constructor
 */
function LineDraw(ctor) {
    this._ctor = ctor || LineGroup;

    // ??? The third mode: largeLineDraw?
    this._incremental;

    this.group = new graphic.Group();
}

var lineDrawProto = LineDraw.prototype;

/**
 * @param {module:echarts/data/List} lineData
 */
lineDrawProto.updateData = function (lineData) {
    var lineDraw = this;
    var group = lineDraw.group;

    var oldLineData = lineDraw._lineData;
    lineDraw._lineData = lineData;

    var seriesScope = makeSeriesScope(lineData);

    // Check and change mode.
    var streamRendering = seriesScope.streamRendering;
    if (this._incremental ^ streamRendering) {
        this.remove();
        streamRendering && group.add(lineDraw._incremental = new IncrementalDisplayable());
    }

    // ??? Process that switch from stream to non-stream.
    if (streamRendering) {
        this._incremental.clearDisplaybles();
    }
    else {
        lineData.diff(oldLineData)
            .add(function (idx) {
                doAdd(lineDraw, lineData, idx, seriesScope);
            })
            .update(function (newIdx, oldIdx) {
                doUpdate(lineDraw, oldLineData, lineData, oldIdx, newIdx, seriesScope);
            })
            .remove(function (idx) {
                group.remove(oldLineData.getItemGraphicEl(idx));
            })
            .execute();
    }

    // ??? set task start index.
    createRenderTask(lineDraw, lineData, seriesScope);
};

// ??? remove?
// lineDrawProto.updateLayout = function () {
//     var lineData = this._lineData;
//     lineData.eachItemGraphicEl(function (el, idx) {
//         el.updateLayout(lineData, idx);
//     }, this);
// };

lineDrawProto.updateView = function () {
    var lineData = this._lineData;
    var lineDraw = this;
    var seriesScope = makeSeriesScope(lineData);

    if (seriesScope.streamRendering) {
        this._incremental.clearDisplaybles();
    }
    else {
        lineData.each(function (item, idx) {
            doUpdate(lineDraw, lineData, lineData, idx, idx, seriesScope);
        });
    }

    // ??? set task start index.
    createRenderTask(lineDraw, lineData, seriesScope);
};

function doAdd(lineDraw, lineData, idx, seriesScope) {
    if (!lineNeedsDraw(lineData.getItemLayout(idx))) {
        return;
    }
    var itemEl = createItemEl(lineDraw, lineData, idx, seriesScope);

    if (seriesScope.streamRendering) {
        lineDraw._incremental.addDisplayable(itemEl, true)
    }
    else {
        lineData.setItemGraphicEl(idx, itemEl);
        lineDraw.group.add(itemEl);
    }
}

function doUpdate(lineDraw, oldLineData, newLineData, oldIdx, newIdx, seriesScope) {
    var itemEl = oldLineData.getItemGraphicEl(oldIdx);
    if (!lineNeedsDraw(newLineData.getItemLayout(newIdx))) {
        lineDraw.group.remove(itemEl);
        return;
    }

    if (!itemEl) {
        itemEl = createItemEl(lineDraw, newLineData, newIdx, seriesScope);
    }
    else {
        itemEl.updateData(newLineData, newIdx, seriesScope);
    }

    newLineData.setItemGraphicEl(newIdx, itemEl);

    lineDraw.group.add(itemEl);
}

function createRenderTask(lineDraw, lineData, seriesScope) {
    var hostModel = lineData.hostModel;
    hostModel.pipeTask && hostModel.pipeTask(lineData.createEachTask(function (idx) {
        doAdd(lineDraw, lineData, idx, seriesScope);
    }), 'render');
}

// ??? Modify Polyline, Line.js to support IncrementalDisplable?
function createItemEl(lineDraw, newLineData, newIdx, seriesScope) {
    if (seriesScope.streamRendering) {
        var el = new Polyline(newLineData, newIdx, seriesScope);
        return el.childAt(0);
    }
    else {
        return new lineDraw._ctor(newLineData, newIdx, seriesScope);
    }
}

function makeSeriesScope(lineData) {
    var hostModel = lineData.hostModel;
    var streamSetting = hostModel.getStreamSetting();
    return {
        lineStyle: hostModel.getModel('lineStyle.normal').getLineStyle(),
        hoverLineStyle: hostModel.getModel('lineStyle.emphasis').getLineStyle(),
        labelModel: hostModel.getModel('label.normal'),
        hoverLabelModel: hostModel.getModel('label.emphasis'),
        streamRendering: streamSetting && streamSetting.threshold < lineData.count()
    };
}

lineDrawProto.remove = function () {
    this._incremental && this._incremental.clearDisplaybles();
    this._incremental = null;
    this.group.removeAll();
};

function isPointNaN(pt) {
    return isNaN(pt[0]) || isNaN(pt[1]);
}

function lineNeedsDraw(pts) {
    return !isPointNaN(pts[0]) && !isPointNaN(pts[1]);
}

export default LineDraw;
<|endoftext|>


<commit_before>'use strict';

timing_test(function() {
  var firstPolyfillRect = document.getElementById('firstPolyfillRect');
  var firstNativeRect = document.getElementById('firstNativeRect');
  var secondPolyfillRect = document.getElementById('secondPolyfillRect');
  var secondNativeRect = document.getElementById('secondNativeRect');
  var thirdPolyfillRect = document.getElementById('thirdPolyfillRect');
  var thirdNativeRect = document.getElementById('thirdNativeRect');
  var fourthPolyfillRect = document.getElementById('fourthPolyfillRect');
  var fourthNativeRect = document.getElementById('fourthNativeRect');
  var fifthPolyfillRect = document.getElementById('fifthPolyfillRect');
  var fifthNativeRect = document.getElementById('fifthNativeRect');

  at(1000, 'width', 200, firstPolyfillRect, firstNativeRect);
  at(2000, 'width', 100, firstPolyfillRect, firstNativeRect);
  at(3000, 'width', 200, secondPolyfillRect, secondNativeRect);
  at(4000, 'width', 100, secondPolyfillRect, secondNativeRect);
  at(5000, 'width', 200, thirdPolyfillRect, thirdNativeRect);
  at(6000, 'width', 100, thirdPolyfillRect, thirdNativeRect);
  at(7000, 'width', 200, fourthPolyfillRect, fourthNativeRect);
  at(8000, 'width', 100, fourthPolyfillRect, fourthNativeRect);
  at(9000, 'width', 200, fifthPolyfillRect, fifthNativeRect);
  at(10000, 'width', 100, fifthPolyfillRect, fifthNativeRect);
  at(11000, 'width', 200, firstPolyfillRect, firstNativeRect);
  at(12000, 'width', 100, firstPolyfillRect, firstNativeRect);
  at(13000, 'width', 200, secondPolyfillRect, secondNativeRect);
  at(14000, 'width', 100, secondPolyfillRect, secondNativeRect);
  at(15000, 'width', 200, thirdPolyfillRect, thirdNativeRect);
  at(16000, 'width', 100, thirdPolyfillRect, thirdNativeRect);
  at(17000, 'width', 200, fourthPolyfillRect, fourthNativeRect);
  at(18000, 'width', 100, fourthPolyfillRect, fourthNativeRect);
  at(19000, 'width', 200, fifthPolyfillRect, fifthNativeRect);
  at(20000, 'width', 100, fifthPolyfillRect, fifthNativeRect);
}, 'sync-base dependencies');
<commit_msg>Avoid flakiness in sync-base test<commit_after>'use strict';

timing_test(function() {
  var firstPolyfillRect = document.getElementById('firstPolyfillRect');
  var firstNativeRect = document.getElementById('firstNativeRect');
  var secondPolyfillRect = document.getElementById('secondPolyfillRect');
  var secondNativeRect = document.getElementById('secondNativeRect');
  var thirdPolyfillRect = document.getElementById('thirdPolyfillRect');
  var thirdNativeRect = document.getElementById('thirdNativeRect');
  var fourthPolyfillRect = document.getElementById('fourthPolyfillRect');
  var fourthNativeRect = document.getElementById('fourthNativeRect');
  var fifthPolyfillRect = document.getElementById('fifthPolyfillRect');
  var fifthNativeRect = document.getElementById('fifthNativeRect');

  at(0, 'width', 100, firstPolyfillRect, firstNativeRect);
  at(1000, 'width', 200, firstPolyfillRect, firstNativeRect);
  at(2000, 'width', 100, firstPolyfillRect, firstNativeRect);
  at(3000, 'width', 200, secondPolyfillRect, secondNativeRect);
  at(4000, 'width', 100, secondPolyfillRect, secondNativeRect);
  at(5000, 'width', 200, thirdPolyfillRect, thirdNativeRect);
  at(6000, 'width', 100, thirdPolyfillRect, thirdNativeRect);
  at(7000, 'width', 200, fourthPolyfillRect, fourthNativeRect);
  at(8000, 'width', 100, fourthPolyfillRect, fourthNativeRect);
  at(9000, 'width', 200, fifthPolyfillRect, fifthNativeRect);
  at(10000, 'width', 100, fifthPolyfillRect, fifthNativeRect);
  at(11000, 'width', 200, firstPolyfillRect, firstNativeRect);
  at(12000, 'width', 100, firstPolyfillRect, firstNativeRect);
  at(13000, 'width', 200, secondPolyfillRect, secondNativeRect);
  at(14000, 'width', 100, secondPolyfillRect, secondNativeRect);
  at(15000, 'width', 200, thirdPolyfillRect, thirdNativeRect);
  at(16000, 'width', 100, thirdPolyfillRect, thirdNativeRect);
  at(17000, 'width', 200, fourthPolyfillRect, fourthNativeRect);
  at(18000, 'width', 100, fourthPolyfillRect, fourthNativeRect);
  at(19000, 'width', 200, fifthPolyfillRect, fifthNativeRect);
  at(20000, 'width', 100, fifthPolyfillRect, fifthNativeRect);
}, 'sync-base dependencies');
<|endoftext|>


<commit_before>// FIXME emphasis label position is not same with normal label position
define(function (require) {

    'use strict';

    var textContain = require('zrender/contain/text');

    function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {
        list.sort(function (a, b) {
            return a.y - b.y;
        });

        // 压
        function shiftDown(start, end, delta, dir) {
            for (var j = start; j < end; j++) {
                list[j].y += delta;
                if (j > start
                    && j + 1 < end
                    && list[j + 1].y > list[j].y + list[j].height
                ) {
                    shiftUp(j, delta / 2);
                    return;
                }
            }

            shiftUp(end - 1, delta / 2);
        }

        // 弹
        function shiftUp(end, delta) {
            for (var j = end; j >= 0; j--) {
                list[j].y -= delta;
                if (j > 0
                    && list[j].y > list[j - 1].y + list[j - 1].height
                ) {
                    break;
                }
            }
        }

        function changeX(list, isDownList, cx, cy, r, dir) {
            var lastDeltaX = dir > 0
                ? isDownList                // 右侧
                    ? Number.MAX_VALUE      // 下
                    : 0                     // 上
                : isDownList                // 左侧
                    ? Number.MAX_VALUE      // 下
                    : 0;                    // 上

            for (var i = 0, l = list.length; i < l; i++) {
                // Not change x for center label
                if (list[i].position === 'center') {
                    continue;
                }
                var deltaY = Math.abs(list[i].y - cy);
                var length = list[i].length;
                var deltaX = (deltaY < r + length)
                    ? Math.sqrt(
                          (r + length + 20) * (r + length + 20)
                          - Math.pow(list[i].y - cy, 2)
                      )
                    : Math.abs(list[i].x - cx);
                if (isDownList && deltaX >= lastDeltaX) {
                    // 右下，左下
                    deltaX = lastDeltaX - 10;
                }
                if (!isDownList && deltaX <= lastDeltaX) {
                    // 右上，左上
                    deltaX = lastDeltaX + 10;
                }

                list[i].x = cx + deltaX * dir;
                lastDeltaX = deltaX;
            }
        }

        var lastY = 0;
        var delta;
        var len = list.length;
        var upList = [];
        var downList = [];
        for (var i = 0; i < len; i++) {
            delta = list[i].y - lastY;
            if (delta < 0) {
                shiftDown(i, len, -delta, dir);
            }
            lastY = list[i].y + list[i].height;
        }
        if (viewHeight - lastY < 0) {
            shiftUp(len - 1, lastY - viewHeight);
        }
        for (var i = 0; i < len; i++) {
            if (list[i].y >= cy) {
                downList.push(list[i]);
            }
            else {
                upList.push(list[i]);
            }
        }
        changeX(downList, true, cx, cy, r, dir);
        changeX(upList, false, cx, cy, r, dir);
    }

    function avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight) {
        var leftList = [];
        var rightList = [];
        for (var i = 0; i < labelLayoutList.length; i++) {
            if (labelLayoutList[i].x < cx) {
                leftList.push(labelLayoutList[i]);
            }
            else {
                rightList.push(labelLayoutList[i]);
            }
        }

        adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight);
        adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight);

        for (var i = 0; i < labelLayoutList.length; i++) {
            var linePoints = labelLayoutList[i].linePoints;
            if (linePoints) {
                var dist = linePoints[1][0] - linePoints[2][0];
                if (labelLayoutList[i].x < cx) {
                    linePoints[2][0] = labelLayoutList[i].x + 3;
                }
                else {
                    linePoints[2][0] = labelLayoutList[i].x - 3;
                }
                linePoints[1][1] = linePoints[2][1] = labelLayoutList[i].y;
                linePoints[1][0] = linePoints[2][0] + dist;
            }
        }
    }

    return function (seriesModel, r, viewWidth, viewHeight) {
        var data = seriesModel.getData();
        var labelLayoutList = [];
        var cx;
        var cy;
        var hasLabelRotate = false;

        data.each(function (idx) {
            var layout = data.getItemLayout(idx);

            var itemModel = data.getItemModel(idx);
            var labelModel = itemModel.getModel('label.normal');
            // Use position in normal or emphasis
            var labelPosition = labelModel.get('position') || itemModel.get('label.emphasis.position');

            var labelLineModel = itemModel.getModel('labelLine.normal');
            var labelLineLen = labelLineModel.get('length');
            var labelLineLen2 = labelLineModel.get('length2');

            var midAngle = (layout.startAngle + layout.endAngle) / 2;
            var dx = Math.cos(midAngle);
            var dy = Math.sin(midAngle);

            var textX;
            var textY;
            var linePoints;
            var textAlign;

            cx = layout.cx;
            cy = layout.cy;

            var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner';
            if (labelPosition === 'center') {
                textX = layout.cx;
                textY = layout.cy;
                textAlign = 'center';
            }
            else {
                var x1 = (isLabelInside ? layout.r / 2 * dx : layout.r * dx) + cx;
                var y1 = (isLabelInside ? layout.r / 2 * dy : layout.r * dy) + cy;

                // For roseType
                labelLineLen += r - layout.r;

                textX = x1 + dx * 3;
                textY = y1 + dy * 3;

                if (!isLabelInside) {
                    var x2 = x1 + dx * labelLineLen;
                    var y2 = y1 + dy * labelLineLen;
                    var x3 = x2 + ((dx < 0 ? -1 : 1) * labelLineLen2);
                    var y3 = y2;

                    textX = x3 + (dx < 0 ? -5 : 5);
                    textY = y3;
                    linePoints = [[x1, y1], [x2, y2], [x3, y3]];
                }

                textAlign = isLabelInside ? 'center' : (dx > 0 ? 'left' : 'right');
            }
            var font = labelModel.getModel('textStyle').getFont();

            var labelRotate = labelModel.get('rotate')
                ? (dx < 0 ? -midAngle + Math.PI : -midAngle) : 0;
            var text = seriesModel.getFormattedLabel(idx, 'normal')
                        || data.getName(idx);
            var textRect = textContain.getBoundingRect(
                text, font, textAlign, 'top'
            );
            hasLabelRotate = !!labelRotate;
            layout.label = {
                x: textX,
                y: textY,
                position: labelPosition,
                height: textRect.height,
                length: labelLineLen,
                length2: labelLineLen2,
                linePoints: linePoints,
                textAlign: textAlign,
                verticalAlign: 'middle',
                font: font,
                rotation: labelRotate
            };

            // Not layout the inside label
            if (!isLabelInside) {
                labelLayoutList.push(layout.label);
            }
        });
        if (!hasLabelRotate && seriesModel.get('avoidLabelOverlap')) {
            avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight);
        }
    };
});<commit_msg>Fix pie label layout bug in roseType.  Fix #2910<commit_after>// FIXME emphasis label position is not same with normal label position
define(function (require) {

    'use strict';

    var textContain = require('zrender/contain/text');

    function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {
        list.sort(function (a, b) {
            return a.y - b.y;
        });

        // 压
        function shiftDown(start, end, delta, dir) {
            for (var j = start; j < end; j++) {
                list[j].y += delta;
                if (j > start
                    && j + 1 < end
                    && list[j + 1].y > list[j].y + list[j].height
                ) {
                    shiftUp(j, delta / 2);
                    return;
                }
            }

            shiftUp(end - 1, delta / 2);
        }

        // 弹
        function shiftUp(end, delta) {
            for (var j = end; j >= 0; j--) {
                list[j].y -= delta;
                if (j > 0
                    && list[j].y > list[j - 1].y + list[j - 1].height
                ) {
                    break;
                }
            }
        }

        function changeX(list, isDownList, cx, cy, r, dir) {
            var lastDeltaX = dir > 0
                ? isDownList                // 右侧
                    ? Number.MAX_VALUE      // 下
                    : 0                     // 上
                : isDownList                // 左侧
                    ? Number.MAX_VALUE      // 下
                    : 0;                    // 上

            for (var i = 0, l = list.length; i < l; i++) {
                // Not change x for center label
                if (list[i].position === 'center') {
                    continue;
                }
                var deltaY = Math.abs(list[i].y - cy);
                var length = list[i].len;
                var length2 = list[i].len2;
                var deltaX = (deltaY < r + length)
                    ? Math.sqrt(
                          (r + length + length2) * (r + length + length2)
                          - deltaY * deltaY
                      )
                    : Math.abs(list[i].x - cx);
                if (isDownList && deltaX >= lastDeltaX) {
                    // 右下，左下
                    deltaX = lastDeltaX - 10;
                }
                if (!isDownList && deltaX <= lastDeltaX) {
                    // 右上，左上
                    deltaX = lastDeltaX + 10;
                }

                list[i].x = cx + deltaX * dir;
                lastDeltaX = deltaX;
            }
        }

        var lastY = 0;
        var delta;
        var len = list.length;
        var upList = [];
        var downList = [];
        for (var i = 0; i < len; i++) {
            delta = list[i].y - lastY;
            if (delta < 0) {
                shiftDown(i, len, -delta, dir);
            }
            lastY = list[i].y + list[i].height;
        }
        if (viewHeight - lastY < 0) {
            shiftUp(len - 1, lastY - viewHeight);
        }
        for (var i = 0; i < len; i++) {
            if (list[i].y >= cy) {
                downList.push(list[i]);
            }
            else {
                upList.push(list[i]);
            }
        }
        changeX(upList, false, cx, cy, r, dir);
        changeX(downList, true, cx, cy, r, dir);
    }

    function avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight) {
        var leftList = [];
        var rightList = [];
        for (var i = 0; i < labelLayoutList.length; i++) {
            if (labelLayoutList[i].x < cx) {
                leftList.push(labelLayoutList[i]);
            }
            else {
                rightList.push(labelLayoutList[i]);
            }
        }

        adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight);
        adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight);

        for (var i = 0; i < labelLayoutList.length; i++) {
            var linePoints = labelLayoutList[i].linePoints;
            if (linePoints) {
                var dist = linePoints[1][0] - linePoints[2][0];
                if (labelLayoutList[i].x < cx) {
                    linePoints[2][0] = labelLayoutList[i].x + 3;
                }
                else {
                    linePoints[2][0] = labelLayoutList[i].x - 3;
                }
                linePoints[1][1] = linePoints[2][1] = labelLayoutList[i].y;
                linePoints[1][0] = linePoints[2][0] + dist;
            }
        }
    }

    return function (seriesModel, r, viewWidth, viewHeight) {
        var data = seriesModel.getData();
        var labelLayoutList = [];
        var cx;
        var cy;
        var hasLabelRotate = false;

        data.each(function (idx) {
            var layout = data.getItemLayout(idx);

            var itemModel = data.getItemModel(idx);
            var labelModel = itemModel.getModel('label.normal');
            // Use position in normal or emphasis
            var labelPosition = labelModel.get('position') || itemModel.get('label.emphasis.position');

            var labelLineModel = itemModel.getModel('labelLine.normal');
            var labelLineLen = labelLineModel.get('length');
            var labelLineLen2 = labelLineModel.get('length2');

            var midAngle = (layout.startAngle + layout.endAngle) / 2;
            var dx = Math.cos(midAngle);
            var dy = Math.sin(midAngle);

            var textX;
            var textY;
            var linePoints;
            var textAlign;

            cx = layout.cx;
            cy = layout.cy;

            var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner';
            if (labelPosition === 'center') {
                textX = layout.cx;
                textY = layout.cy;
                textAlign = 'center';
            }
            else {
                var x1 = (isLabelInside ? layout.r / 2 * dx : layout.r * dx) + cx;
                var y1 = (isLabelInside ? layout.r / 2 * dy : layout.r * dy) + cy;

                textX = x1 + dx * 3;
                textY = y1 + dy * 3;

                if (!isLabelInside) {
                    // For roseType
                    var x2 = x1 + dx * (labelLineLen + r - layout.r);
                    var y2 = y1 + dy * (labelLineLen + r - layout.r);
                    var x3 = x2 + ((dx < 0 ? -1 : 1) * labelLineLen2);
                    var y3 = y2;

                    textX = x3 + (dx < 0 ? -5 : 5);
                    textY = y3;
                    linePoints = [[x1, y1], [x2, y2], [x3, y3]];
                }

                textAlign = isLabelInside ? 'center' : (dx > 0 ? 'left' : 'right');
            }
            var font = labelModel.getModel('textStyle').getFont();

            var labelRotate = labelModel.get('rotate')
                ? (dx < 0 ? -midAngle + Math.PI : -midAngle) : 0;
            var text = seriesModel.getFormattedLabel(idx, 'normal')
                        || data.getName(idx);
            var textRect = textContain.getBoundingRect(
                text, font, textAlign, 'top'
            );
            hasLabelRotate = !!labelRotate;
            layout.label = {
                x: textX,
                y: textY,
                position: labelPosition,
                height: textRect.height,
                len: labelLineLen,
                len2: labelLineLen2,
                linePoints: linePoints,
                textAlign: textAlign,
                verticalAlign: 'middle',
                font: font,
                rotation: labelRotate
            };

            // Not layout the inside label
            if (!isLabelInside) {
                labelLayoutList.push(layout.label);
            }
        });
        if (!hasLabelRotate && seriesModel.get('avoidLabelOverlap')) {
            avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight);
        }
    };
});<|endoftext|>


<commit_before>// @flow
import jQuery from 'jquery';
import Clipboad from 'clipboard';

import { imageRepository } from '../application/repositories';

const createImageElement = (imageUrl: string) => {
  jQuery('main')
    .empty()
    .append(`<img style="min-width: 100px; min-height: 100px;max-width: 500px; max-height: 500px;" src="${imageUrl}">`);
};

const copyToClipboard = (text: string) => {
  jQuery('#clipboard').attr('data-clipboard-text', text);
  jQuery('#clipboard').click();
  jQuery('#alert').show();
};

const notifyTextToTab = (text: string) => {
  chrome.tabs.query({ active: true, currentWindow: true }, (tabs: Array) => {
    const tabId: number = tabs[0].id;
    chrome.tabs.sendMessage(tabId, text, () => { });
  });
};

jQuery(document).ready(() => {
  const clipboard = new Clipboad('.btn');
  clipboard.on('success', (e) => {
    console.info(`Copied to clipboard: ${e.text}`);
  });

  imageRepository
    .fetch()
    .subscribe((images) => {
      if (images.isEmpty()) {
        chrome.runtime.openOptionsPage();
        return;
      }

      const img = images.getRandom();
      const imageUrl = img.src;
      createImageElement(imageUrl);

      const imageText = `[![LGTM](${imageUrl})](${imageUrl})`;
      copyToClipboard(imageText);
      notifyTextToTab(imageText);
    });
});
<commit_msg>Fix type<commit_after>// @flow
import jQuery from 'jquery';
import Clipboad from 'clipboard';

import { imageRepository } from '../application/repositories';

const createImageElement = (imageUrl: string) => {
  jQuery('main')
    .empty()
    .append(`<img style="min-width: 100px; min-height: 100px;max-width: 500px; max-height: 500px;" src="${imageUrl}">`);
};

const copyToClipboard = (text: string) => {
  jQuery('#clipboard').attr('data-clipboard-text', text);
  jQuery('#clipboard').click();
  jQuery('#alert').show();
};

const notifyTextToTab = (text: string) => {
  chrome.tabs.query({ active: true, currentWindow: true }, (tabs: any) => {
    const tabId: number = tabs[0].id;
    chrome.tabs.sendMessage(tabId, text, () => { });
  });
};

jQuery(document).ready(() => {
  const clipboard = new Clipboad('.btn');
  clipboard.on('success', (e) => {
    console.info(`Copied to clipboard: ${e.text}`);
  });

  imageRepository
    .fetch()
    .subscribe((images) => {
      if (images.isEmpty()) {
        chrome.runtime.openOptionsPage();
        return;
      }

      const img = images.getRandom();
      const imageUrl = img.src;
      createImageElement(imageUrl);

      const imageText = `[![LGTM](${imageUrl})](${imageUrl})`;
      copyToClipboard(imageText);
      notifyTextToTab(imageText);
    });
});
<|endoftext|>


<commit_before>'use strict';

var rinput = /^\s*(.*?)(?:\s+"(.+)")?\s*$/;
var rfull = /^(?:https?|ftp):\/\//;

function parseLinkInput (input) {
  return parser.apply(null, input.match(rinput));

  function parser (all, link, title) {
    var href = link.replace(/\?.*$/, queryUnencodedReplacer);
    href = decodeURIComponent(href);
    href = encodeURI(href).replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29');
    href = href.replace(/\?.*$/, queryEncodedReplacer);

    return {
      href: formatHref(href), title: formatTitle(title)
    };
  }
}

function queryUnencodedReplacer (query) {
  return query.replace(/\+/g, ' ');
}

function queryEncodedReplacer (query) {
  return query.replace(/\+/g, '%2b');
}

function formatTitle (title) {
  if (!title) {
    return null;
  }

  return title
    .replace(/^\s+|\s+$/g, '')
    .replace(/"/g, 'quot;')
    .replace(/\(/g, '(')
    .replace(/\)/g, ')')
    .replace(/</g, '<')
    .replace(/>/g, '>');
}

function formatHref (url) {
  var href = url.replace(/^\s+|\s+$/g, '');
  if (href.length && href[0] !== '/' && !rfull.test(href)) {
    return 'http://' + href;
  }
  return href;
}

module.exports = parseLinkInput;
<commit_msg>cleaner link titles<commit_after>'use strict';

var rinput = /^\s*(.*?)(?:\s+"(.+)")?\s*$/;
var rfull = /^(?:https?|ftp):\/\//;

function parseLinkInput (input) {
  return parser.apply(null, input.match(rinput));

  function parser (all, link, title) {
    var href = link.replace(/\?.*$/, queryUnencodedReplacer);
    href = decodeURIComponent(href);
    href = encodeURI(href).replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29');
    href = href.replace(/\?.*$/, queryEncodedReplacer);

    return {
      href: formatHref(href), title: formatTitle(title)
    };
  }
}

function queryUnencodedReplacer (query) {
  return query.replace(/\+/g, ' ');
}

function queryEncodedReplacer (query) {
  return query.replace(/\+/g, '%2b');
}

function formatTitle (title) {
  if (!title) {
    return null;
  }

  return title
    .replace(/^\s+|\s+$/g, '')
    .replace(/"/g, '"')
    .replace(/</g, '<')
    .replace(/>/g, '>');
}

function formatHref (url) {
  var href = url.replace(/^\s+|\s+$/g, '');
  if (href.length && href[0] !== '/' && !rfull.test(href)) {
    return 'http://' + href;
  }
  return href;
}

module.exports = parseLinkInput;
<|endoftext|>


<commit_before>/*!
 * @author      Aleš Kocjančič - github.com/finalangel/classjs-plugins
 * @copyright	Distributed under the BSD License.
 * @version     2.0.0
 */

// ensure namespace is defined
var Cl = window.Cl || {};

(function($){
	'use strict';

	// creating class
	Cl.Gallery = new Class({
		/*
			TODO 2.1.0
			- add coverflow feature
		 */

		options: {
			'index': null, // initial image to show
			'timeout': 5000, // if set, the gallery will start moving automatically
			'autoplay': false, // same as carousel
			'easing': 'linear',
			'duration': 300, // duration for animation
			'move': 'next', // direction to move by default (next, previous or random)
			'engine': 'fade', // animation type (fade, slide)
			'cls': { // these selectors are all relative to the container
				'active': 'active', // class that will be used for active thumbnails
				'wrapper': '.wrapper', // viewport wrapper
				'viewport': '.viewport', // item container
				'elements': '.item',
				'next': '.trigger-next a', // right trigger
				'previous': '.trigger-previous a', // left trigger
				'navigation': 'nav a' // navigation triggers container
			}
		},

		initialize: function (container, options) {
			this.container = $(container);
			this.options = $.extend(true, {}, this.options, options);

			this.wrapper = this.container.find(this.options.cls.wrapper);
			this.viewport = this.container.find(this.options.cls.viewport);
			this.elements = this.container.find(this.options.cls.elements);
			this.navigation = this.container.find(this.options.cls.navigation);

			this.triggers = {
				'next': this.container.find(this.options.cls.next),
				'previous': this.container.find(this.options.cls.previous)
			};

			this.index = null;
			this.bound = this.elements.length;
			this.direction = '';
			this.queue = false;
			this.autoplay = false;
			this.timer = function () {};
			this.callbacks = {};

			var that = this;
			// this fixes chromes jQuery(window).load issue
			jQuery(window).load(function () {
				if(that.elements.length > 0) that._setup();
			});
		},

		_setup: function () {
			var that = this;

			// dynamically set height if necessary (only happens on page reload)
			this.wrapper.css('height', this.elements.eq(0).outerHeight(true));

			// bind event for next triggers
			this.triggers.next.on('click', function(e) {
				e.preventDefault();
				// determine autoplay status
				if(!that.options.autoplay) that.options.timeout = null;
				that.next();
			});

			// bind event for previous triggers
			this.triggers.previous.on('click', function(e) {
				e.preventDefault();
				// determine autoplay status
				if(!that.options.autoplay) that.options.timeout = null;
				that.previous();
			});

			// bind navigation
			this.navigation.on('click', function (e) {
				e.preventDefault();
				// determine autoplay status
				if(!that.options.autoplay) that.options.timeout = null;
				that.move(that.navigation.index($(this)), 'random');
			});

			// show elements
			this.navigation.show();
			this.triggers.next.show();
			this.triggers.previous.show();

			// start autoplay
			if(this.options.timeout) this.play();

			// init first
			this.move(this.options.index || 0, 'setup');
		},

		next: function () {
			// trigger event
			this._fire('next');

			// move
			this.move(this.index + 1, 'next');

			// trigger callback
			this._fire('next', this);
		},

		previous: function () {
			// trigger event
			this._fire('previous');

			// move
			this.move(this.index - 1, 'previous');

			// trigger callback
			this._fire('previous', this);
		},

		move: function (index, direction) {
			// trigger event
			this._fire('play');

			// cancel if queue
			if(this.queue) return false;

			// set new height
			this.wrapper.css('height', this.elements.eq(this.index).outerHeight(true));

			// cancel if index is the same
			if(index === this.index) return false;

			// set new index
			this.index = this._setIndex(index);

			// check if we should autoplay
			if(this.autoplay) this.stop();
			if(this.options.timeout > 0) this.play();

			// set direction
			this.direction = direction || this.options.move;

			// add accessibility
			this._accessibility();

			// change active navigation
			this.navigation.removeClass(this.options.cls.active);
			this.navigation.eq(this.index).addClass(this.options.cls.active);

			// start the engine
			this.engine[this.options.engine].call(this);

			// trigger event
			this._fire('play', this);
		},

		play: function () {
			// trigger event
			this._fire('play');

			var that = this;
			// start timer
			this.timer = setInterval(function () {
				that.next();
			}, this.options.timeout);

			// set runner
			this.autoplay = true;

			// trigger event
			this._fire('play', this);
		},

		stop: function () {
			// trigger event
			this._fire('stop');

			// we just need to clear the intervall
			clearInterval(this.timer);

			// unset runner
			this.autoplay = false;

			// trigger event
			this._fire('stop', this);
		},

		update: function () {
			// trigger event
			this._fire('update');

			// update gallery scripts
			this.move(this.index);

			// trigger event
			this._fire('update', this);
		},

		engine: {

			'fade': function () {
				// add fade animation
				this.elements.fadeOut(this.options.duration, this.options.transition);
				this.elements.eq(this.index).fadeIn(this.options.duration, this.options.transition);
			},

			'slide': function () {
				// set queue
				this.queue = true;

				// setup
				if(this.direction === 'setup') {
					var el = this.elements.eq(this.index);
					// we need to set a fixed width and height
					this.elements.show().css('left', -9999);
					el.css('left', 0);
					// we don't need a queue here
					this.queue = false;
				} else {
					// get current element
					var width = this.viewport.outerWidth();
					var visible = this.elements.filter(function () {
						return parseInt($(this).css('left')) === 0;
					});

					// animate old element
					visible.animate({
						'left': (this.direction === 'previous') ? width : -width
					}, this.options.duration, this.options.transition, function () {
						// ensure element is out of reach
						$(this).css('left', -9999);
					});
					// animate new element
					this.elements.eq(this.index).css('left', (this.direction === 'previous') ? -width : width).animate({
						'left': 0
					}, this.options.duration, this.options.transition);
				}

				var that = this;
				setTimeout(function () {
					that.queue = false;
				}, this.options.duration);
			}

		},

		_setIndex: function (index) {
			if(index < 0) index = this.bound - 1;
			if(index >= this.bound) index = 0;

			return index;
		},

		_accessibility: function () {
			// if only one item is moved at a time
			this.elements
				.attr('aria-hidden', true)
				.attr('aria-selected', false);
			this.elements.eq(this.index)
				.attr('aria-hidden', false)
				.attr('aria-selected', true);
		},

		_fire: function (keyword, scope) {
			if(scope) {
				// cancel if there is no callback found
				if(this.callbacks[keyword] === undefined) return false;
				// excecute callback
				this.callbacks[keyword](scope);
			} else {
				// excecute event
				$.event.trigger('gallery-' + keyword);
			}
		}
	});

})(jQuery);<commit_msg>fixed events being triggerd in wrong order<commit_after>/*!
 * @author      Aleš Kocjančič - github.com/finalangel/classjs-plugins
 * @copyright	Distributed under the BSD License.
 * @version     2.0.0
 */

// ensure namespace is defined
var Cl = window.Cl || {};

(function($){
	'use strict';

	// creating class
	Cl.Gallery = new Class({
		/*
			TODO 2.1.0
			- add coverflow feature
		 */

		options: {
			'index': null, // initial image to show
			'timeout': 5000, // if set, the gallery will start moving automatically
			'autoplay': false, // same as carousel
			'easing': 'linear',
			'duration': 300, // duration for animation
			'move': 'next', // direction to move by default (next, previous or random)
			'engine': 'fade', // animation type (fade, slide)
			'cls': { // these selectors are all relative to the container
				'active': 'active', // class that will be used for active thumbnails
				'wrapper': '.wrapper', // viewport wrapper
				'viewport': '.viewport', // item container
				'elements': '.item',
				'next': '.trigger-next a', // right trigger
				'previous': '.trigger-previous a', // left trigger
				'navigation': 'nav a' // navigation triggers container
			}
		},

		initialize: function (container, options) {
			this.container = $(container);
			this.options = $.extend(true, {}, this.options, options);

			this.wrapper = this.container.find(this.options.cls.wrapper);
			this.viewport = this.container.find(this.options.cls.viewport);
			this.elements = this.container.find(this.options.cls.elements);
			this.navigation = this.container.find(this.options.cls.navigation);

			this.triggers = {
				'next': this.container.find(this.options.cls.next),
				'previous': this.container.find(this.options.cls.previous)
			};

			this.index = null;
			this.bound = this.elements.length;
			this.direction = '';
			this.queue = false;
			this.autoplay = false;
			this.timer = function () {};
			this.callbacks = {};

			var that = this;
			// this fixes chromes jQuery(window).load issue
			jQuery(window).load(function () {
				if(that.elements.length > 0) that._setup();
			});
		},

		_setup: function () {
			var that = this;

			// dynamically set height if necessary (only happens on page reload)
			this.wrapper.css('height', this.elements.eq(0).outerHeight(true));

			// bind event for next triggers
			this.triggers.next.on('click', function(e) {
				e.preventDefault();
				// determine autoplay status
				if(!that.options.autoplay) that.options.timeout = null;
				that.next();
			});

			// bind event for previous triggers
			this.triggers.previous.on('click', function(e) {
				e.preventDefault();
				// determine autoplay status
				if(!that.options.autoplay) that.options.timeout = null;
				that.previous();
			});

			// bind navigation
			this.navigation.on('click', function (e) {
				e.preventDefault();
				// determine autoplay status
				if(!that.options.autoplay) that.options.timeout = null;
				that.move(that.navigation.index($(this)), 'random');
			});

			// show elements
			this.navigation.show();
			this.triggers.next.show();
			this.triggers.previous.show();

			// init first
			this.move(this.options.index || 0, 'setup');
		},

		next: function () {
			// trigger event
			this._fire('next');

			// move
			this.move(this.index + 1, 'next');

			// trigger callback
			this._fire('next', this);
		},

		previous: function () {
			// trigger event
			this._fire('previous');

			// move
			this.move(this.index - 1, 'previous');

			// trigger callback
			this._fire('previous', this);
		},

		move: function (index, direction) {
			// trigger event
			this._fire('move');

			// cancel if queue
			if(this.queue) return false;

			// set new height
			this.wrapper.css('height', this.elements.eq(this.index).outerHeight(true));

			// cancel if index is the same
			if(index === this.index) return false;

			// set new index
			this.index = this._setIndex(index);

			// check if we should autoplay
			if(this.autoplay) this.stop();
			if(this.options.timeout > 0) this.play();

			// set direction
			this.direction = direction || this.options.move;

			// add accessibility
			this._accessibility();

			// change active navigation
			this.navigation.removeClass(this.options.cls.active);
			this.navigation.eq(this.index).addClass(this.options.cls.active);

			// start the engine
			this.engine[this.options.engine].call(this);

			// trigger event
			this._fire('move', this);
		},

		play: function () {
			// trigger event
			this._fire('play');

			var that = this;
			// start timer
			this.timer = setInterval(function () {
				that.next();
			}, this.options.timeout);

			// set runner
			this.autoplay = true;

			// trigger event
			this._fire('play', this);
		},

		stop: function () {
			// trigger event
			this._fire('stop');

			// we just need to clear the intervall
			clearInterval(this.timer);

			// unset runner
			this.autoplay = false;

			// trigger event
			this._fire('stop', this);
		},

		update: function () {
			// trigger event
			this._fire('update');

			// update gallery scripts
			this.move(this.index);

			// trigger event
			this._fire('update', this);
		},

		engine: {

			'fade': function () {
				// add fade animation
				this.elements.fadeOut(this.options.duration, this.options.transition);
				this.elements.eq(this.index).fadeIn(this.options.duration, this.options.transition);
			},

			'slide': function () {
				// set queue
				this.queue = true;

				// setup
				if(this.direction === 'setup') {
					var el = this.elements.eq(this.index);
					// we need to set a fixed width and height
					this.elements.show().css('left', -9999);
					el.css('left', 0);
					// we don't need a queue here
					this.queue = false;
				} else {
					// get current element
					var width = this.viewport.outerWidth();
					var visible = this.elements.filter(function () {
						return parseInt($(this).css('left')) === 0;
					});

					// animate old element
					visible.animate({
						'left': (this.direction === 'previous') ? width : -width
					}, this.options.duration, this.options.transition, function () {
						// ensure element is out of reach
						$(this).css('left', -9999);
					});
					// animate new element
					this.elements.eq(this.index).css('left', (this.direction === 'previous') ? -width : width).animate({
						'left': 0
					}, this.options.duration, this.options.transition);
				}

				var that = this;
				setTimeout(function () {
					that.queue = false;
				}, this.options.duration);
			}

		},

		_setIndex: function (index) {
			if(index < 0) index = this.bound - 1;
			if(index >= this.bound) index = 0;

			return index;
		},

		_accessibility: function () {
			// if only one item is moved at a time
			this.elements
				.attr('aria-hidden', true)
				.attr('aria-selected', false);
			this.elements.eq(this.index)
				.attr('aria-hidden', false)
				.attr('aria-selected', true);
		},

		_fire: function (keyword, scope) {
			if(scope) {
				// cancel if there is no callback found
				if(this.callbacks[keyword] === undefined) return false;
				// excecute callback
				this.callbacks[keyword](scope);
			} else {
				// excecute event
				$.event.trigger('gallery-' + keyword);
			}
		}
	});

})(jQuery);<|endoftext|>


<commit_before>// describe('ui.grid.edit GridCellDirective', function () {
//   var gridUtil;
//   var scope;
//   var element;
//   var uiGridConstants;
//   var recompile;

//   beforeEach(module('ui.grid.edit'));

//   beforeEach(inject(function ($rootScope, $compile, $controller, _gridUtil_, $templateCache, gridClassFactory, uiGridEditService, _uiGridConstants_) {
//     gridUtil = _gridUtil_;
//     uiGridConstants = _uiGridConstants_;

//     $templateCache.put('ui-grid/uiGridCell', '
{{COL_FIELD CUSTOM_FILTERS}}
');
//     $templateCache.put('ui-grid/edit/editableCell', '

');
//     $templateCache.put('ui-grid/edit/cellTextEditor', '<input ng-input="COL_FIELD" ng-model="COL_FIELD" ng-blur="stopEdit()" />');

//     scope = $rootScope.$new();
//     var grid = gridClassFactory.createGrid();
//     grid.options.columnDefs = [
//       {field: 'col1', enableCellEdit: true}
//     ];
//     grid.options.data = [
//       {col1: 'val'}
//     ];
//     grid.registerColumnBuilder(uiGridEditService.editColumnBuilder);
//     grid.buildColumns();
//     grid.modifyRows(grid.options.data);

//     scope.grid = grid;
//     scope.col = grid.columns[0];
//     scope.row = grid.rows[0];

//     recompile = function () {
//       $compile(element)(scope);
//       $rootScope.$digest();
//     };
//   }));

//   describe('ui.grid.edit uiGridCell and uiGridTextEditor full workflow', function () {
//     var displayHtml;
//     beforeEach(function () {
//       element = angular.element('
');
//       recompile();

//       displayHtml = element.html();
//       expect(element.text()).toBe('val');
//       //invoke edit
//       element.dblclick();
//       expect(element.find('input')).toBeDefined();
//     });

//     it('should stop editing on enter', function () {
//       //stop edit
//       var event = jQuery.Event("keydown");
//       event.keyCode = uiGridConstants.keymap.ENTER;
//       element.find('input').trigger(event);

//       //back to beginning
//       expect(element.html()).toBe(displayHtml);
//     });

//     it('should stop editing on esc', function () {
//       //stop edit
//       var event = jQuery.Event("keydown");
//       event.keyCode = uiGridConstants.keymap.ESC;
//       element.find('input').trigger(event);

//       //back to beginning
//       expect(element.html()).toBe(displayHtml);
//     });

//     it('should stop when grid scrolls', function () {
//       //stop edit
//       scope.$broadcast(uiGridConstants.events.GRID_SCROLL);
//       scope.$digest();
//       //back to beginning
//       expect(element.html()).toBe(displayHtml);
//     });
//   });

// });<commit_msg>Reverting to 3.0 tests<commit_after>describe('ui.grid.edit GridCellDirective', function () {
  var gridUtil;
  var scope;
  var element;
  var uiGridConstants;
  var recompile;

  beforeEach(module('ui.grid.edit'));

  beforeEach(inject(function ($rootScope, $compile, $controller, _gridUtil_, $templateCache, gridClassFactory, uiGridEditService, _uiGridConstants_) {
    gridUtil = _gridUtil_;
    uiGridConstants = _uiGridConstants_;

    $templateCache.put('ui-grid/uiGridCell', '
{{COL_FIELD CUSTOM_FILTERS}}
');
    $templateCache.put('ui-grid/edit/editableCell', '

');
    $templateCache.put('ui-grid/edit/cellTextEditor', '<input ng-input="COL_FIELD" ng-model="COL_FIELD" ng-blur="stopEdit()" />');

    scope = $rootScope.$new();
    var grid = gridClassFactory.createGrid();
    grid.options.columnDefs = [
      {field: 'col1', enableCellEdit: true}
    ];
    grid.options.data = [
      {col1: 'val'}
    ];
    grid.registerColumnBuilder(uiGridEditService.editColumnBuilder);
    grid.buildColumns();
    grid.modifyRows(grid.options.data);

    scope.grid = grid;
    scope.col = grid.columns[0];
    scope.row = grid.rows[0];

    recompile = function () {
      $compile(element)(scope);
      $rootScope.$digest();
    };
  }));

  describe('ui.grid.edit uiGridCell and uiGridTextEditor full workflow', function () {
    var displayHtml;
    beforeEach(function () {
      element = angular.element('
');
      recompile();

      displayHtml = element.html();
      expect(element.text()).toBe('val');
      //invoke edit
      element.dblclick();
      expect(element.find('input')).toBeDefined();
    });

    it('should stop editing on enter', function () {
      //stop edit
      var event = jQuery.Event("keydown");
      event.keyCode = uiGridConstants.keymap.ENTER;
      element.find('input').trigger(event);

      //back to beginning
      expect(element.html()).toBe(displayHtml);
    });

    it('should stop editing on esc', function () {
      //stop edit
      var event = jQuery.Event("keydown");
      event.keyCode = uiGridConstants.keymap.ESC;
      element.find('input').trigger(event);

      //back to beginning
      expect(element.html()).toBe(displayHtml);
    });

    it('should stop when grid scrolls', function () {
      //stop edit
      scope.$broadcast(uiGridConstants.events.GRID_SCROLL);
      scope.$digest();
      //back to beginning
      expect(element.html()).toBe(displayHtml);
    });
  });

});<|endoftext|>


<commit_before>var test = require('tape');
var nlp = require('../lib/nlp');

test('clone:', function (t) {
  var arr = [
    'he eats the alligator',
    'Jumanji is the best move. He eats cheese.',
    'Uperman will be wayyyy better than batman!',
  ];
  arr.forEach((str) => {
    var m = nlp(str);
    var neg = m.clone().sentences().toNegative();
    var past = m.clone().sentences().toPastTense();
    var pres = m.clone().sentences().toPresentTense();
    var adv = m.clone().verbs().insertBefore('really');
    var rm = m.clone().verbs().delete('#Verb');
    var out = m.out();
    t.equal(out, str, 'equals input - ' + out);
    t.notEqual(str, neg.out(), 'neg not equal - ' + str);
    t.notEqual(str, past.out(), 'past not equal - ' + str);
    t.notEqual(str, pres.out(), 'pres not equal - ' + str);
    t.notEqual(str, adv.out(), 'adv not equal - ' + str);
    t.notEqual(str, rm.out(), 'rm not equal - ' + str);
  });

  t.end();
});
<commit_msg>clone test issue<commit_after>var test = require('tape');
var nlp = require('../lib/nlp');

test('clone:', function (t) {
  var arr = [
    'he eats the alligator',
    'Jumanji is the best move. He eats cheese.',
    'Uperman is wayyyy better than batman!',
  ];
  arr.forEach((str) => {
    var m = nlp(str);
    var neg = m.clone().sentences().toNegative();
    var past = m.clone().sentences().toPastTense();
    var fut = m.clone().sentences().toFutureTense();
    var adv = m.clone().verbs().insertBefore('really');
    var rm = m.clone().verbs().delete('#Verb');
    var out = m.out();
    t.equal(out, str, 'equals input - ' + out);
    t.notEqual(str, neg.out(), 'neg not equal - ' + str);
    t.notEqual(str, past.out(), 'past not equal - ' + str);
    t.notEqual(str, fut.out(), 'future not equal - ' + str);
    t.notEqual(str, adv.out(), 'adv not equal - ' + str);
    t.notEqual(str, rm.out(), 'rm not equal - ' + str);
  });

  t.end();
});
<|endoftext|>


<commit_before>if (typeof require !== 'undefined') {
  var Validator = require('../src/validator.js');
  var expect = require('chai').expect;
} else {
  var Validator = window.Validator;
  var expect = window.chai.expect;
}

describe('date rule', function() {
  it('should pass for correct, parsable date format', function() {
    var asserts = [
      807926400000,
      'Aug 9, 1995',
      'Wed, 09 Aug 1995 00:00:00 GMT',
      'Wed, 09 Aug 1995 00:00:00',
      '1995-08-09',
      '1995-08-09T00:00:00+00:00',
      '1995-08-09T00:00:00Z',
      '1995-08-09T00:00:00.000Z',
      (new Date())
    ];

    asserts.forEach(function (assert) {
      var validator = new Validator({
        date: assert
      }, {
        date: 'date'
      });
      expect(validator.passes()).to.be.true;
      expect(validator.fails()).to.be.false;
    });
  });

  it('should fail for incorrect date format', function() {

    var validator = new Validator({
      failDate: '2014-25-23'
    }, {
      failDate: 'date'
    });

    expect(validator.fails()).to.be.true;

  });
});
<commit_msg>117 refactored spec to include separate pass / fail blocks<commit_after>if (typeof require !== 'undefined') {
  var Validator = require('../src/validator.js');
  var expect = require('chai').expect;
} else {
  var Validator = window.Validator;
  var expect = window.chai.expect;
}

describe('date rule', function() {
  it('should pass for correct, parsable date format', function() {
    var asserts = [
      807926400000,
      'Aug 9, 1995',
      'Wed, 09 Aug 1995 00:00:00 GMT',
      'Wed, 09 Aug 1995 00:00:00',
      '1995-08-09',
      '1995-08-09T00:00:00+00:00',
      '1995-08-09T00:00:00Z',
      '1995-08-09T00:00:00.000Z',
      (new Date())
    ];

    asserts.forEach(function (assert) {
      var validator = new Validator({
        date: assert
      }, {
        date: 'date'
      });
      expect(validator.passes()).to.be.true;
      expect(validator.fails()).to.be.false;
    });
  });

  it('should pass for correct date formats', function() {
    var validator;

    validator = new Validator({failDate: 807926400}, {failDate: 'date'});
    expect(validator.passes()).to.be.true;

    validator = new Validator({failDate: '2017-03-11'}, {failDate: 'date'});
    expect(validator.passes()).to.be.true;

  });

  it('should fail for incorrect date formats', function() {

    var validator;

    validator = new Validator({failDate: '2014-25-23'}, {failDate: 'date'});
    expect(validator.fails()).to.be.true;

    validator = new Validator({failDate: 'foo-bar'}, {failDate: 'date'});
    expect(validator.fails()).to.be.true;

    validator = new Validator({failDate: '0908 1995'}, {failDate: 'date'});
    expect(validator.fails()).to.be.true;

  });
});
<|endoftext|>