<commit_before>

//----------------------------------------------------------------
// The imports
//----------------------------------------------------------------

/**
 * The Extension of Laravel Mix
 *
 * The Laravel Mix provides a clean, fluent API for defining basic webpack build steps for your web application.
 * The Laravel Mix supports several common CSS and JavaScript preprocessors.
 * @see [Laravel Mix]{@link https://github.com/JeffreyWay/laravel-mix}
 *
 * The Extensions of Laravel Mix adds and modifies methods and presets to Laravel Mix.
 * Its use is recommended for those developments which are stand-alone (not Laravel) projects.
 * @see [The Extensions of Laravel Mix]{@link https://gitlab.com/haasz/laravel-mix-ext}
 *
 * @type {Object}
 */
let mix = require('laravel-mix-ext');

//================================================================
// The custom settings
//================================================================

/**
 * Example settings for development of a general web application.
 *
 */
mix
	.setPublicPath(                         'dist'            )
	.js           ( 'src/js/script.js'    , 'dist/js/'        )
	.sass         ( 'src/scss/style.scss' , 'dist/css/'       )
	.tpl          ( 'src/index.html'      , 'dist/index.html' )
	.out(
		{
			images : {
				directory  : 'img',
				extensions : [ 'svg' ] // This is only the difference from default.
			},
			fonts  : 'font'
		}
	)
	.browserSync() // Call it only after calling mix.setPublicPath()!
;

//----------------------------------------------------------------
// The full API
//----------------------------------------------------------------

/*

mix

	.js(src, output)

	.react(src, output) // Identical to mix.js(), but registers React Babel compilation.

	.ts(src, output) // Requires tsconfig.json to exist in the same folder as webpack.mix.js

	.extract(vendorLibs)

	.sass(src, output)

	.standaloneSass('src', output) // Faster, but isolated from Webpack.

	.fastSass('src', output) // Alias for mix.standaloneSass().

	.less(src, output)

	.stylus(src, output)

	.postCss(src, output, [require('postcss-some-plugin')()])

	.tpl(src, target) // Added by The Extension of Laravel Mix.

	.out({ // Set the output directories (images and fonts). Added by The Extension of Laravel Mix.

		images: { // Object (like this) or String ('img') or Array (['svg'])

			directory: 'img', // Default: 'images'

			extensions: ['svg'] // Default: ['png', 'jpe?g', 'gif']. Giving the difference is enough.

		},

		fonts: { // Object or String or Array

			directory: 'font', // Default: 'fonts'

			extensions: [] // Default: ['woff2?', 'ttf', 'eot', 'svg', 'otf']. Giving the difference is enough.

		}

	})

	.browserSync('my-site.dev') // Call it only after calling mix.setPublicPath()! Modified by The Extension of Laravel Mix.

	.combine(files, destination)

	.babel(files, destination) // Identical to mix.combine(), but also includes Babel compilation.

	.copy(from, to)

	.copyDirectory(fromDir, toDir)

	.minify(file)

	.sourceMaps() // Enable sourcemaps

	.version() // Enable versioning. Auto versioning turned ON (except hot mode) by The Extension of Laravel Mix.

	.disableNotifications()

	.setPublicPath('path/to/public')

	.setResourceRoot('prefix/for/resource/locators')

	.autoload({}) // Will be passed to Webpack's ProvidePlugin.

	// This is a Laravel Mix method, but the original webpack configuration is modified by The Extension of Laravel Mix,
	// so its use is not recommended at this time:
	// .webpackConfig({}) // Override webpack.config.js, without editing the file directly.

	.then(function () {}) // Will be triggered each time Webpack finishes building.

	.options({

		extractVueStyles: false, // Extract .vue component styling to file, rather than inline.

		processCssUrls: true, // Process/optimize relative stylesheet url()'s. Set to false, if you don't want them touched.

		purifyCss: false, // Remove unused CSS selectors.

		uglify: {}, // Uglify-specific options. https://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin

		postCss: [] // Post-CSS options: https://github.com/postcss/postcss/blob/master/docs/plugins.md

	})

;

*/
<commit_msg>Modify comment in webpack.mix.js<commit_after>

//----------------------------------------------------------------
// The imports
//----------------------------------------------------------------

/**
 * The Extension of Laravel Mix
 *
 * The Laravel Mix provides a clean, fluent API for defining basic webpack build steps for your web application.
 * The Laravel Mix supports several common CSS and JavaScript preprocessors.
 * @see [Laravel Mix]{@link https://github.com/JeffreyWay/laravel-mix}
 *
 * The Extensions of Laravel Mix adds and modifies methods and presets to Laravel Mix.
 * Its use is recommended for those developments which are stand-alone (not Laravel) projects.
 * @see [The Extensions of Laravel Mix]{@link https://gitlab.com/haasz/laravel-mix-ext}
 *
 * @type {Object}
 */
let mix = require('laravel-mix-ext');

//================================================================
// The custom settings
//================================================================

/**
 * Example settings for development of a general web application.
 *
 */
mix
	.setPublicPath(                         'dist'            )
	.js           ( 'src/js/script.js'    , 'dist/js/'        )
	.sass         ( 'src/scss/style.scss' , 'dist/css/'       )
	.tpl          ( 'src/index.html'      , 'dist/index.html' )
	.out(
		{
			images : {
				directory  : 'img',
				extensions : [ 'svg' ] // This is only the difference from default.
			},
			fonts  : 'font'
		}
	)
	.browserSync() // Call it only after calling mix.setPublicPath()!
;

//----------------------------------------------------------------
// The full API
//----------------------------------------------------------------

/*

mix

	.js(src, output)

	.react(src, output) // Identical to mix.js(), but registers React Babel compilation.

	.ts(src, output) // Requires tsconfig.json to exist in the same folder as webpack.mix.js

	.extract(vendorLibs)

	.sass(src, output)

	.standaloneSass('src', output) // Faster, but isolated from Webpack.

	.fastSass('src', output) // Alias for mix.standaloneSass().

	.less(src, output)

	.stylus(src, output)

	.postCss(src, output, [require('postcss-some-plugin')()])

	.tpl(src, target) // Added by The Extension of Laravel Mix.

	.out({ // Set the output directories (images and fonts). Added by The Extension of Laravel Mix.

		images: { // Object (like this) or String ('img') or Array (['svg'])

			directory: 'img', // Default: 'images'

			extensions: ['svg'] // Default: ['png', 'jpe?g', 'gif']. Giving the difference is enough.

		},

		fonts: { // Object or String or Array

			directory: 'font', // Default: 'fonts'

			extensions: [] // Default: ['woff2?', 'ttf', 'eot', 'svg', 'otf']. Giving the difference is enough.

		}

	})

	.browserSync('my-site.dev') // Call it only after calling mix.setPublicPath()! Modified by The Extension of Laravel Mix.

	.combine(files, destination)

	.babel(files, destination) // Identical to mix.combine(), but also includes Babel compilation.

	.copy(from, to)

	.copyDirectory(fromDir, toDir)

	.minify(file)

	.sourceMaps() // Enable sourcemaps

	.version() // Enable versioning. Auto versioning turned ON (except hot mode) by The Extension of Laravel Mix.

	.disableNotifications()

	.setPublicPath('path/to/public')

	.setResourceRoot('prefix/for/resource/locators')

	.autoload({}) // Will be passed to Webpack's ProvidePlugin.

	// This is a Laravel Mix method, but the original webpack configuration is modified by The Extension of Laravel Mix,
	// so its use is not recommended at this time:
	// .webpackConfig({}) // Override webpack.config.js, without editing the file directly.

	.then(function () {}) // Will be triggered each time Webpack finishes building.

	.options({

		extractVueStyles: false, // Extract .vue component styling to file, rather than inline.

		globalVueStyles: file, // Variables file to be imported in every component.

		processCssUrls: true, // Process/optimize relative stylesheet url()'s. Set to false, if you don't want them touched.

		purifyCss: false, // Remove unused CSS selectors.

		uglify: {}, // Uglify-specific options. https://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin

		postCss: [] // Post-CSS options: https://github.com/postcss/postcss/blob/master/docs/plugins.md

	})

;

*/
<|endoftext|>


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

var KEY_DELIMITER = '-->';
/**
 * params handler
 * @param {module:echarts/model/SeriesModel} seriesModel
 * @returns {*}
 */
var getAutoCurvenessParams = function (seriesModel) {
    return seriesModel.get('autoCurveness') || null;
};

/**
 * Generate a list of edge curvatures, 20 is the default
 * @param {module:echarts/model/SeriesModel} seriesModel
 * @param {number} appendLength
 * @return  20 => [0, -0.2, 0.2, -0.4, 0.4, -0.6, 0.6, -0.8, 0.8, -1, 1, -1.2, 1.2, -1.4, 1.4, -1.6, 1.6, -1.8, 1.8, -2]
 */
var createCurveness = function (seriesModel, appendLength) {
    var autoCurvenessParmas = getAutoCurvenessParams(seriesModel);
    var length = 20;
    var curvenessList = [];

    // handler the function set
    if (typeof autoCurvenessParmas === 'number') {
        length = autoCurvenessParmas;
    }
    else if (Object.prototype.toString.call(autoCurvenessParmas) === '[object Array]') {
        seriesModel._curvenessList = autoCurvenessParmas;
        return;
    }

    // append length
    if (appendLength > length) {
        length = appendLength;
    }

    // make sure the length is even
    var len = length % 2 ? length + 2 : length + 3;
    curvenessList = [];

    for (var i = 0; i < len; i++) {
        curvenessList.push((i % 2 ? i + 1 : i) / 10 * (i % 2 ? -1 : 1));
    }
    seriesModel._curvenessList = curvenessList;
};

/**
 * Create different cache key data in the positive and negative directions, in order to set the curvature later
 * @param {number|string|module:echarts/data/Graph.Node} n1
 * @param {number|string|module:echarts/data/Graph.Node} n2
 * @param {module:echarts/model/SeriesModel} seriesModel
 * @returns {string} key
 */
var getKeyOfEdges = function (n1, n2, seriesModel) {
    var source = [n1.id, n1.dataIndex].join('.');
    var target = [n2.id, n2.dataIndex].join('.');
    return [seriesModel.uid, source, target].join(KEY_DELIMITER);
};

/**
 * get opposite key
 * @param {string} key
 * @returns {string}
 */
var getOppositeKey = function (key) {
    var keys = key.split(KEY_DELIMITER);
    return [keys[0], keys[2], keys[1]].join(KEY_DELIMITER);
};

/**
 * set edgeMap with key
 * @param {number|string|module:echarts/data/Graph.Node} n1
 * @param {number|string|module:echarts/data/Graph.Node} n2
 * @param {module:echarts/model/SeriesModel} seriesModel
 * @param {number} index
 */
var setEdgeToMap = function (n1, n2, seriesModel, index) {
    var key = getKeyOfEdges(n1, n2, seriesModel);
    var edgeMap = seriesModel._edgeMap;
    var oppositeEdges = edgeMap[getOppositeKey(key)];
    // set direction
    if (edgeMap[key] && !oppositeEdges) {
        edgeMap[key].isForward = true;
    }
    else if (oppositeEdges && edgeMap[key]) {
        oppositeEdges.isForward = true;
        edgeMap[key].isForward = false;
    }

    edgeMap[key] = edgeMap[key] || [];
    edgeMap[key].push(index);
};

/**
 * get edgeMap with key
 * @param edge
 * @param {module:echarts/model/SeriesModel} seriesModel
 */
var getEdgeFromMap = function (edge, seriesModel) {
    var key = getKeyOfEdges(edge.node1, edge.node2, seriesModel);
    return seriesModel._edgeMap[key];
};

/**
 * calculate all cases total length
 * @param edge
 * @param seriesModel
 * @returns {number}
 */
var getTotalLengthBetweenNodes = function (edge, seriesModel) {
    var len = getEdgeMapLengthWithKey(getKeyOfEdges(edge.node1, edge.node2, seriesModel), seriesModel);
    var lenV = getEdgeMapLengthWithKey(getKeyOfEdges(edge.node2, edge.node1, seriesModel), seriesModel);

    return len + lenV;
};

/**
 *
 * @param key
 */
var getEdgeMapLengthWithKey = function (key, seriesModel) {
    var edgeMap = seriesModel._edgeMap;
    return edgeMap[key] ? edgeMap[key].length : 0;
};

/**
 * Count the number of edges between the same two points, used to obtain the curvature table and the parity of the edge
 * @see /graph/GraphSeries.js@getInitialData
 * @param edges
 * @param {module:echarts/model/SeriesModel} seriesModel
 */
export function initCurvenessList(edges, seriesModel) {
    if (!getAutoCurvenessParams(seriesModel)) {
        return;
    }
    // Hang on this object 4 dispose
    seriesModel._curvenessList = seriesModel._curvenessList || [];
    // calc the array of curveness List
    createCurveness(seriesModel);
}

/**
 * create the edgeMap after addEdges
 * @see chart/helper/createGraphFromNodeEdge.js#L52
 * @param {number|string|module:echarts/data/Graph.Node} n1
 * @param {number|string|module:echarts/data/Graph.Node} n2
 * @param {module:echarts/model/SeriesModel} seriesModel
 * @param {number} dataIndex
 */
export function createEdgeMapForCurveness(n1, n2, seriesModel, dataIndex) {
    seriesModel._edgeMap = seriesModel._edgeMap || {};
    setEdgeToMap(n1, n2, seriesModel, dataIndex);
}

/**
 * get curvature for edge
 * @param edge
 * @param {module:echarts/model/SeriesModel} seriesModel
 * @param index
 */
export function getCurvenessForEdge(edge, seriesModel, index, needReverse) {
    const autoCurvenessParams = getAutoCurvenessParams(seriesModel);
    const isArrayParam = Object.prototype.toString.call(autoCurvenessParams) === '[object Array]';
    if (!autoCurvenessParams) {
        return null;
    }

    var edgeArray = getEdgeFromMap(edge, seriesModel);
    if (!edgeArray) {
        return null;
    }

    var edgeIndex = -1;
    for (var i = 0; i < edgeArray.length; i++) {
        if (edgeArray[i] === index) {
            edgeIndex = i;
            break;
        }
    }
    // if totalLen is Longer createCurveness
    var totalLen = getTotalLengthBetweenNodes(edge, seriesModel);
    createCurveness(seriesModel, totalLen);

    edge.lineStyle = edge.lineStyle || {};
    // if is opposite edge, must set curvenss to opposite number
    var curKey = getKeyOfEdges(edge.node1, edge.node2, seriesModel);
    var curvenessList = seriesModel._curvenessList;
    // if pass array no need parity
    var parityCorrection = isArrayParam ? 0 : totalLen % 2 ? 0 : 1;

    if (!edgeArray.isForward) {
        // the opposite edge show outside
        var oppositeKey = getOppositeKey(curKey);
        var len = getEdgeMapLengthWithKey(oppositeKey, seriesModel);
        var resValue = curvenessList[edgeIndex + len + parityCorrection];
        // isNeedReverse, simple, force type need reverse the curveness in the junction of the forword and the opposite
        if (needReverse) {
            // set as array may make the parity by add 1
            if (isArrayParam) {
                return (len + parityCorrection + 1) % 2 ? resValue : -resValue;
            }
            else {
                return (len + parityCorrection) % 2 ? resValue : -resValue;
            }
        }
        else {
            return curvenessList[edgeIndex + len + parityCorrection];
        }
    }
    else {
        return curvenessList[edgeIndex];
    }
}
<commit_msg>fix(tree): code rebuild follow the review suggest #2<commit_after>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

var KEY_DELIMITER = '-->';
/**
 * params handler
 * @param {module:echarts/model/SeriesModel} seriesModel
 * @returns {*}
 */
var getAutoCurvenessParams = function (seriesModel) {
    return seriesModel.get('autoCurveness') || null;
};

/**
 * Generate a list of edge curvatures, 20 is the default
 * @param {module:echarts/model/SeriesModel} seriesModel
 * @param {number} appendLength
 * @return  20 => [0, -0.2, 0.2, -0.4, 0.4, -0.6, 0.6, -0.8, 0.8, -1, 1, -1.2, 1.2, -1.4, 1.4, -1.6, 1.6, -1.8, 1.8, -2]
 */
var createCurveness = function (seriesModel, appendLength) {
    var autoCurvenessParmas = getAutoCurvenessParams(seriesModel);
    var length = 20;
    var curvenessList = [];

    // handler the function set
    if (typeof autoCurvenessParmas === 'number') {
        length = autoCurvenessParmas;
    }
    else if (Object.prototype.toString.call(autoCurvenessParmas) === '[object Array]') {
        seriesModel._curvenessList = autoCurvenessParmas;
        return;
    }

    // append length
    if (appendLength > length) {
        length = appendLength;
    }

    // make sure the length is even
    var len = length % 2 ? length + 2 : length + 3;
    curvenessList = [];

    for (var i = 0; i < len; i++) {
        curvenessList.push((i % 2 ? i + 1 : i) / 10 * (i % 2 ? -1 : 1));
    }
    seriesModel._curvenessList = curvenessList;
};

/**
 * Create different cache key data in the positive and negative directions, in order to set the curvature later
 * @param {number|string|module:echarts/data/Graph.Node} n1
 * @param {number|string|module:echarts/data/Graph.Node} n2
 * @param {module:echarts/model/SeriesModel} seriesModel
 * @returns {string} key
 */
var getKeyOfEdges = function (n1, n2, seriesModel) {
    var source = [n1.id, n1.dataIndex].join('.');
    var target = [n2.id, n2.dataIndex].join('.');
    return [seriesModel.uid, source, target].join(KEY_DELIMITER);
};

/**
 * get opposite key
 * @param {string} key
 * @returns {string}
 */
var getOppositeKey = function (key) {
    var keys = key.split(KEY_DELIMITER);
    return [keys[0], keys[2], keys[1]].join(KEY_DELIMITER);
};

/**
 * set edgeMap with key
 * @param {number|string|module:echarts/data/Graph.Node} n1
 * @param {number|string|module:echarts/data/Graph.Node} n2
 * @param {module:echarts/model/SeriesModel} seriesModel
 * @param {number} index
 */
var setEdgeToMap = function (n1, n2, seriesModel, index) {
    var key = getKeyOfEdges(n1, n2, seriesModel);
    var edgeMap = seriesModel._edgeMap;
    var oppositeEdges = edgeMap[getOppositeKey(key)];
    // set direction
    if (edgeMap[key] && !oppositeEdges) {
        edgeMap[key].isForward = true;
    }
    else if (oppositeEdges && edgeMap[key]) {
        oppositeEdges.isForward = true;
        edgeMap[key].isForward = false;
    }

    edgeMap[key] = edgeMap[key] || [];
    edgeMap[key].push(index);
};

/**
 * get edgeMap with key
 * @param edge
 * @param {module:echarts/model/SeriesModel} seriesModel
 */
var getEdgeFromMap = function (edge, seriesModel) {
    var key = getKeyOfEdges(edge.node1, edge.node2, seriesModel);
    return seriesModel._edgeMap[key];
};

/**
 * calculate all cases total length
 * @param edge
 * @param seriesModel
 * @returns {number}
 */
var getTotalLengthBetweenNodes = function (edge, seriesModel) {
    var len = getEdgeMapLengthWithKey(getKeyOfEdges(edge.node1, edge.node2, seriesModel), seriesModel);
    var lenV = getEdgeMapLengthWithKey(getKeyOfEdges(edge.node2, edge.node1, seriesModel), seriesModel);

    return len + lenV;
};

/**
 *
 * @param key
 */
var getEdgeMapLengthWithKey = function (key, seriesModel) {
    var edgeMap = seriesModel._edgeMap;
    return edgeMap[key] ? edgeMap[key].length : 0;
};

/**
 * Count the number of edges between the same two points, used to obtain the curvature table and the parity of the edge
 * @see /graph/GraphSeries.js@getInitialData
 * @param edges
 * @param {module:echarts/model/SeriesModel} seriesModel
 */
export function initCurvenessList(edges, seriesModel) {
    if (!getAutoCurvenessParams(seriesModel)) {
        return;
    }
    // Hang on this object 4 dispose
    seriesModel._curvenessList = seriesModel._curvenessList || [];
    // calc the array of curveness List
    createCurveness(seriesModel);
}

/**
 * create the edgeMap after addEdges
 * @see chart/helper/createGraphFromNodeEdge.js#L52
 * @param {number|string|module:echarts/data/Graph.Node} n1
 * @param {number|string|module:echarts/data/Graph.Node} n2
 * @param {module:echarts/model/SeriesModel} seriesModel
 * @param {number} dataIndex
 */
export function createEdgeMapForCurveness(n1, n2, seriesModel, dataIndex) {
    seriesModel._edgeMap = seriesModel._edgeMap || {};
    setEdgeToMap(n1, n2, seriesModel, dataIndex);
}

/**
 * get curvature for edge
 * @param edge
 * @param {module:echarts/model/SeriesModel} seriesModel
 * @param index
 */
export function getCurvenessForEdge(edge, seriesModel, index, needReverse) {
    const autoCurvenessParams = getAutoCurvenessParams(seriesModel);
    const isArrayParam = Object.prototype.toString.call(autoCurvenessParams) === '[object Array]';
    if (!autoCurvenessParams) {
        return null;
    }

    var edgeArray = getEdgeFromMap(edge, seriesModel);
    if (!edgeArray) {
        return null;
    }

    var edgeIndex = -1;
    for (var i = 0; i < edgeArray.length; i++) {
        if (edgeArray[i] === index) {
            edgeIndex = i;
            break;
        }
    }
    // if totalLen is Longer createCurveness
    var totalLen = getTotalLengthBetweenNodes(edge, seriesModel);
    createCurveness(seriesModel, totalLen);

    edge.lineStyle = edge.lineStyle || {};
    // if is opposite edge, must set curvenss to opposite number
    var curKey = getKeyOfEdges(edge.node1, edge.node2, seriesModel);
    var curvenessList = seriesModel._curvenessList;
    // if pass array no need parity
    var parityCorrection = isArrayParam ? 0 : totalLen % 2 ? 0 : 1;

    if (!edgeArray.isForward) {
        // the opposite edge show outside
        var oppositeKey = getOppositeKey(curKey);
        var len = getEdgeMapLengthWithKey(oppositeKey, seriesModel);
        var resValue = curvenessList[edgeIndex + len + parityCorrection];
        // isNeedReverse, simple, force type need reverse the curveness in the junction of the forword and the opposite
        if (needReverse) {
            // set as array may make the parity by add 1
            if (isArrayParam) {
                return ((len % 2 ? 0 : 1) + parityCorrection) % 2 ? resValue : -resValue;
            }
            else {
                return (len + parityCorrection) % 2 ? resValue : -resValue;
            }
        }
        else {
            return curvenessList[edgeIndex + len + parityCorrection];
        }
    }
    else {
        return curvenessList[edgeIndex];
    }
}
<|endoftext|>


<commit_before>/*!
 * OS.js - JavaScript Cloud/Web Desktop Platform
 *
 * Copyright (c) 2011-2017, Anders Evenrud <andersevenrud@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author  Anders Evenrud <andersevenrud@gmail.com>
 * @licence Simplified BSD License
 */
import axios from 'axios';
import Promise from 'bluebird';
import Transport from 'vfs/transport';
import Connection from 'core/connection';
import * as FS from 'utils/fs';

export default class WebTransport extends Transport {

  _request(url, responseType, method, options) {
    return new Promise((resolve, reject) => {
      if ( !options.cors ) {
        const binary = options.type === 'text' ? false : (responseType === 'arraybuffer');

        Connection.request('curl', {
          url: url,
          method: method,
          binary: binary
        }).then((result) => {
          if ( binary ) {
            return FS.dataSourceToAb(result.body, 'application/octet-stream', (err, ab) => {
              return err ? reject(err) : resolve(ab);
            });
          }
          return resolve(result.body);
        }).catch(reject);
      } else {
        axios({
          responseType: responseType,
          url: url,
          method: method
        }).then((response) => {
          return resolve(responseType === null ? response.statusText : response.data);
        }).catch((e) => reject(new Error(e.message || e)));
      }
    });
  }

  scandir(item, options, mount) {
    return new Promise((resolve, reject) => {
      const root = mount.option('root');
      const url = item.path.replace(/\/?$/, '/_scandir.json');

      this._request(url, 'json', 'GET', options).then((response) => {
        return resolve(response.map((iter) => {
          iter.path = root + iter.path.replace(/^\//, '');
          return iter;
        }));
      }).catch(reject);
    });
  }

  read(item, options) {
    const mime = item.mime || 'application/octet-stream';

    return new Promise((resolve, reject) => {
      this._request(item.path, 'arraybuffer', 'GET', options).then((response) => {
        if ( options.cors ) {
          if ( options.type === 'text' ) {
            resolve(response);
          } else {
            FS.dataSourceToAb(response, 'application/octet-stream', (err, ab) => {
              return err ? reject(err) : resolve(ab);
            });
          }

          return true;
        }

        if ( options.type === 'text' ) {
          FS.abToText(response, mime, (err, txt) => {
            if ( err ) {
              reject(new Error(err));
            } else {
              resolve(txt);
            }
          });

          return true;
        }

        return resolve(response);
      }).catch(reject);
    });
  }

  exists(item) {
    return new Promise((resolve, reject) => {
      this._request(item.path, null, 'HEAD').then((response) => {
        return resolve(response.toUpperCase() === 'OK');
      }).catch(reject);
    });
  }

  url(item) {
    return Promise.resolve(item.path);
  }
}
<commit_msg>client: Updated some documentation<commit_after>/*!
 * OS.js - JavaScript Cloud/Web Desktop Platform
 *
 * Copyright (c) 2011-2017, Anders Evenrud <andersevenrud@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author  Anders Evenrud <andersevenrud@gmail.com>
 * @licence Simplified BSD License
 */
import axios from 'axios';
import Promise from 'bluebird';
import Transport from 'vfs/transport';
import Connection from 'core/connection';
import * as FS from 'utils/fs';

/**
 * Web VFS Transport Module
 *
 * This module makes it possible to use normal URLs in VFS operations
 *
 * @extends Transport
 */
export default class WebTransport extends Transport {

  _request(url, responseType, method, options) {
    return new Promise((resolve, reject) => {
      if ( !options.cors ) {
        const binary = options.type === 'text' ? false : (responseType === 'arraybuffer');

        Connection.request('curl', {
          url: url,
          method: method,
          binary: binary
        }).then((result) => {
          if ( binary ) {
            return FS.dataSourceToAb(result.body, 'application/octet-stream', (err, ab) => {
              return err ? reject(err) : resolve(ab);
            });
          }
          return resolve(result.body);
        }).catch(reject);
      } else {
        axios({
          responseType: responseType,
          url: url,
          method: method
        }).then((response) => {
          return resolve(responseType === null ? response.statusText : response.data);
        }).catch((e) => reject(new Error(e.message || e)));
      }
    });
  }

  scandir(item, options, mount) {
    return new Promise((resolve, reject) => {
      const root = mount.option('root');
      const url = item.path.replace(/\/?$/, '/_scandir.json');

      this._request(url, 'json', 'GET', options).then((response) => {
        return resolve(response.map((iter) => {
          iter.path = root + iter.path.replace(/^\//, '');
          return iter;
        }));
      }).catch(reject);
    });
  }

  read(item, options) {
    const mime = item.mime || 'application/octet-stream';

    return new Promise((resolve, reject) => {
      this._request(item.path, 'arraybuffer', 'GET', options).then((response) => {
        if ( options.cors ) {
          if ( options.type === 'text' ) {
            resolve(response);
          } else {
            FS.dataSourceToAb(response, 'application/octet-stream', (err, ab) => {
              return err ? reject(err) : resolve(ab);
            });
          }

          return true;
        }

        if ( options.type === 'text' ) {
          FS.abToText(response, mime, (err, txt) => {
            if ( err ) {
              reject(new Error(err));
            } else {
              resolve(txt);
            }
          });

          return true;
        }

        return resolve(response);
      }).catch(reject);
    });
  }

  exists(item) {
    return new Promise((resolve, reject) => {
      this._request(item.path, null, 'HEAD').then((response) => {
        return resolve(response.toUpperCase() === 'OK');
      }).catch(reject);
    });
  }

  url(item) {
    return Promise.resolve(item.path);
  }
}
<|endoftext|>


<commit_before>import * as is from '../../is';
import { defaults } from '../../util';

const floydWarshallDefaults = defaults({
  weight: edge => 1,
  directed: false
});

let elesfn = ({

  // Implemented from pseudocode from wikipedia
  floydWarshall: function( options ){
    let cy = this.cy();

    let { weight, directed } = floydWarshallDefaults(options);
    let weightFn = weight;

    let { nodes, edges } = this.byGroup();
    edges.filter( e => !e.isLoop() );

    let numNodes = nodes.length;

    let indexOf = node => nodes.indexOf(node);
    let atIndex = i => nodes[i];

    // Initialize distance matrix
    let dist = [];
    for( let i = 0; i < numNodes; i++ ){
      let newRow = new Array( numNodes );
      for( let j = 0; j < numNodes; j++ ){
        if( i === j ){
          newRow[ j ] = 0;
        } else {
          newRow[ j ] = Infinity;
        }
      }
      dist.push( newRow );
    }

    // Initialize matrix used for path reconstruction
    // Initialize distance matrix
    let next = [];
    let edgeNext = [];

    let initMatrix = function( next ){
      for( let i = 0; i < numNodes; i++ ){
        let newRow = new Array( numNodes );

        for( let j = 0; j < numNodes; j++ ){
          newRow[ j ] = undefined;
        }

        next.push( newRow );
      }
    };

    initMatrix( next );
    initMatrix( edgeNext );

    // Process edges
    for( let i = 0; i < edges.length; i++ ){
      let edge = edges[i];
      let s = indexOf( edge.source() );
      let t = indexOf( edge.target() );
      let weight = weightFn( edge );

      // Check if already process another edge between same 2 nodes
      if( dist[s][t] > weight ){
        dist[s][t] = weight;
        next[s][t] = t;
        edgeNext[s][t] = edge;
      }

      // If undirected graph, process 'reversed' edge
      if( !directed && dist[t][s] > weight ){
        dist[t][s] = weight;
        next[t][s] = s;
        edgeNext[t][s] = edge;
      }
    }

    // Main loop
    for( let k = 0; k < numNodes; k++ ){
      for( let i = 0; i < numNodes; i++ ){
        for( let j = 0; j < numNodes; j++ ){
          if( dist[i][k] + dist[k][j] < dist[i][j] ){
            dist[i][j] = dist[i][k] + dist[k][j];
            next[i][j] = next[i][k];
          }
        }
      }
    }

    let getArgEle = ele => ( is.string(ele) ? cy.filter(ele) : ele )[0];

    let res = {
      distance: function( from, to ){
        from = getArgEle(from);
        to = getArgEle(to);

        return dist[ indexOf(from) ][ indexOf(to) ];
      },

      path: function( from, to ){
        from = getArgEle(from);
        to = getArgEle(to);

        let i = indexOf(from);
        let j = indexOf(to);
        let fromNode = atIndex(i);

        if( i === j ){ return fromNode.collection(); }

        if( next[i][j] == null ){ return cy.collection(); }

        let path = cy.collection();
        let prev = i;
        let edge;

        path.merge( fromNode );

        while( i !== j ){
          prev = i;
          i = next[i][j];
          edge = edgeNext[prev][i];

          path.merge( edge );
          path.merge( atIndex(i) );
        }

        return path;
      }
    };

    return res;

  } // floydWarshall

}); // elesfn

export default elesfn;
<commit_msg>Use a 1-dimensional array for Floyd-Warshall rather than multi-dimensional arrays<commit_after>import * as is from '../../is';
import { defaults } from '../../util';

const floydWarshallDefaults = defaults({
  weight: edge => 1,
  directed: false
});

let elesfn = ({

  // Implemented from pseudocode from wikipedia
  floydWarshall: function( options ){
    let cy = this.cy();

    let { weight, directed } = floydWarshallDefaults(options);
    let weightFn = weight;

    let { nodes, edges } = this.byGroup();
    edges.filter( e => !e.isLoop() );

    let N = nodes.length;
    let Nsq = N * N;

    let indexOf = node => nodes.indexOf(node);
    let atIndex = i => nodes[i];

    // Initialize distance matrix
    let dist = new Array(Nsq);
    for( let n = 0; n < Nsq; n++ ){
      let j = n % N;
      let i = (n - j) / N;

      if( i === j ){
        dist[n] = 0;
      } else {
        dist[n] = Infinity;
      }
    }

    // Initialize matrix used for path reconstruction
    // Initialize distance matrix
    let next = new Array(Nsq);
    let edgeNext = new Array(Nsq);

    // Process edges
    for( let i = 0; i < edges.length; i++ ){
      let edge = edges[i];
      let s = indexOf( edge.source() );
      let t = indexOf( edge.target() );
      let st = s * N + t; // source to target index
      let weight = weightFn( edge );

      // Check if already process another edge between same 2 nodes
      if( dist[st] > weight ){
        dist[st] = weight;
        next[st] = t;
        edgeNext[st] = edge;
      }

      // If undirected graph, process 'reversed' edge
      if( !directed ){
        let ts = t * N + s; // target to source index

        if( !directed && dist[ts] > weight ){
          dist[ts] = weight;
          next[ts] = s;
          edgeNext[ts] = edge;
        }
      }
    }

    // Main loop
    for( let k = 0; k < N; k++ ){

      for( let i = 0; i < N; i++ ){
        let ik = i * N + k;

        for( let j = 0; j < N; j++ ){
          let ij = i * N + j;
          let kj = k * N + j;

          if( dist[ik] + dist[kj] < dist[ij] ){
            dist[ij] = dist[ik] + dist[kj];
            next[ij] = next[ik];
          }
        }
      }
    }

    let getArgEle = ele => ( is.string(ele) ? cy.filter(ele) : ele )[0];
    let indexOfArgEle = ele => indexOf(getArgEle(ele));

    let res = {
      distance: function( from, to ){
        let i = indexOfArgEle(from);
        let j = indexOfArgEle(to);

        return dist[ i * N + j ];
      },

      path: function( from, to ){
        let i = indexOfArgEle(from);
        let j = indexOfArgEle(to);

        let fromNode = atIndex(i);

        if( i === j ){ return fromNode.collection(); }

        if( next[i * N + j] == null ){ return cy.collection(); }

        let path = cy.collection();
        let prev = i;
        let edge;

        path.merge( fromNode );

        while( i !== j ){
          prev = i;
          i = next[i * N + j];
          edge = edgeNext[prev * N + i];

          path.merge( edge );
          path.merge( atIndex(i) );
        }

        return path;
      }
    };

    return res;

  } // floydWarshall

}); // elesfn

export default elesfn;
<|endoftext|>


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

import * as zrUtil from 'zrender/src/core/util';
import * as graphic from '../../util/graphic';
import ChartView from '../../view/Chart';

/**
 * @param {module:echarts/model/Series} seriesModel
 * @param {boolean} hasAnimation
 * @inner
 */
function updateDataSelected(uid, seriesModel, hasAnimation, api) {
    var data = seriesModel.getData();
    var dataIndex = this.dataIndex;
    var name = data.getName(dataIndex);
    var selectedOffset = seriesModel.get('selectedOffset');

    api.dispatchAction({
        type: 'pieToggleSelect',
        from: uid,
        name: name,
        seriesId: seriesModel.id
    });

    data.each(function (idx) {
        toggleItemSelected(
            data.getItemGraphicEl(idx),
            data.getItemLayout(idx),
            seriesModel.isSelected(data.getName(idx)),
            selectedOffset,
            hasAnimation
        );
    });
}

/**
 * @param {module:zrender/graphic/Sector} el
 * @param {Object} layout
 * @param {boolean} isSelected
 * @param {number} selectedOffset
 * @param {boolean} hasAnimation
 * @inner
 */
function toggleItemSelected(el, layout, isSelected, selectedOffset, hasAnimation) {
    var midAngle = (layout.startAngle + layout.endAngle) / 2;

    var dx = Math.cos(midAngle);
    var dy = Math.sin(midAngle);

    var offset = isSelected ? selectedOffset : 0;
    var position = [dx * offset, dy * offset];

    hasAnimation
        // animateTo will stop revious animation like update transition
        ? el.animate()
            .when(200, {
                position: position
            })
            .start('bounceOut')
        : el.attr('position', position);
}

/**
 * Piece of pie including Sector, Label, LabelLine
 * @constructor
 * @extends {module:zrender/graphic/Group}
 */
function PiePiece(data, idx) {

    graphic.Group.call(this);

    var sector = new graphic.Sector({
        z2: 2
    });
    var polyline = new graphic.Polyline();
    var text = new graphic.Text();
    this.add(sector);
    this.add(polyline);
    this.add(text);

    this.updateData(data, idx, true);

    // Hover to change label and labelLine
    function onEmphasis() {
        polyline.ignore = polyline.hoverIgnore;
        text.ignore = text.hoverIgnore;
    }
    function onNormal() {
        polyline.ignore = polyline.normalIgnore;
        text.ignore = text.normalIgnore;
    }
    this.on('emphasis', onEmphasis)
        .on('normal', onNormal)
        .on('mouseover', onEmphasis)
        .on('mouseout', onNormal);
}

var piePieceProto = PiePiece.prototype;

piePieceProto.updateData = function (data, idx, firstCreate) {

    var sector = this.childAt(0);

    var seriesModel = data.hostModel;
    var itemModel = data.getItemModel(idx);
    var layout = data.getItemLayout(idx);
    var sectorShape = zrUtil.extend({}, layout);
    sectorShape.label = null;

    if (firstCreate) {
        sector.setShape(sectorShape);

        var animationType = seriesModel.getShallow('animationType');
        if (animationType === 'scale') {
            sector.shape.r = layout.r0;
            graphic.initProps(sector, {
                shape: {
                    r: layout.r
                }
            }, seriesModel, idx);
        }
        // Expansion
        else {
            sector.shape.endAngle = layout.startAngle;
            graphic.updateProps(sector, {
                shape: {
                    endAngle: layout.endAngle
                }
            }, seriesModel, idx);
        }

    }
    else {
        graphic.updateProps(sector, {
            shape: sectorShape
        }, seriesModel, idx);
    }

    // Update common style
    var visualColor = data.getItemVisual(idx, 'color');

    sector.useStyle(
        zrUtil.defaults(
            {
                lineJoin: 'bevel',
                fill: visualColor
            },
            itemModel.getModel('itemStyle').getItemStyle()
        )
    );
    sector.hoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();

    var cursorStyle = itemModel.getShallow('cursor');
    cursorStyle && sector.attr('cursor', cursorStyle);

    // Toggle selected
    toggleItemSelected(
        this,
        data.getItemLayout(idx),
        seriesModel.isSelected(null, idx),
        seriesModel.get('selectedOffset'),
        seriesModel.get('animation')
    );

    function onEmphasis() {
        // Sector may has animation of updating data. Force to move to the last frame
        // Or it may stopped on the wrong shape
        sector.stopAnimation(true);
        sector.animateTo({
            shape: {
                r: layout.r + seriesModel.get('hoverOffset')
            }
        }, 300, 'elasticOut');
    }
    function onNormal() {
        sector.stopAnimation(true);
        sector.animateTo({
            shape: {
                r: layout.r
            }
        }, 300, 'elasticOut');
    }
    sector.off('mouseover').off('mouseout').off('emphasis').off('normal');
    if (itemModel.get('hoverAnimation') && seriesModel.isAnimationEnabled()) {
        sector
            .on('mouseover', onEmphasis)
            .on('mouseout', onNormal)
            .on('emphasis', onEmphasis)
            .on('normal', onNormal);
    }

    this._updateLabel(data, idx);

    graphic.setHoverStyle(this);
};

piePieceProto._getFilterIgnore = function(data, idx) {
    var seriesModel = data.hostModel;
    var itemModel = data.getItemModel(idx);
    var valueDim = data.mapDimension('value');
    var sum = data.getSum(valueDim);
    var filterValue = seriesModel.get('labelDisplayThreshold');
    var filterIgnore = false;
    if (sum * filterValue.option > itemModel.option.value) {
        filterIgnore = true;
    }
    return filterIgnore;
}

piePieceProto._updateLabel = function(data, idx) {

    var labelLine = this.childAt(1);
    var labelText = this.childAt(2);

    var seriesModel = data.hostModel;
    var itemModel = data.getItemModel(idx);
    var layout = data.getItemLayout(idx);
    var labelLayout = layout.label;
    var visualColor = data.getItemVisual(idx, 'color');
    var filterIgnore = this._getFilterIgnore(data, idx);

    graphic.updateProps(labelLine, {
        shape: {
            points: labelLayout.linePoints || [
                [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y]
            ]
        }
    }, seriesModel, idx);

    graphic.updateProps(labelText, {
        style: {
            x: labelLayout.x,
            y: labelLayout.y
        }
    }, seriesModel, idx);
    labelText.attr({
        rotation: labelLayout.rotation,
        origin: [labelLayout.x, labelLayout.y],
        z2: 10
    });

    var labelModel = itemModel.getModel('label');
    var labelHoverModel = itemModel.getModel('emphasis.label');
    var labelLineModel = itemModel.getModel('labelLine');
    var labelLineHoverModel = itemModel.getModel('emphasis.labelLine');
    var visualColor = data.getItemVisual(idx, 'color');

    graphic.setLabelStyle(
        labelText.style, labelText.hoverStyle = {}, labelModel, labelHoverModel,
        {
            labelFetcher: data.hostModel,
            labelDataIndex: idx,
            defaultText: data.getName(idx),
            autoColor: visualColor,
            useInsideStyle: !!labelLayout.inside
        },
        {
            textAlign: labelLayout.textAlign,
            textVerticalAlign: labelLayout.verticalAlign,
            opacity: data.getItemVisual(idx, 'opacity')
        }
    );

    labelText.ignore = labelText.normalIgnore = !labelModel.get('show') || filterIgnore;
    labelText.hoverIgnore = !labelHoverModel.get('show') || filterIgnore;

    labelLine.ignore = labelLine.normalIgnore = !labelLineModel.get('show') || filterIgnore;
    labelLine.hoverIgnore = !labelLineHoverModel.get('show') || filterIgnore;

    // Default use item visual color
    labelLine.setStyle({
        stroke: visualColor,
        opacity: data.getItemVisual(idx, 'opacity')
    });
    labelLine.setStyle(labelLineModel.getModel('lineStyle').getLineStyle());

    labelLine.hoverStyle = labelLineHoverModel.getModel('lineStyle').getLineStyle();

    var smooth = labelLineModel.get('smooth');
    if (smooth && smooth === true) {
        smooth = 0.4;
    }
    labelLine.setShape({
        smooth: smooth
    });
};

zrUtil.inherits(PiePiece, graphic.Group);

// Pie view
var PieView = ChartView.extend({

    type: 'pie',

    init: function () {
        var sectorGroup = new graphic.Group();
        this._sectorGroup = sectorGroup;
    },

    render: function (seriesModel, ecModel, api, payload) {
        if (payload && (payload.from === this.uid)) {
            return;
        }

        var data = seriesModel.getData();
        var oldData = this._data;
        var group = this.group;

        var hasAnimation = ecModel.get('animation');
        var isFirstRender = !oldData;
        var animationType = seriesModel.get('animationType');

        var onSectorClick = zrUtil.curry(
            updateDataSelected, this.uid, seriesModel, hasAnimation, api
        );

        var selectedMode = seriesModel.get('selectedMode');

        data.diff(oldData)
            .add(function (idx) {
                var piePiece = new PiePiece(data, idx);
                // Default expansion animation
                if (isFirstRender && animationType !== 'scale') {
                    piePiece.eachChild(function (child) {
                        child.stopAnimation(true);
                    });
                }

                selectedMode && piePiece.on('click', onSectorClick);

                data.setItemGraphicEl(idx, piePiece);

                group.add(piePiece);
            })
            .update(function (newIdx, oldIdx) {
                var piePiece = oldData.getItemGraphicEl(oldIdx);

                piePiece.updateData(data, newIdx);

                piePiece.off('click');
                selectedMode && piePiece.on('click', onSectorClick);
                group.add(piePiece);
                data.setItemGraphicEl(newIdx, piePiece);
            })
            .remove(function (idx) {
                var piePiece = oldData.getItemGraphicEl(idx);
                group.remove(piePiece);
            })
            .execute();

        if (
            hasAnimation && isFirstRender && data.count() > 0
            // Default expansion animation
            && animationType !== 'scale'
        ) {
            var shape = data.getItemLayout(0);
            var r = Math.max(api.getWidth(), api.getHeight()) / 2;

            var removeClipPath = zrUtil.bind(group.removeClipPath, group);
            group.setClipPath(this._createClipPath(
                shape.cx, shape.cy, r, shape.startAngle, shape.clockwise, removeClipPath, seriesModel
            ));
        }

        this._data = data;
    },

    dispose: function () {},

    _createClipPath: function (
        cx, cy, r, startAngle, clockwise, cb, seriesModel
    ) {
        var clipPath = new graphic.Sector({
            shape: {
                cx: cx,
                cy: cy,
                r0: 0,
                r: r,
                startAngle: startAngle,
                endAngle: startAngle,
                clockwise: clockwise
            }
        });

        graphic.initProps(clipPath, {
            shape: {
                endAngle: startAngle + (clockwise ? 1 : -1) * Math.PI * 2
            }
        }, seriesModel, cb);

        return clipPath;
    },

    /**
     * @implement
     */
    containPoint: function (point, seriesModel) {
        var data = seriesModel.getData();
        var itemLayout = data.getItemLayout(0);
        if (itemLayout) {
            var dx = point[0] - itemLayout.cx;
            var dy = point[1] - itemLayout.cy;
            var radius = Math.sqrt(dx * dx + dy * dy);
            return radius <= itemLayout.r && radius >= itemLayout.r0;
        }
    }

});

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

import * as zrUtil from 'zrender/src/core/util';
import * as graphic from '../../util/graphic';
import ChartView from '../../view/Chart';

/**
 * @param {module:echarts/model/Series} seriesModel
 * @param {boolean} hasAnimation
 * @inner
 */
function updateDataSelected(uid, seriesModel, hasAnimation, api) {
    var data = seriesModel.getData();
    var dataIndex = this.dataIndex;
    var name = data.getName(dataIndex);
    var selectedOffset = seriesModel.get('selectedOffset');

    api.dispatchAction({
        type: 'pieToggleSelect',
        from: uid,
        name: name,
        seriesId: seriesModel.id
    });

    data.each(function (idx) {
        toggleItemSelected(
            data.getItemGraphicEl(idx),
            data.getItemLayout(idx),
            seriesModel.isSelected(data.getName(idx)),
            selectedOffset,
            hasAnimation
        );
    });
}

/**
 * @param {module:zrender/graphic/Sector} el
 * @param {Object} layout
 * @param {boolean} isSelected
 * @param {number} selectedOffset
 * @param {boolean} hasAnimation
 * @inner
 */
function toggleItemSelected(el, layout, isSelected, selectedOffset, hasAnimation) {
    var midAngle = (layout.startAngle + layout.endAngle) / 2;

    var dx = Math.cos(midAngle);
    var dy = Math.sin(midAngle);

    var offset = isSelected ? selectedOffset : 0;
    var position = [dx * offset, dy * offset];

    hasAnimation
        // animateTo will stop revious animation like update transition
        ? el.animate()
            .when(200, {
                position: position
            })
            .start('bounceOut')
        : el.attr('position', position);
}

/**
 * Piece of pie including Sector, Label, LabelLine
 * @constructor
 * @extends {module:zrender/graphic/Group}
 */
function PiePiece(data, idx) {

    graphic.Group.call(this);

    var sector = new graphic.Sector({
        z2: 2
    });
    var polyline = new graphic.Polyline();
    var text = new graphic.Text();
    this.add(sector);
    this.add(polyline);
    this.add(text);

    this.updateData(data, idx, true);

    // Hover to change label and labelLine
    function onEmphasis() {
        polyline.ignore = polyline.hoverIgnore;
        text.ignore = text.hoverIgnore;
    }
    function onNormal() {
        polyline.ignore = polyline.normalIgnore;
        text.ignore = text.normalIgnore;
    }
    this.on('emphasis', onEmphasis)
        .on('normal', onNormal)
        .on('mouseover', onEmphasis)
        .on('mouseout', onNormal);
}

var piePieceProto = PiePiece.prototype;

piePieceProto.updateData = function (data, idx, firstCreate) {

    var sector = this.childAt(0);

    var seriesModel = data.hostModel;
    var itemModel = data.getItemModel(idx);
    var layout = data.getItemLayout(idx);
    var sectorShape = zrUtil.extend({}, layout);
    sectorShape.label = null;

    if (firstCreate) {
        sector.setShape(sectorShape);

        var animationType = seriesModel.getShallow('animationType');
        if (animationType === 'scale') {
            sector.shape.r = layout.r0;
            graphic.initProps(sector, {
                shape: {
                    r: layout.r
                }
            }, seriesModel, idx);
        }
        // Expansion
        else {
            sector.shape.endAngle = layout.startAngle;
            graphic.updateProps(sector, {
                shape: {
                    endAngle: layout.endAngle
                }
            }, seriesModel, idx);
        }

    }
    else {
        graphic.updateProps(sector, {
            shape: sectorShape
        }, seriesModel, idx);
    }

    // Update common style
    var visualColor = data.getItemVisual(idx, 'color');

    sector.useStyle(
        zrUtil.defaults(
            {
                lineJoin: 'bevel',
                fill: visualColor
            },
            itemModel.getModel('itemStyle').getItemStyle()
        )
    );
    sector.hoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();

    var cursorStyle = itemModel.getShallow('cursor');
    cursorStyle && sector.attr('cursor', cursorStyle);

    // Toggle selected
    toggleItemSelected(
        this,
        data.getItemLayout(idx),
        seriesModel.isSelected(null, idx),
        seriesModel.get('selectedOffset'),
        seriesModel.get('animation')
    );

    function onEmphasis() {
        // Sector may has animation of updating data. Force to move to the last frame
        // Or it may stopped on the wrong shape
        sector.stopAnimation(true);
        sector.animateTo({
            shape: {
                r: layout.r + seriesModel.get('hoverOffset')
            }
        }, 300, 'elasticOut');
    }
    function onNormal() {
        sector.stopAnimation(true);
        sector.animateTo({
            shape: {
                r: layout.r
            }
        }, 300, 'elasticOut');
    }
    sector.off('mouseover').off('mouseout').off('emphasis').off('normal');
    if (itemModel.get('hoverAnimation') && seriesModel.isAnimationEnabled()) {
        sector
            .on('mouseover', onEmphasis)
            .on('mouseout', onNormal)
            .on('emphasis', onEmphasis)
            .on('normal', onNormal);
    }

    this._updateLabel(data, idx);

    graphic.setHoverStyle(this);
};

piePieceProto._getFilterIgnore = function(data, idx) {
    var seriesModel = data.hostModel;
    var itemModel = data.getItemModel(idx);
    var valueDim = data.mapDimension('value');
    var sum = data.getSum(valueDim);
    var filterValue = seriesModel.get('labelDisplayThreshold');
    var filterIgnore = false;
    if (sum * filterValue.option > itemModel.option.value) {
        filterIgnore = true;
    }
    return filterIgnore;
}

piePieceProto._updateLabel = function(data, idx) {

    var labelLine = this.childAt(1);
    var labelText = this.childAt(2);

    var seriesModel = data.hostModel;
    var itemModel = data.getItemModel(idx);
    var layout = data.getItemLayout(idx);
    var labelLayout = layout.label;
    var visualColor = data.getItemVisual(idx, 'color');
    var filterIgnore = this._getFilterIgnore(data, idx);

    graphic.updateProps(labelLine, {
        shape: {
            points: labelLayout.linePoints || [
                [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y]
            ]
        }
    }, seriesModel, idx);

    graphic.updateProps(labelText, {
        style: {
            x: labelLayout.x,
            y: labelLayout.y
        }
    }, seriesModel, idx);
    labelText.attr({
        rotation: labelLayout.rotation,
        origin: [labelLayout.x, labelLayout.y],
        z2: 10
    });

    var labelModel = itemModel.getModel('label');
    var labelHoverModel = itemModel.getModel('emphasis.label');
    var labelLineModel = itemModel.getModel('labelLine');
    var labelLineHoverModel = itemModel.getModel('emphasis.labelLine');
    var visualColor = data.getItemVisual(idx, 'color');

    graphic.setLabelStyle(
        labelText.style, labelText.hoverStyle = {}, labelModel, labelHoverModel,
        {
            labelFetcher: data.hostModel,
            labelDataIndex: idx,
            defaultText: data.getName(idx),
            autoColor: visualColor,
            useInsideStyle: !!labelLayout.inside
        },
        {
            textAlign: labelLayout.textAlign,
            textVerticalAlign: labelLayout.verticalAlign,
            opacity: data.getItemVisual(idx, 'opacity')
        }
    );

    labelText.ignore = labelText.normalIgnore = !labelModel.get('show') || filterIgnore;
    labelText.hoverIgnore = !labelHoverModel.get('show') || filterIgnore;

    labelLine.ignore = labelLine.normalIgnore = !labelLineModel.get('show') || filterIgnore;
    labelLine.hoverIgnore = !labelLineHoverModel.get('show') || filterIgnore;

    // Default use item visual color
    labelLine.setStyle({
        stroke: visualColor,
        opacity: data.getItemVisual(idx, 'opacity')
    });
    labelLine.setStyle(labelLineModel.getModel('lineStyle').getLineStyle());

    labelLine.hoverStyle = labelLineHoverModel.getModel('lineStyle').getLineStyle();

    var smooth = labelLineModel.get('smooth');
    if (smooth && smooth === true) {
        smooth = 0.4;
    }
    labelLine.setShape({
        smooth: smooth
    });
};

zrUtil.inherits(PiePiece, graphic.Group);

// Pie view
var PieView = ChartView.extend({

    type: 'pie',

    init: function () {
        var sectorGroup = new graphic.Group();
        this._sectorGroup = sectorGroup;
    },

    render: function (seriesModel, ecModel, api, payload) {
        if (payload && (payload.from === this.uid)) {
            return;
        }

        var data = seriesModel.getData();
        var oldData = this._data;
        var group = this.group;

        var hasAnimation = ecModel.get('animation');
        var isFirstRender = !oldData;
        var animationType = seriesModel.get('animationType');

        var onSectorClick = zrUtil.curry(
            updateDataSelected, this.uid, seriesModel, hasAnimation, api
        );

        var selectedMode = seriesModel.get('selectedMode');

        data.diff(oldData)
            .add(function (idx) {
                var piePiece = new PiePiece(data, idx);
                // Default expansion animation
                if (isFirstRender && animationType !== 'scale') {
                    piePiece.eachChild(function (child) {
                        child.stopAnimation(true);
                    });
                }

                selectedMode && piePiece.on('click', onSectorClick);

                data.setItemGraphicEl(idx, piePiece);

                group.add(piePiece);
            })
            .update(function (newIdx, oldIdx) {
                var piePiece = oldData.getItemGraphicEl(oldIdx);

                piePiece.updateData(data, newIdx);

                piePiece.off('click');
                selectedMode && piePiece.on('click', onSectorClick);
                group.add(piePiece);
                data.setItemGraphicEl(newIdx, piePiece);
            })
            .remove(function (idx) {
                var piePiece = oldData.getItemGraphicEl(idx);
                group.remove(piePiece);
            })
            .execute();

        if (
            hasAnimation && isFirstRender && data.count() > 0
            // Default expansion animation
            && animationType !== 'scale'
        ) {
            var shape = data.getItemLayout(0);
            var r = Math.max(api.getWidth(), api.getHeight()) / 2;

            var removeClipPath = zrUtil.bind(group.removeClipPath, group);
            group.setClipPath(this._createClipPath(
                shape.cx, shape.cy, r, shape.startAngle, shape.clockwise, removeClipPath, seriesModel
            ));
        }

        this._data = data;
    },

    dispose: function () {},

    _createClipPath: function (
        cx, cy, r, startAngle, clockwise, cb, seriesModel
    ) {
        var clipPath = new graphic.Sector({
            shape: {
                cx: cx,
                cy: cy,
                r0: 0,
                r: r,
                startAngle: startAngle,
                endAngle: startAngle,
                clockwise: clockwise
            }
        });

        graphic.initProps(clipPath, {
            shape: {
                endAngle: startAngle + (clockwise ? 1 : -1) * Math.PI * 2
            }
        }, seriesModel, cb);

        return clipPath;
    },

    /**
     * @implement
     */
    containPoint: function (point, seriesModel) {
        var data = seriesModel.getData();
        var itemLayout = data.getItemLayout(0);
        if (itemLayout) {
            var dx = point[0] - itemLayout.cx;
            var dy = point[1] - itemLayout.cy;
            var radius = Math.sqrt(dx * dx + dy * dy);
            return radius <= itemLayout.r && radius >= itemLayout.r0;
        }
    }

});

export default PieView;
<|endoftext|>


<commit_before>var testcase_items = new Array();
var active = false;
var empty = true;
var tab_id = null;
console.log('init');
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  console.log(request);
  if (request.action == "append") {
    testcase_items[testcase_items.length] = request.obj;
    empty = false;
    sendResponse({});
  }
  if (request.action == "poke") {
    testcase_items[testcase_items.length - 1] = request.obj;
    sendResponse({});
  }
  if (request.action == "get_status") {
    sendResponse({'active': active, 'empty': empty});
  }
  if (request.action == "start") {
  	if(!active) {
  	    active = true;
  	    empty = true;
  	    testcase_items = new Array();
  	    tab_id = request.recorded_tab;
  	    chrome.tabs.update(tab_id, {url: request.start_url}, function(tab) {
          alert("Click OK to begin recording your automation flow");
          chrome.tabs.sendMessage(tab_id, {action: "open", 'url': request.start_url});
          sendResponse({start: true});
  	    });
  	}
  }
  if (request.action == "stop") {
    active = false;
    chrome.tabs.sendMessage(tab_id, {action: "stop"});
    sendResponse({});
  }
  if (request.action == "get_items") {
	sendResponse({'items': testcase_items});
  }
});<commit_msg>update chrome extension message<commit_after>var testcase_items = new Array();
var active = false;
var empty = true;
var tab_id = null;
console.log('init');
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  console.log(request);
  if (request.action == "append") {
    testcase_items[testcase_items.length] = request.obj;
    empty = false;
    sendResponse({});
  }
  if (request.action == "poke") {
    testcase_items[testcase_items.length - 1] = request.obj;
    sendResponse({});
  }
  if (request.action == "get_status") {
    sendResponse({'active': active, 'empty': empty});
  }
  if (request.action == "start") {
  	if(!active) {
  	    active = true;
  	    empty = true;
  	    testcase_items = new Array();
  	    tab_id = request.recorded_tab;
  	    chrome.tabs.update(tab_id, {url: request.start_url}, function(tab) {
          alert("Click OK to begin recording automation flow");
          chrome.tabs.sendMessage(tab_id, {action: "open", 'url': request.start_url});
          sendResponse({start: true});
  	    });
  	}
  }
  if (request.action == "stop") {
    active = false;
    chrome.tabs.sendMessage(tab_id, {action: "stop"});
    sendResponse({});
  }
  if (request.action == "get_items") {
	sendResponse({'items': testcase_items});
  }
});<|endoftext|>


<commit_before>import {PluginError} from 'gulp-util';
import through from 'through2';
import path from 'path';
import {spawn} from 'child_process';
import childProcessData from 'child-process-data';
import {InputStream, CommonTokenStream} from 'antlr4';
import {ParseTreeWalker} from 'antlr4/tree';

const PLUGIN_NAME = 'gulp-antlr4';

export default function (_options) {
  checkJava();

  const options = formatOptions(_options);
  const parserDir = getParserDir(options);
  const mode = getMode(options);
  const ANTLR4 = getClasses(options);

  return through.obj(function (file, encoding, callback) {
    if (file.isNull()) {
      return callback(null, file);
    }

    if (file.isStream()) {
      this.emit('error', new PluginError(PLUGIN_NAME,
        'Streams not supported (yet)!'));
    } else if (file.isBuffer()) {
      const inputFile = file.history[0];

      switch (path.extname(inputFile)) {
      case '.g4':
        const args = ['org.antlr.v4.Tool', '-Dlanguage=JavaScript', '-o',
          parserDir];
        if (mode === 'visitor' || mode === 'both') {
          args.push('-visitor');
        }
        if (mode !== 'listener' && mode !== 'both') {
          args.push('-no-listener');
        }
        args.push(inputFile);
        return childProcessData(spawn('java', args))
        .then(() => {
          callback(null, file);
        }, err => {
          this.emit('error', new PluginError(PLUGIN_NAME,
            new Error(err)));
        });

      default:
        if (ANTLR4.isProperlySetup()) {
          const data = file.contents.toString('utf8');
          const chars = new InputStream(data, true);
          const lexer = new ANTLR4.Lexer(chars);
          const tokens = new CommonTokenStream(lexer);
          const parser = new ANTLR4.Parser(tokens);
          parser.buildParseTrees = true;
          const tree = parser[ANTLR4.rule]();

          switch (mode) {
          case 'tree':
            console.log(tree.toStringTree(parser.ruleNames));
            break;

          case 'listener':
            const walker = new ParseTreeWalker();
            const listener = new ANTLR4.Listener();
            walker.walk(listener, tree);
            console.log('');
            break;

          case 'visitor':
            const visitor = new ANTLR4.Visitor();
            visitor.visit(tree);
            break;
          }
        }

        return callback(null, file);
      }
    }
  });
}

function checkJava () {
  const CLASSPATH = process.env.CLASSPATH;

  if (!CLASSPATH) {
    throw new PluginError(PLUGIN_NAME,
      new ReferenceError(`Environment variable CLASSPATH is not defined`));
  }

  // Not matching '~' as it is not understood by Java anyway
  const matchJar = CLASSPATH.match(
    /.*:((\d|\w|\/|-|_|\.)+antlr-\d+\.\d+-complete\.jar):.*/);

  if (matchJar === null) {
    throw new PluginError(PLUGIN_NAME,
      new ReferenceError(`Cannot find ANTLR 4 .jar file`));
  }
}

function formatOptions (options) {
  if (typeof options === 'string') {
    return {parserDir: options};
  }
  return typeof options === 'object' ? Object.assign({
    listenerDir: options.parserDir, // Default is same dir
    visitorDir: options.parserDir, // Default is same dir
  }, options) : {};
}

function getParserDir (options) {
  const {parserDir} = options;

  if (typeof parserDir !== 'string') {
    throw new PluginError(PLUGIN_NAME,
      new TypeError(`You must provide the directory where to write or read
     the generated lexing and parsing tools (option 'parserDir')`));
  }

  return parserDir;
}

function getMode (options) {
  const {mode, listener, visitor} = options;

  if (typeof mode !== 'string' && mode !== undefined) {
    throw new PluginError(PLUGIN_NAME,
      new TypeError(`Bad option: ${mode}`));
  }

  if (listener && visitor) {
    return 'both';
  }

  if (listener) {
    return 'listener';
  }

  if (visitor) {
    return 'visitor';
  }

  return mode || 'listener';
}

function getClasses (options) {
  const {grammar} = options;

  if (!grammar) {
    return {
      isProperlySetup () {
        return false;
      },
    };
  }

  return {
    rule: getRule(options),
    Lexer: getLexer(options),
    Parser: getParser(options),
    Listener: getListener(options),
    Visitor: getVisitor(options),
    isProperlySetup () {
      return true;
    },
  };
}

function getRule (options) {
  const {rule} = options;

  if (!rule) {
    throw new PluginError(PLUGIN_NAME,
      `Undefined starting rule (option 'rule')`);
  }

  return rule;
}

function getLexer (options) {
  const {grammar, parserDir} = options;
  const lexer = `${grammar}Lexer`;

  // Convert relative to absolute path
  const base = process.cwd();
  const rel = path.relative(base, parserDir);
  return require(path.join(base, rel, lexer))[lexer];
}

function getParser (options) {
  const {grammar, parserDir} = options;
  const parser = `${grammar}Parser`;

  // Convert relative to absolute path
  const base = process.cwd();
  const rel = path.relative(base, parserDir);
  return require(path.join(base, rel, parser))[parser];
}

function getListener (options) {
  const {listener, listenerDir} = options;

  if (!listener) {
    return;
  }

  // Convert relative to absolute path
  const base = process.cwd();
  const rel = path.relative(base, listenerDir);
  return require(path.join(base, rel, listener))[listener];
}

function getVisitor (options) {
  const {visitor, visitorDir} = options;

  if (!visitor) {
    return;
  }

  // Convert relative to absolute path
  const base = process.cwd();
  const rel = path.relative(base, visitorDir);
  return require(path.join(base, rel, visitor))[visitor];
}
<commit_msg>Improved error messages in chackJava()<commit_after>import {PluginError} from 'gulp-util';
import through from 'through2';
import path from 'path';
import {spawn} from 'child_process';
import childProcessData from 'child-process-data';
import {InputStream, CommonTokenStream} from 'antlr4';
import {ParseTreeWalker} from 'antlr4/tree';

const PLUGIN_NAME = 'gulp-antlr4';

export default function (_options) {
  checkJava();

  const options = formatOptions(_options);
  const parserDir = getParserDir(options);
  const mode = getMode(options);
  const ANTLR4 = getClasses(options);

  return through.obj(function (file, encoding, callback) {
    if (file.isNull()) {
      return callback(null, file);
    }

    if (file.isStream()) {
      this.emit('error', new PluginError(PLUGIN_NAME,
        'Streams not supported (yet)!'));
    } else if (file.isBuffer()) {
      const inputFile = file.history[0];

      switch (path.extname(inputFile)) {
      case '.g4':
        const args = ['org.antlr.v4.Tool', '-Dlanguage=JavaScript', '-o',
          parserDir];
        if (mode === 'visitor' || mode === 'both') {
          args.push('-visitor');
        }
        if (mode !== 'listener' && mode !== 'both') {
          args.push('-no-listener');
        }
        args.push(inputFile);
        return childProcessData(spawn('java', args))
        .then(() => {
          callback(null, file);
        }, err => {
          this.emit('error', new PluginError(PLUGIN_NAME,
            new Error(err)));
        });

      default:
        if (ANTLR4.isProperlySetup()) {
          const data = file.contents.toString('utf8');
          const chars = new InputStream(data, true);
          const lexer = new ANTLR4.Lexer(chars);
          const tokens = new CommonTokenStream(lexer);
          const parser = new ANTLR4.Parser(tokens);
          parser.buildParseTrees = true;
          const tree = parser[ANTLR4.rule]();

          switch (mode) {
          case 'tree':
            console.log(tree.toStringTree(parser.ruleNames));
            break;

          case 'listener':
            const walker = new ParseTreeWalker();
            const listener = new ANTLR4.Listener();
            walker.walk(listener, tree);
            console.log('');
            break;

          case 'visitor':
            const visitor = new ANTLR4.Visitor();
            visitor.visit(tree);
            break;
          }
        }

        return callback(null, file);
      }
    }
  });
}

function checkJava () {
  const CLASSPATH = process.env.CLASSPATH;

  if (!CLASSPATH) {
    throw new PluginError(PLUGIN_NAME,
      new ReferenceError(`Environment variable CLASSPATH is not defined;
Java is not installed or is improperly set`));
  }

  // Not matching '~' as it is not understood by Java anyway
  const matchJar = CLASSPATH.match(
    /.*:((\d|\w|\/|-|_|\.)+antlr-\d+\.\d+-complete\.jar):.*/);

  if (matchJar === null) {
    throw new PluginError(PLUGIN_NAME,
      new ReferenceError(`Cannot find ANTLR4 .jar file;
It should appear in your CLASSPATH`));
  }
}

function formatOptions (options) {
  if (typeof options === 'string') {
    return {parserDir: options};
  }
  return typeof options === 'object' ? Object.assign({
    listenerDir: options.parserDir, // Default is same dir
    visitorDir: options.parserDir, // Default is same dir
  }, options) : {};
}

function getParserDir (options) {
  const {parserDir} = options;

  if (typeof parserDir !== 'string') {
    throw new PluginError(PLUGIN_NAME,
      new TypeError(`You must provide the directory where to write or read
     the generated lexing and parsing tools (option 'parserDir')`));
  }

  return parserDir;
}

function getMode (options) {
  const {mode, listener, visitor} = options;

  if (typeof mode !== 'string' && mode !== undefined) {
    throw new PluginError(PLUGIN_NAME,
      new TypeError(`Bad option: ${mode}`));
  }

  if (listener && visitor) {
    return 'both';
  }

  if (listener) {
    return 'listener';
  }

  if (visitor) {
    return 'visitor';
  }

  return mode || 'listener';
}

function getClasses (options) {
  const {grammar} = options;

  if (!grammar) {
    return {
      isProperlySetup () {
        return false;
      },
    };
  }

  return {
    rule: getRule(options),
    Lexer: getLexer(options),
    Parser: getParser(options),
    Listener: getListener(options),
    Visitor: getVisitor(options),
    isProperlySetup () {
      return true;
    },
  };
}

function getRule (options) {
  const {rule} = options;

  if (!rule) {
    throw new PluginError(PLUGIN_NAME,
      `Undefined starting rule (option 'rule')`);
  }

  return rule;
}

function getLexer (options) {
  const {grammar, parserDir} = options;
  const lexer = `${grammar}Lexer`;

  // Convert relative to absolute path
  const base = process.cwd();
  const rel = path.relative(base, parserDir);
  return require(path.join(base, rel, lexer))[lexer];
}

function getParser (options) {
  const {grammar, parserDir} = options;
  const parser = `${grammar}Parser`;

  // Convert relative to absolute path
  const base = process.cwd();
  const rel = path.relative(base, parserDir);
  return require(path.join(base, rel, parser))[parser];
}

function getListener (options) {
  const {listener, listenerDir} = options;

  if (!listener) {
    return;
  }

  // Convert relative to absolute path
  const base = process.cwd();
  const rel = path.relative(base, listenerDir);
  return require(path.join(base, rel, listener))[listener];
}

function getVisitor (options) {
  const {visitor, visitorDir} = options;

  if (!visitor) {
    return;
  }

  // Convert relative to absolute path
  const base = process.cwd();
  const rel = path.relative(base, visitorDir);
  return require(path.join(base, rel, visitor))[visitor];
}
<|endoftext|>