<commit_before>/*global Tile */
import {Geo} from './geo';
import {StyleParser} from './styles/style_parser';
import WorkerBroker from './worker_broker';

import log from 'loglevel';

export default class Tile {

    /**
        Tile
        @constructor
        Required properties:
        coords: object with {x, y, z} properties identifying tile coordinate location
        worker: web worker to handle tile construction
    */
    constructor({ coords, worker, max_zoom }) {
        Object.assign(this, {
            coords: {
                x: null,
                y: null,
                z: null
            },
            debug: {},
            loading: false,
            loaded: false,
            error: null,
            worker: null,
            order: {
                min: Infinity,
                max: -Infinity
            }
        });

        this.coords = coords;
        this.worker = worker;
        this.max_zoom = max_zoom;

        this.coords = this.calculateOverZoom();
        this.key = [this.coords.x, this.coords.y, this.coords.z].join('/');
    }

    static create(spec) { return new Tile(spec); }

    freeResources() {
        if (this != null && this.gl_geometry != null) {
            for (var p in this.gl_geometry) {
                this.gl_geometry[p].destroy();
            }
            this.gl_geometry = null;
        }
    }

    destroy() {
        this.freeResources();
        this.worker = null;
    }

    buildAsMessage() {
        return {
            key: this.key,
            coords: this.coords,
            min: this.min,
            max: this.max,
            order: this.order,
            debug: this.debug
        };
    }

    workerMessage (...message) {
        return WorkerBroker.postMessage(this.worker, ...message);
    }

    // TODO: remove scene dependency
    build(scene) {
        scene.trackTileBuildStart(this.key);
        this.workerMessage(
            'buildTile',
            { tile: this.buildAsMessage() })
        .then(message => {
            scene.buildTileCompleted(message);
        }).catch(error => {
            throw error;
        });
    }

    // Process geometry for tile - called by web worker
    // Returns a set of tile keys that should be sent to the main thread (so that we can minimize data exchange between worker and main thread)
    static buildGeometry (tile, layers, rules, styles) {
        var feature, style, feature_style;
        var vertex_data = {};
        var style_vertex_data;

        tile.debug.rendering = +new Date();

        for (let sourceName in tile.sources) {
            let source = tile.sources[sourceName];

            source.debug.rendering = +new Date();
            source.debug.features = 0;

            // Treat top-level style rules as 'layers'
            for (var name in layers) {
                let layer = layers[name];
                // Skip layers with no geometry defined
                if (!layer.geometry) {
                    log.warn(`Layer ${layer} was defined without an geometry configuration and will not be rendered.`);
                    continue;
                }

                var geom = Tile.getGeometryForSource(source, layer.geometry);

                if (!geom) {
                    continue;
                }

                var num_features = geom.features.length;

                // Render features within each layer, in reverse order - aka top to bottom
                for (var f = num_features-1; f >= 0; f--) {
                    feature = geom.features[f];

                    feature.layer = name;

                    var context = StyleParser.getFeatureParseContext(feature, tile);
                    // Find matching rules
                    var matchedRules = [];
                    var layer_rules = rules[name];
                    for (var r in layer_rules) {
                        layer_rules[r].matchFeature(context, matchedRules);
                    }

                    // Parse & render styles
                    for (var rule of matchedRules) {
                        if (!rule.visible) {
                            continue;
                        }

                        // Parse style
                        rule.name = rule.name || StyleParser.defaults.style.name;
                        style = styles[rule.name];
                        feature_style = style.parseFeature(feature, rule, context);

                        // Skip feature?
                        if (!feature_style) {
                            continue;
                        }

                        // Track min/max order range
                        if (feature_style.order < tile.order.min) {
                            tile.order.min = feature_style.order;
                        }
                        if (feature_style.order > tile.order.max) {
                            tile.order.max = feature_style.order;
                        }

                        // First feature in this render style?
                        if (vertex_data[style.name] == null) {
                            vertex_data[style.name] = style.vertex_layout.createVertexData();
                        }
                        style_vertex_data = vertex_data[style.name];

                        // Layer order: 'order' property between [-1, 1] adjusts render order of features *within* this layer
                        // Does not affect order outside of this layer, e.g. all features on previous layers are drawn underneath
                        //  this one, all features on subsequent layers are drawn on top of this one
                        // feature_style.layer = (layer.geometry.order || 0) + 0.5;      // 'center' this layer at 0.5 above the baseline
                        // feature_style.layer += feature_style.order / 2.5;   // scale [-1, 1] to [-.4, .4] to stay within layer bounds, .1 buffer to be safe
                        feature_style.layer = feature_style.order;

                        if (feature.geometry.type === 'Polygon') {
                            style.buildPolygons([feature.geometry.coordinates], feature_style, style_vertex_data);
                        }
                        else if (feature.geometry.type === 'MultiPolygon') {
                            style.buildPolygons(feature.geometry.coordinates, feature_style, style_vertex_data);
                        }
                        else if (feature.geometry.type === 'LineString') {
                            style.buildLines([feature.geometry.coordinates], feature_style, style_vertex_data);
                        }
                        else if (feature.geometry.type === 'MultiLineString') {
                            style.buildLines(feature.geometry.coordinates, feature_style, style_vertex_data);
                        }
                        else if (feature.geometry.type === 'Point') {
                            style.buildPoints([feature.geometry.coordinates], feature_style, style_vertex_data);
                        }
                        else if (feature.geometry.type === 'MultiPoint') {
                            style.buildPoints(feature.geometry.coordinates, feature_style, style_vertex_data);
                        }
                    }

                    source.debug.features++;
                }

            }

            source.debug.rendering = +new Date() - source.debug.rendering;
        }

        // Finalize array buffer for each render style
        tile.vertex_data = {};
        for (var m in vertex_data) {
            tile.vertex_data[m] = vertex_data[m].end().buffer;
        }

        tile.debug.rendering = +new Date() - tile.debug.rendering;
        tile.debug.projection = 0;
        tile.debug.features = 0;
        tile.debug.network = 0;
        tile.debug.parsing = 0;

        for (let i in tile.sources) {
            tile.debug.features  += tile.sources[i].debug.features;
            tile.debug.projection += tile.sources[i].debug.projection;
            tile.debug.network += tile.sources[i].debug.network;
            tile.debug.parsing += tile.sources[i].debug.parsing;
        }

        // Return keys to be transfered to main thread
        return {
            vertex_data: true
        };
    }

    /**
        Retrieves geometry from a tile according to a data source definition
    */
    static getGeometryForSource (sourceData, sourceConfig) {
        var geom;

        if (sourceConfig != null) {
            // Just pass through data untouched if no data transform function defined
            // if (!source.filter) {
            //     geom = tile.layers[source.filter];
            // }
            // Pass through data but with different layer name in tile source data
            /*else*/ if (typeof sourceConfig.filter === 'string') {
                geom = sourceData.layers[sourceConfig.filter];
            }
            // Apply the transform function for post-processing
            else if (typeof sourceConfig.filter === 'function') {
                geom = sourceConfig.filter(sourceData.layers);
            }
        }

        return geom;
    }

    /**
       Called on main thread when a web worker completes processing
       for a single tile.
    */
    finalizeGeometry(styles) {
        var vertex_data = this.vertex_data;
        // Cleanup existing GL geometry objects
        this.freeResources();
        this.gl_geometry = {};

        // Create GL geometry objects
        for (var s in vertex_data) {
            this.gl_geometry[s] = styles[s].makeGLGeometry(vertex_data[s]);
        }

        this.debug.geometries = 0;
        this.debug.buffer_size = 0;
        for (var p in this.gl_geometry) {
            this.debug.geometries += this.gl_geometry[p].geometry_count;
            this.debug.buffer_size += this.gl_geometry[p].vertex_data.byteLength;
        }
        this.debug.geom_ratio = (this.debug.geometries / this.debug.features).toFixed(1);

        delete this.vertex_data; // TODO: might want to preserve this for rebuilding geometries when styles/etc. change?
    }

    remove() {
        this.workerMessage('removeTile', this.key);
    }

    showDebug(div) {
        var debug_overlay = document.createElement('div');
        debug_overlay.textContent = this.key;
        debug_overlay.style.position = 'absolute';
        debug_overlay.style.left = 0;
        debug_overlay.style.top = 0;
        debug_overlay.style.color = 'white';
        debug_overlay.style.fontSize = '16px';
        debug_overlay.style.textOutline = '1px #000000';
        div.appendChild(debug_overlay);
        div.style.borderStyle = 'solid';
        div.style.borderColor = 'white';
        div.style.borderWidth = '1px';
        return debug_overlay;
    }

    printDebug () {
        log.debug(`Tile: debug for ${this.key}: [  ${JSON.stringify(this.debug)} ]`);
    }

    updateDebugElement(div, show) {
        div.setAttribute('data-tile-key', this.key);
        div.style.width = '256px';
        div.style.height = '256px';

        if (show) {
            this.showDebug(div);
        }
    }

    update(scene) {
        this.visible =  (this.coords.z === Math.round(scene.zoom)) ||
                        (this.coords.z === this.max_zoom && scene.zoom >= this.max_zoom);

        this.center_dist = Math.abs(scene.center_meters.x - this.min.x) + Math.abs(scene.center_meters.y - this.min.y);
    }

    calculateOverZoom() {
        var zgap,
            {x, y, z} = this.coords;

        if (z > this.max_zoom) {
            zgap = z - this.max_zoom;
            x = ~~(x / Math.pow(2, zgap));
            y = ~~(y / Math.pow(2, zgap));
            z -= zgap;
        }

        return {x, y, z};
    }

    load(scene) {
        scene.trackTileSetLoadStart();

        this.min = Geo.metersForTile(this.coords);
        this.max = Geo.metersForTile({x: this.coords.x + 1, y: this.coords.y + 1, z: this.coords.z }),
        this.span = { x: (this.max.x - this.min.x), y: (this.max.y - this.min.y) };
        this.bounds = { sw: { x: this.min.x, y: this.max.y }, ne: { x: this.max.x, y: this.min.y } };
        this.loading = true;

        this.build(scene);
        this.update(scene);
    }

    merge(other) {
        for (var key in other) {
            if (key !== 'key') {
                this[key] = other[key];
            }
        }
        return this;
    }

}
<commit_msg>tile: calc min/max/etc. earlier<commit_after>/*global Tile */
import {Geo} from './geo';
import {StyleParser} from './styles/style_parser';
import WorkerBroker from './worker_broker';

import log from 'loglevel';

export default class Tile {

    /**
        Tile
        @constructor
        Required properties:
        coords: object with {x, y, z} properties identifying tile coordinate location
        worker: web worker to handle tile construction
    */
    constructor({ coords, worker, max_zoom }) {
        Object.assign(this, {
            coords: {
                x: null,
                y: null,
                z: null
            },
            debug: {},
            loading: false,
            loaded: false,
            error: null,
            worker: null,
            order: {
                min: Infinity,
                max: -Infinity
            }
        });

        this.coords = coords;
        this.coords = this.calculateOverZoom();
        this.key = [this.coords.x, this.coords.y, this.coords.z].join('/');
        this.min = Geo.metersForTile(this.coords);
        this.max = Geo.metersForTile({x: this.coords.x + 1, y: this.coords.y + 1, z: this.coords.z }),
        this.span = { x: (this.max.x - this.min.x), y: (this.max.y - this.min.y) };
        this.bounds = { sw: { x: this.min.x, y: this.max.y }, ne: { x: this.max.x, y: this.min.y } };

        this.worker = worker;
        this.max_zoom = max_zoom;
    }

    static create(spec) { return new Tile(spec); }

    freeResources() {
        if (this != null && this.gl_geometry != null) {
            for (var p in this.gl_geometry) {
                this.gl_geometry[p].destroy();
            }
            this.gl_geometry = null;
        }
    }

    destroy() {
        this.freeResources();
        this.worker = null;
    }

    buildAsMessage() {
        return {
            key: this.key,
            coords: this.coords,
            min: this.min,
            max: this.max,
            order: this.order,
            debug: this.debug
        };
    }

    workerMessage (...message) {
        return WorkerBroker.postMessage(this.worker, ...message);
    }

    // TODO: remove scene dependency
    build(scene) {
        scene.trackTileBuildStart(this.key);
        this.workerMessage(
            'buildTile',
            { tile: this.buildAsMessage() })
        .then(message => {
            scene.buildTileCompleted(message);
        }).catch(error => {
            throw error;
        });
    }

    // Process geometry for tile - called by web worker
    // Returns a set of tile keys that should be sent to the main thread (so that we can minimize data exchange between worker and main thread)
    static buildGeometry (tile, layers, rules, styles) {
        var feature, style, feature_style;
        var vertex_data = {};
        var style_vertex_data;

        tile.debug.rendering = +new Date();

        for (let sourceName in tile.sources) {
            let source = tile.sources[sourceName];

            source.debug.rendering = +new Date();
            source.debug.features = 0;

            // Treat top-level style rules as 'layers'
            for (var name in layers) {
                let layer = layers[name];
                // Skip layers with no geometry defined
                if (!layer.geometry) {
                    log.warn(`Layer ${layer} was defined without an geometry configuration and will not be rendered.`);
                    continue;
                }

                var geom = Tile.getGeometryForSource(source, layer.geometry);

                if (!geom) {
                    continue;
                }

                var num_features = geom.features.length;

                // Render features within each layer, in reverse order - aka top to bottom
                for (var f = num_features-1; f >= 0; f--) {
                    feature = geom.features[f];

                    feature.layer = name;

                    var context = StyleParser.getFeatureParseContext(feature, tile);
                    // Find matching rules
                    var matchedRules = [];
                    var layer_rules = rules[name];
                    for (var r in layer_rules) {
                        layer_rules[r].matchFeature(context, matchedRules);
                    }

                    // Parse & render styles
                    for (var rule of matchedRules) {
                        if (!rule.visible) {
                            continue;
                        }

                        // Parse style
                        rule.name = rule.name || StyleParser.defaults.style.name;
                        style = styles[rule.name];
                        feature_style = style.parseFeature(feature, rule, context);

                        // Skip feature?
                        if (!feature_style) {
                            continue;
                        }

                        // Track min/max order range
                        if (feature_style.order < tile.order.min) {
                            tile.order.min = feature_style.order;
                        }
                        if (feature_style.order > tile.order.max) {
                            tile.order.max = feature_style.order;
                        }

                        // First feature in this render style?
                        if (vertex_data[style.name] == null) {
                            vertex_data[style.name] = style.vertex_layout.createVertexData();
                        }
                        style_vertex_data = vertex_data[style.name];

                        // Layer order: 'order' property between [-1, 1] adjusts render order of features *within* this layer
                        // Does not affect order outside of this layer, e.g. all features on previous layers are drawn underneath
                        //  this one, all features on subsequent layers are drawn on top of this one
                        // feature_style.layer = (layer.geometry.order || 0) + 0.5;      // 'center' this layer at 0.5 above the baseline
                        // feature_style.layer += feature_style.order / 2.5;   // scale [-1, 1] to [-.4, .4] to stay within layer bounds, .1 buffer to be safe
                        feature_style.layer = feature_style.order;

                        if (feature.geometry.type === 'Polygon') {
                            style.buildPolygons([feature.geometry.coordinates], feature_style, style_vertex_data);
                        }
                        else if (feature.geometry.type === 'MultiPolygon') {
                            style.buildPolygons(feature.geometry.coordinates, feature_style, style_vertex_data);
                        }
                        else if (feature.geometry.type === 'LineString') {
                            style.buildLines([feature.geometry.coordinates], feature_style, style_vertex_data);
                        }
                        else if (feature.geometry.type === 'MultiLineString') {
                            style.buildLines(feature.geometry.coordinates, feature_style, style_vertex_data);
                        }
                        else if (feature.geometry.type === 'Point') {
                            style.buildPoints([feature.geometry.coordinates], feature_style, style_vertex_data);
                        }
                        else if (feature.geometry.type === 'MultiPoint') {
                            style.buildPoints(feature.geometry.coordinates, feature_style, style_vertex_data);
                        }
                    }

                    source.debug.features++;
                }

            }

            source.debug.rendering = +new Date() - source.debug.rendering;
        }

        // Finalize array buffer for each render style
        tile.vertex_data = {};
        for (var m in vertex_data) {
            tile.vertex_data[m] = vertex_data[m].end().buffer;
        }

        tile.debug.rendering = +new Date() - tile.debug.rendering;
        tile.debug.projection = 0;
        tile.debug.features = 0;
        tile.debug.network = 0;
        tile.debug.parsing = 0;

        for (let i in tile.sources) {
            tile.debug.features  += tile.sources[i].debug.features;
            tile.debug.projection += tile.sources[i].debug.projection;
            tile.debug.network += tile.sources[i].debug.network;
            tile.debug.parsing += tile.sources[i].debug.parsing;
        }

        // Return keys to be transfered to main thread
        return {
            vertex_data: true
        };
    }

    /**
        Retrieves geometry from a tile according to a data source definition
    */
    static getGeometryForSource (sourceData, sourceConfig) {
        var geom;

        if (sourceConfig != null) {
            // Just pass through data untouched if no data transform function defined
            // if (!source.filter) {
            //     geom = tile.layers[source.filter];
            // }
            // Pass through data but with different layer name in tile source data
            /*else*/ if (typeof sourceConfig.filter === 'string') {
                geom = sourceData.layers[sourceConfig.filter];
            }
            // Apply the transform function for post-processing
            else if (typeof sourceConfig.filter === 'function') {
                geom = sourceConfig.filter(sourceData.layers);
            }
        }

        return geom;
    }

    /**
       Called on main thread when a web worker completes processing
       for a single tile.
    */
    finalizeGeometry(styles) {
        var vertex_data = this.vertex_data;
        // Cleanup existing GL geometry objects
        this.freeResources();
        this.gl_geometry = {};

        // Create GL geometry objects
        for (var s in vertex_data) {
            this.gl_geometry[s] = styles[s].makeGLGeometry(vertex_data[s]);
        }

        this.debug.geometries = 0;
        this.debug.buffer_size = 0;
        for (var p in this.gl_geometry) {
            this.debug.geometries += this.gl_geometry[p].geometry_count;
            this.debug.buffer_size += this.gl_geometry[p].vertex_data.byteLength;
        }
        this.debug.geom_ratio = (this.debug.geometries / this.debug.features).toFixed(1);

        delete this.vertex_data; // TODO: might want to preserve this for rebuilding geometries when styles/etc. change?
    }

    remove() {
        this.workerMessage('removeTile', this.key);
    }

    showDebug(div) {
        var debug_overlay = document.createElement('div');
        debug_overlay.textContent = this.key;
        debug_overlay.style.position = 'absolute';
        debug_overlay.style.left = 0;
        debug_overlay.style.top = 0;
        debug_overlay.style.color = 'white';
        debug_overlay.style.fontSize = '16px';
        debug_overlay.style.textOutline = '1px #000000';
        div.appendChild(debug_overlay);
        div.style.borderStyle = 'solid';
        div.style.borderColor = 'white';
        div.style.borderWidth = '1px';
        return debug_overlay;
    }

    printDebug () {
        log.debug(`Tile: debug for ${this.key}: [  ${JSON.stringify(this.debug)} ]`);
    }

    updateDebugElement(div, show) {
        div.setAttribute('data-tile-key', this.key);
        div.style.width = '256px';
        div.style.height = '256px';

        if (show) {
            this.showDebug(div);
        }
    }

    update(scene) {
        this.visible =  (this.coords.z === Math.round(scene.zoom)) ||
                        (this.coords.z === this.max_zoom && scene.zoom >= this.max_zoom);

        this.center_dist = Math.abs(scene.center_meters.x - this.min.x) + Math.abs(scene.center_meters.y - this.min.y);
    }

    calculateOverZoom() {
        var zgap,
            {x, y, z} = this.coords;

        if (z > this.max_zoom) {
            zgap = z - this.max_zoom;
            x = ~~(x / Math.pow(2, zgap));
            y = ~~(y / Math.pow(2, zgap));
            z -= zgap;
        }

        return {x, y, z};
    }

    load(scene) {
        scene.trackTileSetLoadStart();

        this.loading = true;
        this.build(scene);
        this.update(scene);
    }

    merge(other) {
        for (var key in other) {
            if (key !== 'key') {
                this[key] = other[key];
            }
        }
        return this;
    }

}
<|endoftext|>


<commit_before>"use strict";
var ASSERT = require("./assert");
var es5 = require("./es5");
// Assume CSP if browser
var canEvaluate = typeof navigator == "undefined";

//Try catch is not supported in optimizing
//compiler, so it is isolated
var errorObj = {e: {}};
var tryCatchTarget;
var globalObject = typeof self !== "undefined" ? self :
    typeof window !== "undefined" ? window :
    typeof global !== "undefined" ? global :
    this !== undefined ? this : null;

function tryCatcher() {
    try {
        var target = tryCatchTarget;
        tryCatchTarget = null;
        return target.apply(this, arguments);
    } catch (e) {
        errorObj.e = e;
        return errorObj;
    }
}
function tryCatch(fn) {
    ASSERT(typeof fn === "function");
    tryCatchTarget = fn;
    return tryCatcher;
}

//Un-magical enough that using this doesn't prevent
//extending classes from outside using any convention
var inherits = function(Child, Parent) {
    var hasProp = {}.hasOwnProperty;

    function T() {
        this.constructor = Child;
        this.constructor$ = Parent;
        for (var propertyName in Parent.prototype) {
            if (hasProp.call(Parent.prototype, propertyName) &&
                propertyName.charAt(propertyName.length-1) !== "$"
           ) {
                this[propertyName + "$"] = Parent.prototype[propertyName];
            }
        }
    }
    T.prototype = Parent.prototype;
    Child.prototype = new T();
    return Child.prototype;
};

function isPrimitive(val) {
    return val == null || val === true || val === false ||
        typeof val === "string" || typeof val === "number";

}

function isObject(value) {
    return typeof value === "function" ||
           typeof value === "object" && value !== null;
}

function maybeWrapAsError(maybeError) {
    if (!isPrimitive(maybeError)) return maybeError;

    return new Error(safeToString(maybeError));
}

function withAppended(target, appendee) {
    var len = target.length;
    var ret = new Array(len + 1);
    var i;
    for (i = 0; i < len; ++i) {
        ret[i] = target[i];
    }
    ret[i] = appendee;
    return ret;
}

function getDataPropertyOrDefault(obj, key, defaultValue) {
    if (es5.isES5) {
        var desc = Object.getOwnPropertyDescriptor(obj, key);

        if (desc != null) {
            return desc.get == null && desc.set == null
                    ? desc.value
                    : defaultValue;
        }
    } else {
        return {}.hasOwnProperty.call(obj, key) ? obj[key] : undefined;
    }
}

function notEnumerableProp(obj, name, value) {
    if (isPrimitive(obj)) return obj;
    var descriptor = {
        value: value,
        configurable: true,
        enumerable: false,
        writable: true
    };
    es5.defineProperty(obj, name, descriptor);
    return obj;
}

function thrower(r) {
    throw r;
}

var inheritedDataKeys = (function() {
    var excludedPrototypes = [
        Array.prototype,
        Object.prototype,
        Function.prototype
    ];

    var isExcludedProto = function(val) {
        for (var i = 0; i < excludedPrototypes.length; ++i) {
            if (excludedPrototypes[i] === val) {
                return true;
            }
        }
        return false;
    };

    if (es5.isES5) {
        var getKeys = Object.getOwnPropertyNames;
        return function(obj) {
            var ret = [];
            var visitedKeys = Object.create(null);
            while (obj != null && !isExcludedProto(obj)) {
                var keys;
                try {
                    keys = getKeys(obj);
                } catch (e) {
                    return ret;
                }
                for (var i = 0; i < keys.length; ++i) {
                    var key = keys[i];
                    if (visitedKeys[key]) continue;
                    visitedKeys[key] = true;
                    var desc = Object.getOwnPropertyDescriptor(obj, key);
                    if (desc != null && desc.get == null && desc.set == null) {
                        ret.push(key);
                    }
                }
                obj = es5.getPrototypeOf(obj);
            }
            return ret;
        };
    } else {
        var hasProp = {}.hasOwnProperty;
        return function(obj) {
            if (isExcludedProto(obj)) return [];
            var ret = [];

            /*jshint forin:false */
            enumeration: for (var key in obj) {
                if (hasProp.call(obj, key)) {
                    ret.push(key);
                } else {
                    for (var i = 0; i < excludedPrototypes.length; ++i) {
                        if (hasProp.call(excludedPrototypes[i], key)) {
                            continue enumeration;
                        }
                    }
                    ret.push(key);
                }
            }
            return ret;
        };
    }

})();

var thisAssignmentPattern = /this\s*\.\s*\S+\s*=/;
function isClass(fn) {
    try {
        if (typeof fn === "function") {
            var keys = es5.names(fn.prototype);

            var hasMethods = es5.isES5 && keys.length > 1;
            var hasMethodsOtherThanConstructor = keys.length > 0 &&
                !(keys.length === 1 && keys[0] === "constructor");
            var hasThisAssignmentAndStaticMethods =
                thisAssignmentPattern.test(String(fn))
                    && es5.names(fn).length > 0;

            if (hasMethods || hasMethodsOtherThanConstructor ||
                hasThisAssignmentAndStaticMethods) {
                return true;
            }
        }
        return false;
    } catch (e) {
        return false;
    }
}

function toFastProperties(obj) {
    /*jshint -W027,-W055,-W031*/
    function FakeConstructor() {}
    FakeConstructor.prototype = obj;
    var receiver = new FakeConstructor();
    function ic() {
        return typeof receiver.foo;
    }
    ic();
    ic();
    ASSERT("%HasFastProperties", true, obj);
    return obj;
    // Prevent the function from being optimized through dead code elimination
    // or further optimizations. This code is never reached but even using eval
    // in unreachable code causes v8 to not optimize functions.
    eval(obj);
}

var rident = /^[a-z$_][a-z$_0-9]*$/i;
function isIdentifier(str) {
    return rident.test(str);
}

function filledRange(count, prefix, suffix) {
    var ret = new Array(count);
    for(var i = 0; i < count; ++i) {
        ret[i] = prefix + i + suffix;
    }
    return ret;
}

function safeToString(obj) {
    try {
        return String(obj);
    } catch (e) {
        return "[no string representation]";
    }
}

function isError(obj) {
    return obj instanceof Error ||
        (obj !== null &&
           typeof obj === "object" &&
           typeof obj.message === "string" &&
           typeof obj.name === "string");
}

function markAsOriginatingFromRejection(e) {
    try {
        notEnumerableProp(e, OPERATIONAL_ERROR_KEY, true);
    }
    catch(ignore) {}
}

function originatesFromRejection(e) {
    if (e == null) return false;
    return ((e instanceof Error[BLUEBIRD_ERRORS].OperationalError) ||
        e[OPERATIONAL_ERROR_KEY] === true);
}

function canAttachTrace(obj) {
    return isError(obj) && es5.propertyIsWritable(obj, "stack");
}

var ensureErrorObject = (function() {
    if (!("stack" in new Error())) {
        return function(value) {
            if (canAttachTrace(value)) return value;
            try {throw new Error(safeToString(value));}
            catch(err) {return err;}
        };
    } else {
        return function(value) {
            if (canAttachTrace(value)) return value;
            return new Error(safeToString(value));
        };
    }
})();

function classString(obj) {
    return {}.toString.call(obj);
}

function copyDescriptors(from, to, filter) {
    var keys = es5.names(from);
    for (var i = 0; i < keys.length; ++i) {
        var key = keys[i];
        if (filter(key)) {
            try {
                es5.defineProperty(to, key, es5.getDescriptor(from, key));
            } catch (ignore) {}
        }
    }
}

var asArray = function(v) {
    if (es5.isArray(v)) {
        return v;
    }
    return null;
};

if (typeof Symbol !== "undefined" && Symbol.iterator) {
    var ArrayFrom = typeof Array.from === "function" ? function(v) {
        return Array.from(v);
    } : function(v) {
        var ret = [];
        var it = v[Symbol.iterator]();
        var itResult;
        while (!((itResult = it.next()).done)) {
            ret.push(itResult.value);
        }
        return ret;
    };

    asArray = function(v) {
        if (es5.isArray(v)) {
            return v;
        } else if (v != null && typeof v[Symbol.iterator] === "function") {
            return ArrayFrom(v);
        }
        return null;
    };
}

var isNode = typeof process !== "undefined" &&
        classString(process).toLowerCase() === "[object process]";

var hasEnvVariables = typeof process !== "undefined" &&
    typeof process.env !== "undefined";

function env(key) {
    return hasEnvVariables ? process.env[key] : undefined;
}

function getNativePromise() {
    if (typeof Promise === "function") {
        try {
            var promise = new Promise(function(){});
            if ({}.toString.call(promise) === "[object Promise]") {
                return Promise;
            }
        } catch (e) {}
    }
}

function domainBind(self, cb) {
    return self.bind(cb);
}

var ret = {
    isClass: isClass,
    isIdentifier: isIdentifier,
    inheritedDataKeys: inheritedDataKeys,
    getDataPropertyOrDefault: getDataPropertyOrDefault,
    thrower: thrower,
    isArray: es5.isArray,
    asArray: asArray,
    notEnumerableProp: notEnumerableProp,
    isPrimitive: isPrimitive,
    isObject: isObject,
    isError: isError,
    canEvaluate: canEvaluate,
    errorObj: errorObj,
    tryCatch: tryCatch,
    inherits: inherits,
    withAppended: withAppended,
    maybeWrapAsError: maybeWrapAsError,
    toFastProperties: toFastProperties,
    filledRange: filledRange,
    toString: safeToString,
    canAttachTrace: canAttachTrace,
    ensureErrorObject: ensureErrorObject,
    originatesFromRejection: originatesFromRejection,
    markAsOriginatingFromRejection: markAsOriginatingFromRejection,
    classString: classString,
    copyDescriptors: copyDescriptors,
    hasDevTools: typeof chrome !== "undefined" && chrome &&
                 typeof chrome.loadTimes === "function",
    isNode: isNode,
    hasEnvVariables: hasEnvVariables,
    env: env,
    global: globalObject,
    getNativePromise: getNativePromise,
    domainBind: domainBind
};
ret.isRecentNode = ret.isNode && (function() {
    var version;
    if (process.versions && process.versions.node) {
        version = process.versions.node.split(".").map(Number);
    } else if (process.version) {
        version = process.version.split(".").map(Number);
    }
    return (version[0] === 0 && version[1] > 10) || (version[0] > 0);
})();

if (ret.isNode) ret.toFastProperties(process);

try {throw new Error(); } catch (e) {ret.lastLineError = e;}
module.exports = ret;
<commit_msg>Reuse classString function (#1568)<commit_after>"use strict";
var ASSERT = require("./assert");
var es5 = require("./es5");
// Assume CSP if browser
var canEvaluate = typeof navigator == "undefined";

//Try catch is not supported in optimizing
//compiler, so it is isolated
var errorObj = {e: {}};
var tryCatchTarget;
var globalObject = typeof self !== "undefined" ? self :
    typeof window !== "undefined" ? window :
    typeof global !== "undefined" ? global :
    this !== undefined ? this : null;

function tryCatcher() {
    try {
        var target = tryCatchTarget;
        tryCatchTarget = null;
        return target.apply(this, arguments);
    } catch (e) {
        errorObj.e = e;
        return errorObj;
    }
}
function tryCatch(fn) {
    ASSERT(typeof fn === "function");
    tryCatchTarget = fn;
    return tryCatcher;
}

//Un-magical enough that using this doesn't prevent
//extending classes from outside using any convention
var inherits = function(Child, Parent) {
    var hasProp = {}.hasOwnProperty;

    function T() {
        this.constructor = Child;
        this.constructor$ = Parent;
        for (var propertyName in Parent.prototype) {
            if (hasProp.call(Parent.prototype, propertyName) &&
                propertyName.charAt(propertyName.length-1) !== "$"
           ) {
                this[propertyName + "$"] = Parent.prototype[propertyName];
            }
        }
    }
    T.prototype = Parent.prototype;
    Child.prototype = new T();
    return Child.prototype;
};

function isPrimitive(val) {
    return val == null || val === true || val === false ||
        typeof val === "string" || typeof val === "number";

}

function isObject(value) {
    return typeof value === "function" ||
           typeof value === "object" && value !== null;
}

function maybeWrapAsError(maybeError) {
    if (!isPrimitive(maybeError)) return maybeError;

    return new Error(safeToString(maybeError));
}

function withAppended(target, appendee) {
    var len = target.length;
    var ret = new Array(len + 1);
    var i;
    for (i = 0; i < len; ++i) {
        ret[i] = target[i];
    }
    ret[i] = appendee;
    return ret;
}

function getDataPropertyOrDefault(obj, key, defaultValue) {
    if (es5.isES5) {
        var desc = Object.getOwnPropertyDescriptor(obj, key);

        if (desc != null) {
            return desc.get == null && desc.set == null
                    ? desc.value
                    : defaultValue;
        }
    } else {
        return {}.hasOwnProperty.call(obj, key) ? obj[key] : undefined;
    }
}

function notEnumerableProp(obj, name, value) {
    if (isPrimitive(obj)) return obj;
    var descriptor = {
        value: value,
        configurable: true,
        enumerable: false,
        writable: true
    };
    es5.defineProperty(obj, name, descriptor);
    return obj;
}

function thrower(r) {
    throw r;
}

var inheritedDataKeys = (function() {
    var excludedPrototypes = [
        Array.prototype,
        Object.prototype,
        Function.prototype
    ];

    var isExcludedProto = function(val) {
        for (var i = 0; i < excludedPrototypes.length; ++i) {
            if (excludedPrototypes[i] === val) {
                return true;
            }
        }
        return false;
    };

    if (es5.isES5) {
        var getKeys = Object.getOwnPropertyNames;
        return function(obj) {
            var ret = [];
            var visitedKeys = Object.create(null);
            while (obj != null && !isExcludedProto(obj)) {
                var keys;
                try {
                    keys = getKeys(obj);
                } catch (e) {
                    return ret;
                }
                for (var i = 0; i < keys.length; ++i) {
                    var key = keys[i];
                    if (visitedKeys[key]) continue;
                    visitedKeys[key] = true;
                    var desc = Object.getOwnPropertyDescriptor(obj, key);
                    if (desc != null && desc.get == null && desc.set == null) {
                        ret.push(key);
                    }
                }
                obj = es5.getPrototypeOf(obj);
            }
            return ret;
        };
    } else {
        var hasProp = {}.hasOwnProperty;
        return function(obj) {
            if (isExcludedProto(obj)) return [];
            var ret = [];

            /*jshint forin:false */
            enumeration: for (var key in obj) {
                if (hasProp.call(obj, key)) {
                    ret.push(key);
                } else {
                    for (var i = 0; i < excludedPrototypes.length; ++i) {
                        if (hasProp.call(excludedPrototypes[i], key)) {
                            continue enumeration;
                        }
                    }
                    ret.push(key);
                }
            }
            return ret;
        };
    }

})();

var thisAssignmentPattern = /this\s*\.\s*\S+\s*=/;
function isClass(fn) {
    try {
        if (typeof fn === "function") {
            var keys = es5.names(fn.prototype);

            var hasMethods = es5.isES5 && keys.length > 1;
            var hasMethodsOtherThanConstructor = keys.length > 0 &&
                !(keys.length === 1 && keys[0] === "constructor");
            var hasThisAssignmentAndStaticMethods =
                thisAssignmentPattern.test(String(fn))
                    && es5.names(fn).length > 0;

            if (hasMethods || hasMethodsOtherThanConstructor ||
                hasThisAssignmentAndStaticMethods) {
                return true;
            }
        }
        return false;
    } catch (e) {
        return false;
    }
}

function toFastProperties(obj) {
    /*jshint -W027,-W055,-W031*/
    function FakeConstructor() {}
    FakeConstructor.prototype = obj;
    var receiver = new FakeConstructor();
    function ic() {
        return typeof receiver.foo;
    }
    ic();
    ic();
    ASSERT("%HasFastProperties", true, obj);
    return obj;
    // Prevent the function from being optimized through dead code elimination
    // or further optimizations. This code is never reached but even using eval
    // in unreachable code causes v8 to not optimize functions.
    eval(obj);
}

var rident = /^[a-z$_][a-z$_0-9]*$/i;
function isIdentifier(str) {
    return rident.test(str);
}

function filledRange(count, prefix, suffix) {
    var ret = new Array(count);
    for(var i = 0; i < count; ++i) {
        ret[i] = prefix + i + suffix;
    }
    return ret;
}

function safeToString(obj) {
    try {
        return String(obj);
    } catch (e) {
        return "[no string representation]";
    }
}

function isError(obj) {
    return obj instanceof Error ||
        (obj !== null &&
           typeof obj === "object" &&
           typeof obj.message === "string" &&
           typeof obj.name === "string");
}

function markAsOriginatingFromRejection(e) {
    try {
        notEnumerableProp(e, OPERATIONAL_ERROR_KEY, true);
    }
    catch(ignore) {}
}

function originatesFromRejection(e) {
    if (e == null) return false;
    return ((e instanceof Error[BLUEBIRD_ERRORS].OperationalError) ||
        e[OPERATIONAL_ERROR_KEY] === true);
}

function canAttachTrace(obj) {
    return isError(obj) && es5.propertyIsWritable(obj, "stack");
}

var ensureErrorObject = (function() {
    if (!("stack" in new Error())) {
        return function(value) {
            if (canAttachTrace(value)) return value;
            try {throw new Error(safeToString(value));}
            catch(err) {return err;}
        };
    } else {
        return function(value) {
            if (canAttachTrace(value)) return value;
            return new Error(safeToString(value));
        };
    }
})();

function classString(obj) {
    return {}.toString.call(obj);
}

function copyDescriptors(from, to, filter) {
    var keys = es5.names(from);
    for (var i = 0; i < keys.length; ++i) {
        var key = keys[i];
        if (filter(key)) {
            try {
                es5.defineProperty(to, key, es5.getDescriptor(from, key));
            } catch (ignore) {}
        }
    }
}

var asArray = function(v) {
    if (es5.isArray(v)) {
        return v;
    }
    return null;
};

if (typeof Symbol !== "undefined" && Symbol.iterator) {
    var ArrayFrom = typeof Array.from === "function" ? function(v) {
        return Array.from(v);
    } : function(v) {
        var ret = [];
        var it = v[Symbol.iterator]();
        var itResult;
        while (!((itResult = it.next()).done)) {
            ret.push(itResult.value);
        }
        return ret;
    };

    asArray = function(v) {
        if (es5.isArray(v)) {
            return v;
        } else if (v != null && typeof v[Symbol.iterator] === "function") {
            return ArrayFrom(v);
        }
        return null;
    };
}

var isNode = typeof process !== "undefined" &&
        classString(process).toLowerCase() === "[object process]";

var hasEnvVariables = typeof process !== "undefined" &&
    typeof process.env !== "undefined";

function env(key) {
    return hasEnvVariables ? process.env[key] : undefined;
}

function getNativePromise() {
    if (typeof Promise === "function") {
        try {
            var promise = new Promise(function(){});
            if (classString(promise) === "[object Promise]") {
                return Promise;
            }
        } catch (e) {}
    }
}

function domainBind(self, cb) {
    return self.bind(cb);
}

var ret = {
    isClass: isClass,
    isIdentifier: isIdentifier,
    inheritedDataKeys: inheritedDataKeys,
    getDataPropertyOrDefault: getDataPropertyOrDefault,
    thrower: thrower,
    isArray: es5.isArray,
    asArray: asArray,
    notEnumerableProp: notEnumerableProp,
    isPrimitive: isPrimitive,
    isObject: isObject,
    isError: isError,
    canEvaluate: canEvaluate,
    errorObj: errorObj,
    tryCatch: tryCatch,
    inherits: inherits,
    withAppended: withAppended,
    maybeWrapAsError: maybeWrapAsError,
    toFastProperties: toFastProperties,
    filledRange: filledRange,
    toString: safeToString,
    canAttachTrace: canAttachTrace,
    ensureErrorObject: ensureErrorObject,
    originatesFromRejection: originatesFromRejection,
    markAsOriginatingFromRejection: markAsOriginatingFromRejection,
    classString: classString,
    copyDescriptors: copyDescriptors,
    hasDevTools: typeof chrome !== "undefined" && chrome &&
                 typeof chrome.loadTimes === "function",
    isNode: isNode,
    hasEnvVariables: hasEnvVariables,
    env: env,
    global: globalObject,
    getNativePromise: getNativePromise,
    domainBind: domainBind
};
ret.isRecentNode = ret.isNode && (function() {
    var version;
    if (process.versions && process.versions.node) {
        version = process.versions.node.split(".").map(Number);
    } else if (process.version) {
        version = process.version.split(".").map(Number);
    }
    return (version[0] === 0 && version[1] > 10) || (version[0] > 0);
})();

if (ret.isNode) ret.toFastProperties(process);

try {throw new Error(); } catch (e) {ret.lastLineError = e;}
module.exports = ret;
<|endoftext|>


<commit_before>/**
 * Created by madlord on 16/2/1.
 */
var semver=require('semver');
var fs=require('fs');
var path =require('path');

function mkdirsSync(dirpath, mode) {
    if (!fs.existsSync(dirpath)) {
        var pathtmp="/";
        dirpath.split(path.sep).forEach(function(dirname) {
            if (pathtmp) {
                pathtmp = path.join(pathtmp, dirname);
            }
            else {
                pathtmp = dirname;
            }
            if (!fs.existsSync(pathtmp)) {
                if (!fs.mkdirSync(pathtmp, mode)) {
                    return false;
                }
            }
        });
    }
    return true;
}

var copy_dir = function( src, dst ){
    // 读取目录中的所有文件/目录
    var paths=fs.readdirSync( src);
    paths.forEach(function( path ){
        var _src = src + '/' + path,
            _dst = dst + '/' + path;
        var st=fs.statSync( _src);
        if( st.isFile() ){

            fs.writeFileSync(_dst,fs.readFileSync( _src ));
        }
        // 如果是目录则递归调用自身
        else if( st.isDirectory() ){
            exists( _src, _dst, copy_dir );
        }
    });
};
// 在复制目录前需要判断该目录是否存在，不存在需要先创建目录
var exists = function( src, dst, callback ){
    if( fs.existsSync(dst) ){
        callback( src, dst );
    }
    // 不存在
    else{
        fs.mkdirSync(dst);
        callback( src, dst );
    }
};

var copy=function(src,dst) {
    if (fs.existsSync(src)&&fs.statSync(src).isFile()) {
        fs.createReadStream(src).pipe(fs.createWriteStream(dst));
    }
}
function deleteFolderRecursive(path) {
    var files = [];
    if (fs.existsSync(path)) {
        files = fs.readdirSync(path);
        files.forEach(function (file, index) {
            var curPath = path + "/" + file;
            if (fs.statSync(curPath).isDirectory()) { // recurse
                deleteFolderRecursive(curPath);
            } else { // delete file
                fs.unlinkSync(curPath);
            }
        });
        fs.rmdirSync(path);
    }
};

function chooseCorrectVersion(cortex_config,versions,pkg_name,noBeta,base_path) {
    var rule=cortex_config.dependencies[pkg_name];
    var filtedVersions=[];
    versions.forEach(function (item) {
        if (fs.statSync(base_path+'/'+item).isDirectory()) {
            var version=item;
            if ((!noBeta)||(item.indexOf('beta')==-1)) {
                item=item.split('-')[0];
                try {
                    if (!rule||(rule&&semver.satisfies(item,rule))) {
                        filtedVersions.push(version);
                    }
                } catch (e) {
                    console.warn("file or dir ["+item+"] is weired, but I choose to ignore!");
                }
            }
        }
    });
    filtedVersions.sort();
    return filtedVersions[filtedVersions.length-1];

}

function fixRequire(code) {
    var resultCode=code;

    resultCode= resultCode.replace(/require\.resolve\((\s)*["'][\S]+['"](\s)*\)/g, function (word) {//require.resolve("xxx")
        return word.replace(/require\.resolve\((\s)*/g,"require(");
    });

    resultCode= resultCode.replace(/require\.async\((\s)*["'][\S]+['"](\s)*,/g, function (word) {//require.async("xxx")
        word=word.replace(/require\.async\((\s)*/g,"require([").replace(',','],');
        return word.replace(/["'](\S)+["']/,function(_p) {
            if (_p.length>3&&_p[1]!='.'&&_p[1]!='/'&&_p[1]!='@') {
                return '"@cortex/'+_p.substring(1,_p.length-1)+'"';
            } else {
                return _p;
            }
        })
    });

    resultCode= resultCode.replace(/require(\s)*\((\s)*["'](\S)+["'](\s)*\)/g, function (word) {//require("xxx")
        return word.replace(/["'](\S)+["']/,function(_p) {
            if (_p.length>3&&_p[1]!='.'&&_p[1]!='/'&&_p[1]!='@') {
                return '"@cortex/'+_p.substring(1,_p.length-1)+'"';
            } else {
                return _p;
            }
        })
    });

    return resultCode;
}

function processJS(src,dst_path,currentModuleName) {
    if (fs.existsSync(src)) {//读取删除js对应的源js文件
        var code=fs.readFileSync(src,'utf8');
        code=fixRequire(code);//处理require关键字
        var fc=new Function("" +
            "var result=[];"+
            "function  define(alias,dep,func,conf) {"+
            "result.push({key:alias,code:func.toString(),isMain:!!conf.main});"+
            "}"+
            code+
            "return result;"+
            "");

        var result=fc();
        result.forEach(function (obj) {
            var pkg_name=obj.key;
            var code=obj.code;
            var ss=code.substring(code.indexOf('{')+1).split('}');
            ss.pop();
            code=ss.join('}');
            //console.log(code);
            var _t=pkg_name.split('@');
            var module_name=_t[0];
            var module_path=(_t[1].indexOf('/')!=-1?_t[1].substring(_t[1].indexOf('/')):'');
            if (module_name==currentModuleName&&module_path) {
                mkdirsSync(path.dirname(dst_path+module_path));
                fs.writeFileSync(dst_path+module_path,code);
            }
        });
    }
}

module.exports={
    mkdirsSync:mkdirsSync,
    copy_dir:copy_dir,
    exists:exists,
    copy:copy,
    deleteFolderRecursive:deleteFolderRecursive,
    chooseCorrectVersion:chooseCorrectVersion,
    fixRequire:fixRequire,
    processJS:processJS
}<commit_msg>use origin quote<commit_after>/**
 * Created by madlord on 16/2/1.
 */
var semver=require('semver');
var fs=require('fs');
var path =require('path');

function mkdirsSync(dirpath, mode) {
    if (!fs.existsSync(dirpath)) {
        var pathtmp="/";
        dirpath.split(path.sep).forEach(function(dirname) {
            if (pathtmp) {
                pathtmp = path.join(pathtmp, dirname);
            }
            else {
                pathtmp = dirname;
            }
            if (!fs.existsSync(pathtmp)) {
                if (!fs.mkdirSync(pathtmp, mode)) {
                    return false;
                }
            }
        });
    }
    return true;
}

var copy_dir = function( src, dst ){
    // 读取目录中的所有文件/目录
    var paths=fs.readdirSync( src);
    paths.forEach(function( path ){
        var _src = src + '/' + path,
            _dst = dst + '/' + path;
        var st=fs.statSync( _src);
        if( st.isFile() ){

            fs.writeFileSync(_dst,fs.readFileSync( _src ));
        }
        // 如果是目录则递归调用自身
        else if( st.isDirectory() ){
            exists( _src, _dst, copy_dir );
        }
    });
};
// 在复制目录前需要判断该目录是否存在，不存在需要先创建目录
var exists = function( src, dst, callback ){
    if( fs.existsSync(dst) ){
        callback( src, dst );
    }
    // 不存在
    else{
        fs.mkdirSync(dst);
        callback( src, dst );
    }
};

var copy=function(src,dst) {
    if (fs.existsSync(src)&&fs.statSync(src).isFile()) {
        fs.createReadStream(src).pipe(fs.createWriteStream(dst));
    }
}
function deleteFolderRecursive(path) {
    var files = [];
    if (fs.existsSync(path)) {
        files = fs.readdirSync(path);
        files.forEach(function (file, index) {
            var curPath = path + "/" + file;
            if (fs.statSync(curPath).isDirectory()) { // recurse
                deleteFolderRecursive(curPath);
            } else { // delete file
                fs.unlinkSync(curPath);
            }
        });
        fs.rmdirSync(path);
    }
};

function chooseCorrectVersion(cortex_config,versions,pkg_name,noBeta,base_path) {
    var rule=cortex_config.dependencies[pkg_name];
    var filtedVersions=[];
    versions.forEach(function (item) {
        if (fs.statSync(base_path+'/'+item).isDirectory()) {
            var version=item;
            if ((!noBeta)||(item.indexOf('beta')==-1)) {
                item=item.split('-')[0];
                try {
                    if (!rule||(rule&&semver.satisfies(item,rule))) {
                        filtedVersions.push(version);
                    }
                } catch (e) {
                    console.warn("file or dir ["+item+"] is weired, but I choose to ignore!");
                }
            }
        }
    });
    filtedVersions.sort();
    return filtedVersions[filtedVersions.length-1];

}

function fixRequire(code) {
    var resultCode=code;

    resultCode= resultCode.replace(/require\.resolve\((\s)*["'][\S]+['"](\s)*\)/g, function (word) {//require.resolve("xxx")
        return word.replace(/require\.resolve\((\s)*/g,"require(");
    });

    resultCode= resultCode.replace(/require\.async\((\s)*["'][\S]+['"](\s)*,/g, function (word) {//require.async("xxx")
        word=word.replace(/require\.async\((\s)*/g,"require([").replace(',','],');
        return word.replace(/["'](\S+)["']/,function(_p) {
            var quote = _p[0]

            if (_p.length>3&&_p[1]!='.'&&_p[1]!='/'&&_p[1]!='@') {
                return quote + '@cortex/'+_p.substring(1,_p.length-1)+quote;
            } else {
                return _p;
            }
        })
    });

    resultCode= resultCode.replace(/require(\s)*\((\s)*["'](\S)+["'](\s)*\)/g, function (word) {//require("xxx")
        return word.replace(/["'](\S+)["']/,function(_p) {
            var quote = _p[0]

            if (_p.length>3&&_p[1]!='.'&&_p[1]!='/'&&_p[1]!='@') {
                return quote + '@cortex/'+_p.substring(1,_p.length-1)+quote;
            } else {
                return _p;
            }
        })
    });

    return resultCode;
}

function processJS(src,dst_path,currentModuleName) {
    if (fs.existsSync(src)) {//读取删除js对应的源js文件
        var code=fs.readFileSync(src,'utf8');
        code=fixRequire(code);//处理require关键字
        var fc=new Function("" +
            "var result=[];"+
            "function  define(alias,dep,func,conf) {"+
            "result.push({key:alias,code:func.toString(),isMain:!!conf.main});"+
            "}"+
            code+
            "return result;"+
            "");

        var result=fc();
        result.forEach(function (obj) {
            var pkg_name=obj.key;
            var code=obj.code;
            var ss=code.substring(code.indexOf('{')+1).split('}');
            ss.pop();
            code=ss.join('}');
            //console.log(code);
            var _t=pkg_name.split('@');
            var module_name=_t[0];
            var module_path=(_t[1].indexOf('/')!=-1?_t[1].substring(_t[1].indexOf('/')):'');
            if (module_name==currentModuleName&&module_path) {
                mkdirsSync(path.dirname(dst_path+module_path));
                fs.writeFileSync(dst_path+module_path,code);
            }
        });
    }
}

module.exports={
    mkdirsSync:mkdirsSync,
    copy_dir:copy_dir,
    exists:exists,
    copy:copy,
    deleteFolderRecursive:deleteFolderRecursive,
    chooseCorrectVersion:chooseCorrectVersion,
    fixRequire:fixRequire,
    processJS:processJS
}<|endoftext|>


<commit_before>var stackTrace = require('stack-trace');

var _ = {
  compose: require('lodash.compose')
};

var fs = require('fs');

/**
 * Advance position by increment.
 * That is, add increment.line to position.line and increment.column to position.column.
 * Return a fresh position.
 *
 * If a property does not exist in position, it is skipped.
 * If a property does not exist in increment, it is left unchanged.
 * Note that this behaviour makes the function sensitive to the order of arguments (noncommutative).
 *
 * If the second argument is omitted, effectively make a copy of the original position.
 *
 * @arg {Position} position
 * @arg {Position} [increment]
 * @return {Position}
 */
exports.advance = function (position, increment) {
  increment = increment || {};
  var result = Object.create(null);

  if (position.line != null) {
    result.line = position.line + (increment.line || 0);
  }
  if (position.column != null) {
    result.column = position.column + (increment.column || 0);
  }

  return result;
};

/**
 * Run the given function and pass its first line's number.
 *
 * @arg {function(number)} proc
 * @return {*} Whatever proc returns.
 */
exports.withLineNumber = function (proc) {
  return proc(stackTrace.get()[1].getLineNumber() + 1);
};

/**
 * Decode escape sequences in a string.
 * If the given string contains a quotation mark ('"', U+0022), the exception is raised.
 * This assumption simplifies the implementation a lot.
 *
 * @arg {string} string
 * @return {string}
 */
exports.decodeString = function (string) {
  if (string.indexOf('"') >= 0) {
    throw new Error('Could not decode.');
  }

  return eval('"' + string + '"');
};

/**
 * Decode escape sequences in a comment's body.
 *
 * @arg {Comment} comment
 * @return {Comment} Same comment actually, mutated.
 */
exports.decodeComment = function (comment) {
  comment.lines = comment.lines.map(exports.decodeString);
  return comment;
};

/**
 * Fire the rule checker and capture all the positions it has thrown.
 *
 * @arg {RuleChecker} ruleChecker
 * @arg {Comment} comment - Comment to check with the rule.
 * @return {Position[]}
 */
exports.positions = function (ruleChecker, comment) {
  var positions = [];
  ruleChecker(comment, _.compose([].push.bind(positions), exports.advance));
  return positions;
};

// These statements moved further in file to allow parseFormat use functions defined earlier,
//   such as 'util.advance'.
var extract = require('../src/extract'),
    parseFormat = require('../src/parse-format');

/**
 * Extract comments from file and leave only those that start with "/*!" or "//!".
 * The bang mark itself is contracted from the output.
 *
 * Valid options:
 *   - parseFormat: boolean, defaults to true.
 *
 * @arg {string} filename
 * @arg {Object} [options]
 * @return {Comment[] | string[]} Depending on parseFormat option.
 */
exports.extractMarkedComments = function (filename, options) {
  options = options || {};
  if (options.parseFormat == null) {
    options.parseFormat = true;
  }

  var comments = extract(fs.readFileSync(filename).toString()).filter(function (comment) {
    return comment.text[2] == '!';
  }).map(function (comment) {
    comment.text = comment.text.slice(0, 2) + comment.text.slice(3);
    return comment;
  });

  return options.parseFormat ? parseFormat(comments) : comments;
};
<commit_msg>Fix return type of util.extractMarkedComments<commit_after>var stackTrace = require('stack-trace');

var _ = {
  compose: require('lodash.compose')
};

var fs = require('fs');

/**
 * Advance position by increment.
 * That is, add increment.line to position.line and increment.column to position.column.
 * Return a fresh position.
 *
 * If a property does not exist in position, it is skipped.
 * If a property does not exist in increment, it is left unchanged.
 * Note that this behaviour makes the function sensitive to the order of arguments (noncommutative).
 *
 * If the second argument is omitted, effectively make a copy of the original position.
 *
 * @arg {Position} position
 * @arg {Position} [increment]
 * @return {Position}
 */
exports.advance = function (position, increment) {
  increment = increment || {};
  var result = Object.create(null);

  if (position.line != null) {
    result.line = position.line + (increment.line || 0);
  }
  if (position.column != null) {
    result.column = position.column + (increment.column || 0);
  }

  return result;
};

/**
 * Run the given function and pass its first line's number.
 *
 * @arg {function(number)} proc
 * @return {*} Whatever proc returns.
 */
exports.withLineNumber = function (proc) {
  return proc(stackTrace.get()[1].getLineNumber() + 1);
};

/**
 * Decode escape sequences in a string.
 * If the given string contains a quotation mark ('"', U+0022), the exception is raised.
 * This assumption simplifies the implementation a lot.
 *
 * @arg {string} string
 * @return {string}
 */
exports.decodeString = function (string) {
  if (string.indexOf('"') >= 0) {
    throw new Error('Could not decode.');
  }

  return eval('"' + string + '"');
};

/**
 * Decode escape sequences in a comment's body.
 *
 * @arg {Comment} comment
 * @return {Comment} Same comment actually, mutated.
 */
exports.decodeComment = function (comment) {
  comment.lines = comment.lines.map(exports.decodeString);
  return comment;
};

/**
 * Fire the rule checker and capture all the positions it has thrown.
 *
 * @arg {RuleChecker} ruleChecker
 * @arg {Comment} comment - Comment to check with the rule.
 * @return {Position[]}
 */
exports.positions = function (ruleChecker, comment) {
  var positions = [];
  ruleChecker(comment, _.compose([].push.bind(positions), exports.advance));
  return positions;
};

// These statements moved further in file to allow parseFormat use functions defined earlier,
//   such as 'util.advance'.
var extract = require('../src/extract'),
    parseFormat = require('../src/parse-format');

/**
 * Extract comments from file and leave only those that start with "/*!" or "//!".
 * The bang mark itself is contracted from the output.
 *
 * Valid options:
 *   - parseFormat: boolean, defaults to true.
 *
 * @arg {string} filename
 * @arg {Object} [options]
 * @return {Comment[] | {text: string, loc: Location}[]} Depending on parseFormat option.
 */
exports.extractMarkedComments = function (filename, options) {
  options = options || {};
  if (options.parseFormat == null) {
    options.parseFormat = true;
  }

  var comments = extract(fs.readFileSync(filename).toString()).filter(function (comment) {
    return comment.text[2] == '!';
  }).map(function (comment) {
    comment.text = comment.text.slice(0, 2) + comment.text.slice(3);
    return comment;
  });

  return options.parseFormat ? parseFormat(comments) : comments;
};
<|endoftext|>


<commit_before>import fs from 'fs';
import path from 'path';
import mkdirp from 'mkdirp';
import yaml from 'js-yaml';
import strip from 'strip';
import escapeHtml from 'escape-html';
import _ from 'lodash';

/**
 * Remove extension from file name.
 *
 * @param {String} filename
 * @return {String}
 */
export function removeExtension(filename) {
	return filename.replace(/\.\w+$/, '');
}

/**
 * Returns extension of a file (without the leading dot).
 *
 * @param {String} filename
 * @return {String}
 */
export function getExtension(filename) {
	return path.extname(filename).substring(1);
}

/**
 * Read text file.
 *
 * @param {String} filepath
 * @return {String}
 */
export function readFile(filepath) {
	return fs.readFileSync(filepath, {encoding: 'utf8'});
}

/**
 * Save text to a file (create all folders if necessary).
 *
 * @param {String} filepath
 * @param {String} content
 * @return {String}
 */
export function writeFile(filepath, content) {
	mkdirp.sync(path.dirname(filepath));
	return fs.writeFileSync(filepath, content, {encoding: 'utf8'});
}

/**
 * Read YAML file.
 *
 * @param {String} filepath
 * @return {String}
 */
export function readYamlFile(filepath) {
	try {
		return yaml.safeLoad(readFile(filepath));
	}
	catch (e) {
		console.log(`Cannot read YAML file ${filepath}:`, e);
	}
}

/**
 * Prepare fields list in short format to _.sortByOrder()
 * @param {Array} shortFields ['foo', '-bar']
 * @return {Array}
 */
export function formatFieldsForSortByOrder(shortFields) {
	return _.unzip(shortFields.map((field) => {
		if (field[0] === '-') {
			return [field.substr(1), 'desc'];
		}
		else {
			return [field, 'asc'];
		}
	}));
}

/**
 * Returns HTML meta tag.
 *
 * @param {String} name Meta name.
 * @param {String} content Meta value.
 * @return {String}
 */
export function meta(name, content) {
	content = cleanHtml(content);
	return `<meta name="${name}" content="${content}">`;
}

/**
 * Returns HTML meta tag for Open Graph.
 *
 * @param {String} name Meta name.
 * @param {String} content Meta value.
 * @return {String}
 */
export function og(name, content) {
	content = cleanHtml(content);
	return `<meta property="${name}" content="${content}">`;
}

/**
 * Return the content of the first paragraph in a given HTML.
 *
 * @param {String} text
 * @return {String}
 */
export function getFirstParagraph(text) {
	let m = text.match(/<p[^>]*>(.*?)<\/p>/i);
	return m && m[1];
}

/**
 * Return the URL of the first image in a given HTML.
 *
 * @param {String} text
 * @return {String}
 */
export function getFirstImage(text) {
	let m = text.match(/<img\s+src=["']([^"']+)["']/i);
	return m && m[1];
}

/**
 * Remove HTML and escape special characters.
 *
 * @param {String} text
 * @return {String}
 */
export function cleanHtml(text) {
	return escapeHtml(
		strip(text)
	);
}

/**
 * Print message immidiately and show execution time on process exit.
 *
 * @param {String} message
 */
export function start(message) {
	console.log(message);
	let startTime = new Date().getTime();

	process.on('exit', () => {
		let time = new Date().getTime() - startTime;
		let minutes = Math.floor(time / 1000 / 60) % 60;
		let seconds = Math.floor(time / 1000) % 60;
		console.log('Done in', (minutes ? `${minutes}m ` : '') + (seconds ? `${seconds}s` : ''));
	});
}
<commit_msg>Print “done in a moment” if generation time is less than 1 second.<commit_after>import fs from 'fs';
import path from 'path';
import mkdirp from 'mkdirp';
import yaml from 'js-yaml';
import strip from 'strip';
import escapeHtml from 'escape-html';
import _ from 'lodash';

/**
 * Remove extension from file name.
 *
 * @param {String} filename
 * @return {String}
 */
export function removeExtension(filename) {
	return filename.replace(/\.\w+$/, '');
}

/**
 * Returns extension of a file (without the leading dot).
 *
 * @param {String} filename
 * @return {String}
 */
export function getExtension(filename) {
	return path.extname(filename).substring(1);
}

/**
 * Read text file.
 *
 * @param {String} filepath
 * @return {String}
 */
export function readFile(filepath) {
	return fs.readFileSync(filepath, {encoding: 'utf8'});
}

/**
 * Save text to a file (create all folders if necessary).
 *
 * @param {String} filepath
 * @param {String} content
 * @return {String}
 */
export function writeFile(filepath, content) {
	mkdirp.sync(path.dirname(filepath));
	return fs.writeFileSync(filepath, content, {encoding: 'utf8'});
}

/**
 * Read YAML file.
 *
 * @param {String} filepath
 * @return {String}
 */
export function readYamlFile(filepath) {
	try {
		return yaml.safeLoad(readFile(filepath));
	}
	catch (e) {
		console.log(`Cannot read YAML file ${filepath}:`, e);
	}
}

/**
 * Prepare fields list in short format to _.sortByOrder()
 * @param {Array} shortFields ['foo', '-bar']
 * @return {Array}
 */
export function formatFieldsForSortByOrder(shortFields) {
	return _.unzip(shortFields.map((field) => {
		if (field[0] === '-') {
			return [field.substr(1), 'desc'];
		}
		else {
			return [field, 'asc'];
		}
	}));
}

/**
 * Returns HTML meta tag.
 *
 * @param {String} name Meta name.
 * @param {String} content Meta value.
 * @return {String}
 */
export function meta(name, content) {
	content = cleanHtml(content);
	return `<meta name="${name}" content="${content}">`;
}

/**
 * Returns HTML meta tag for Open Graph.
 *
 * @param {String} name Meta name.
 * @param {String} content Meta value.
 * @return {String}
 */
export function og(name, content) {
	content = cleanHtml(content);
	return `<meta property="${name}" content="${content}">`;
}

/**
 * Return the content of the first paragraph in a given HTML.
 *
 * @param {String} text
 * @return {String}
 */
export function getFirstParagraph(text) {
	let m = text.match(/<p[^>]*>(.*?)<\/p>/i);
	return m && m[1];
}

/**
 * Return the URL of the first image in a given HTML.
 *
 * @param {String} text
 * @return {String}
 */
export function getFirstImage(text) {
	let m = text.match(/<img\s+src=["']([^"']+)["']/i);
	return m && m[1];
}

/**
 * Remove HTML and escape special characters.
 *
 * @param {String} text
 * @return {String}
 */
export function cleanHtml(text) {
	return escapeHtml(
		strip(text)
	);
}

/**
 * Print message immidiately and show execution time on process exit.
 *
 * @param {String} message
 */
export function start(message) {
	console.log(message);
	let startTime = new Date().getTime();

	process.on('exit', () => {
		let time = new Date().getTime() - startTime;
		let minutes = Math.floor(time / 1000 / 60) % 60;
		let seconds = Math.floor(time / 1000) % 60;
		console.log('Done in', (minutes ? `${minutes}m ` : '') + (seconds ? `${seconds}s` : '') + (!minutes && !seconds ? 'a moment' : ''));
	});
}
<|endoftext|>


<commit_before>/**
 * Helper function for iterating over an array backwards. If the func
 * returns a true value, it will break out of the loop.
 */
function eachReverse(ary, func) {
  if (ary) {
    var i;
    for (i = ary.length - 1; i > -1; i -= 1) {
      if (ary[i] && func(ary[i], i, ary)) {
        break;
      }
    }
  }
}

function hasProp(obj, prop) {
  return Object.prototype.hasOwnProperty.call(obj, prop);
}

/**
 * Cycles over properties in an object and calls a function for each
 * property value. If the function returns a truthy value, then the
 * iteration is stopped.
 */
function eachProp(obj, func) {
  var prop;
  for (prop in obj) {
    if (obj.hasOwnProperty(prop)) {
      if (func(obj[prop], prop)) {
        break;
      }
    }
  }
}

/**
 * Simple function to mix in properties from source into target,
 * but only if target does not already have a property of the same name.
 * This is not robust in IE for transferring methods that match
 * Object.prototype names, but the uses of mixin here seem unlikely to
 * trigger a problem related to that.
 */
function mixin(target, source, force, deepStringMixin) {
  if (source) {
    eachProp(source, function (value, prop) {
      if (force || !hasProp(target, prop)) {
        if (deepStringMixin && typeof value !== 'string') {
          if (!target[prop]) {
            target[prop] = {};
          }
          mixin(target[prop], value, force, deepStringMixin);
        } else {
          target[prop] = value;
        }
      }
    });
  }
  return target;
}

/**
 * Add 'on' and 'emit' methods to an object, which act as a light weight
 * event handling structure.
 */
function handleEvents(obj) {
  var eventState = {
    listeners: {},
    conditional: [],
    oneshots: {},
    onceConditional: []
  };

  obj['on'] = function(type, handler) {
    if (typeof type === 'function') {
      this.conditional.push([type, handler]);
    } else if (this.listeners[type]) {
      this.listeners[type].push(handler);
    } else {
      this.listeners[type] = [handler];
    }
  }.bind(eventState);

  obj['once'] = function(type, handler) {
    if (typeof type === 'function') {
      this.onceConditional.push([type, handler]);
    } else if (this.oneshots[type]) {
      this.oneshots[type].push(handler);
    } else {
      this.oneshots[type] = [handler];
    }
  }.bind(eventState);

  obj['emit'] = function(type, data) {
    if (this.listeners[type]) {
      for (var i = 0; i < this.listeners[type].length; i++) {
        if (this.listeners[type][i](data) === false) {
          return;
        }
      }
    }
    if (this.oneshots[type]) {
      for (var i = 0; i < this.oneshots[type].length; i++) {
        this.oneshots[type][i](data);
      }
      this.oneshots[type] = [];
    }
    for (var i = 0; i < this.conditional.length; i++) {
      if (this.conditional[i][0](type, data)) {
        this.conditional[i][1](data);
      }
    }
    for (var i = this.onceConditional.length - 1; i >= 0; i--) {
      if (this.onceConditional[i][0](type, data)) {
        var cond = this.onceConditional.splice(i, 1);
        cond[0][1](data);
      }
    }
  }.bind(eventState);
}

/**
 * Determine if execution is working in a web worker,
 * Or a direct browser page.
 */
function isAppContext() {
  return (typeof window === 'undefined');
}

/**
 * Advertise the presence of an active freedom app to initiate interaction
 * with an installled / priveleged freedom context.
 */
function advertise() {
  var script = document.createElement('script');
  script.src = 'http://127.3733366/advertise.js';
  window.addEventListener('message', function(m) {
    if (m.source == window && m.data.type = 'freedomAdvertisementResponse') {
      console.log("Fdom advertisement response");
    }
  });
  document.children[0] && document.children[0].appendChild(script);
}

/**
 * Find all scripts on the given page.
 */
function scripts() {
    return document.getElementsByTagName('script');
}

/**
 * Make a relative URL absolute, based on the current location.
 */
function makeAbsolute(url) {
  if (url.indexOf("http") !== 0) {
    var base = location.protocol + "//" + location.host;
    if (url.indexOf("/") === 0) {
      return base + url;
    } else {
      base += location.pathname;
      var here = base.substr(0, base.lastIndexOf("/"));
      return here + "/" + url;
    }
  } else {
    return url;
  }
}
<commit_msg>Update util to work in chrome-extension context<commit_after>/**
 * Helper function for iterating over an array backwards. If the func
 * returns a true value, it will break out of the loop.
 */
function eachReverse(ary, func) {
  if (ary) {
    var i;
    for (i = ary.length - 1; i > -1; i -= 1) {
      if (ary[i] && func(ary[i], i, ary)) {
        break;
      }
    }
  }
}

function hasProp(obj, prop) {
  return Object.prototype.hasOwnProperty.call(obj, prop);
}

/**
 * Cycles over properties in an object and calls a function for each
 * property value. If the function returns a truthy value, then the
 * iteration is stopped.
 */
function eachProp(obj, func) {
  var prop;
  for (prop in obj) {
    if (obj.hasOwnProperty(prop)) {
      if (func(obj[prop], prop)) {
        break;
      }
    }
  }
}

/**
 * Simple function to mix in properties from source into target,
 * but only if target does not already have a property of the same name.
 * This is not robust in IE for transferring methods that match
 * Object.prototype names, but the uses of mixin here seem unlikely to
 * trigger a problem related to that.
 */
function mixin(target, source, force, deepStringMixin) {
  if (source) {
    eachProp(source, function (value, prop) {
      if (force || !hasProp(target, prop)) {
        if (deepStringMixin && typeof value !== 'string') {
          if (!target[prop]) {
            target[prop] = {};
          }
          mixin(target[prop], value, force, deepStringMixin);
        } else {
          target[prop] = value;
        }
      }
    });
  }
  return target;
}

/**
 * Add 'on' and 'emit' methods to an object, which act as a light weight
 * event handling structure.
 */
function handleEvents(obj) {
  var eventState = {
    listeners: {},
    conditional: [],
    oneshots: {},
    onceConditional: []
  };

  obj['on'] = function(type, handler) {
    if (typeof type === 'function') {
      this.conditional.push([type, handler]);
    } else if (this.listeners[type]) {
      this.listeners[type].push(handler);
    } else {
      this.listeners[type] = [handler];
    }
  }.bind(eventState);

  obj['once'] = function(type, handler) {
    if (typeof type === 'function') {
      this.onceConditional.push([type, handler]);
    } else if (this.oneshots[type]) {
      this.oneshots[type].push(handler);
    } else {
      this.oneshots[type] = [handler];
    }
  }.bind(eventState);

  obj['emit'] = function(type, data) {
    if (this.listeners[type]) {
      for (var i = 0; i < this.listeners[type].length; i++) {
        if (this.listeners[type][i](data) === false) {
          return;
        }
      }
    }
    if (this.oneshots[type]) {
      for (var i = 0; i < this.oneshots[type].length; i++) {
        this.oneshots[type][i](data);
      }
      this.oneshots[type] = [];
    }
    for (var i = 0; i < this.conditional.length; i++) {
      if (this.conditional[i][0](type, data)) {
        this.conditional[i][1](data);
      }
    }
    for (var i = this.onceConditional.length - 1; i >= 0; i--) {
      if (this.onceConditional[i][0](type, data)) {
        var cond = this.onceConditional.splice(i, 1);
        cond[0][1](data);
      }
    }
  }.bind(eventState);
}

/**
 * Determine if execution is working in a web worker,
 * Or a direct browser page.
 */
function isAppContext() {
  return (typeof window === 'undefined');
}

/**
 * Advertise the presence of an active freedom app to initiate interaction
 * with an installled / priveleged freedom context.
 */
function advertise() {
  var script = document.createElement('script');
  script.src = 'http://127.3733366/advertise.js';
  window.addEventListener('message', function(m) {
    if (m.source == window && m.data.type = 'freedomAdvertisementResponse') {
      console.log("Fdom advertisement response");
    }
  });
  var head = document.getElementsByTagName("head")[0];
  head && head.appendChild(script);
}

/**
 * Find all scripts on the given page.
 */
function scripts() {
    return document.getElementsByTagName('script');
}

/**
 * Make a relative URL absolute, based on the current location.
 */
function makeAbsolute(url) {
  if (url.indexOf("http") !== 0 && url.indexOf("chrome-extension://") !== 0) {
    var base = location.protocol + "//" + location.host;
    if (url.indexOf("/") === 0) {
      return base + url;
    } else {
      base += location.pathname;
      var here = base.substr(0, base.lastIndexOf("/"));
      return here + "/" + url;
    }
  } else {
    return url;
  }
}
<|endoftext|>


<commit_before>// 订单金额计算器
exports.orderCalculator = require('./calculator.js');

// 设置cookie
exports.setCookie = function(name, value, isForever, domain){
  var sDomain;
  if(domain){
    sDomain = ";domain=" + domain;
  }else{
    sDomain = "";
  }
  document.cookie = name + "=" + escape(value) + sDomain + (isForever?";expires="+  (new Date(2099,12,31)).toGMTString():"") + ";path=/";
};
// 获取cookie
exports.getCookie = function(sName){
  var sSearch = sName + "=";
  if(document.cookie.length > 0){
    offset = document.cookie.indexOf(sSearch);
    if(offset != -1){
      offset += sSearch.length;
      end = document.cookie.indexOf(";", offset);
      if(end == -1) end = document.cookie.length;
      return unescape(document.cookie.substring(offset, end));
    }
    else return "";
  }
};
// 获取图片url
exports.getImageUrl = function(image_id, image_name, image_size, image_epoch){
  if(!image_id || !image_name){
    var aDef = window.productImage.split('.');
    aDef[0] = aDef[0] + '_' + image_size;
    var sDef = aDef.join('.');
    var sPath = window.assetPath;
    if(!sPath){
      sPath = window.assetHost;
    }
    sDef = sPath + sDef;
    return sDef;
  }
  var sHost = window.assetHost;
  if(!sHost){
    sHost = window.assetPath;
  }
  sHost = sHost + image_id + '/';
  var sFileName = image_name;
  if(image_size){
    var aSplit = image_name.split('.');
    var nLen = aSplit.length;
    if(nLen > 1){
    // var sImageSize = '_' + image_size;
    // var sFileNotExt = aSplit[nLen - 2];
    // aSplit[nLen - 2] = sFileNotExt + sImageSize;
    // sFileName = aSplit.join('.');
    var sImageSize = 's_' + image_size;
    var sFileExtName = aSplit.pop();
    sFileName = sImageSize + '.' + sFileExtName;
    }else{
    //alert('文件没有后缀名？');
    }
  }
  sHost = sHost + sFileName;
  if(image_epoch){
    sHost = sHost + '?epoch=' + image_epoch;
  }
  return sHost;
};
//
exports.getProductUrl = function(sUrl, nWidth, nHeight){
  var sResUrl = sUrl;
  var aImgUrl = sUrl.split('.');
  var aExtName = ['jpg', 'jpeg', 'gif', 'png'];
  var nImgUrlLen = aImgUrl.length;
  var sExtName = aImgUrl[nImgUrlLen - 1];
  if(sExtName.indexOf('?') > -1){
    sExtName = sExtName.split('?')[0];
  }
  sExtName = sExtName.toLowerCase();
  $.each(aExtName, function(index, name){
    if(name == sExtName){
      aImgUrl[nImgUrlLen - 2] = aImgUrl[nImgUrlLen - 2] + '_' + nWidth + 'x' + nHeight;
      sResUrl = aImgUrl.join('.');
      return false;
    }
  });
  return sResUrl;
};
//
exports.getQuery = function(name, bNotEscape){
  var sUrl = window.location.search.substr(1);
  var r = sUrl.match(new RegExp("(^|&)" + name + "=([^&]*)(&|$)"));
  if(bNotEscape){
    return (r === null ? null : r[2]);
  }else{
    return (r === null ? null : unescape(r[2]));
  }
};
//
exports.setQuery = function( key , value , url ){
  var aHash = url.match(/#.*(\?|$)/ig);
  var sHash = '';
  if(aHash && aHash[0]){
    sHash = aHash[0];
    url = url.replace(sHash, '');
  }
  url = url || window.location.href;
  url = url.replace( new RegExp( '(^|\\?)' + key + '=[^&]*(&|$|#)' , 'g' ) , '?' );
  url = url.replace( new RegExp( '(^|&)' + key + '=[^&]*(?=&|$|#)' , 'g' ) , '' );
  var p = key + '=' + encodeURIComponent(value);
  var sUrl = url;
  if(!(/\?$/.test( url ))){
    sUrl = url + ( /\?/.test( url ) ? '&' : '?' );
  }
  return sUrl + p + sHash;
};
//
exports.isEmail = function(sEmail){
  var rEmail = /([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})/i;
  return rEmail.test(sEmail);
};
//
exports.isMobile = function(sPhone){
  var rPhone = /^(13|14|15|17|18)\d{9}$/;
  return rPhone.test(sPhone);
};
//
exports.isUsername = function(sUsername){
  var rUsername = /^([A-Za-z\u4e00-\u9fa5])[A-Za-z0-9\u4e00-\u9fa5_-]{3,15}$/;
  return rUsername.test(sUsername);
};
//
exports.isRealname = function(sRealname){
  var rRealname = /^.{1,255}$/;
  return rRealname.test(sRealname);
};
//
exports.yuan = function(nFen){
  var nYuan = nFen / 100;
  return nYuan;
};
//
exports.inArray = function(){
  if(!Array.prototype.indexOf){
    Array.prototype.indexOf = function(elt, from){
      var len = this.length >>> 0;
      from = Number(arguments[1]) || 0;
      from = (from < 0) ? Math.ceil(from) : Math.floor(from);
      if (from < 0)
        from += len;

      for (; from < len; from++)
      {
        if (from in this &&
          this[from] === elt)
          return from;
      }
      return -1;
    };
  }
  return arguments[1].indexOf(arguments[0]);
};
//
exports.forEach = function (collection, callback, isNotObject, scope) {
  if (Object.prototype.toString.call(collection) === '[object Object]' && !isNotObject) {
    for (var prop in collection) {
      if (Object.prototype.hasOwnProperty.call(collection, prop)) {
        if(callback.call(scope, collection[prop], prop, collection) === false){
          break;
        }
      }
    }
  } else {
    for (var i = 0, len = collection.length; i < len; i++) {
      if(callback.call(scope, collection[i], i, collection) === false){
        break;
      }
    }
  }
};

/**
 * 实用工具集合
 *
 * ```setCookie
 * `` name
 * &` 类型：String<br/>需要设置的 cookie 名称。
 * `` value
 * &` 类型：String<br/>需要设置的 cookie 值。
 * `` isForever
 * &` 类型：Boolean ( 默认值：^^^false^^^ )<br/>设置为^^^true^^^，cookie 永不过期。
 * ```
 *
 * ```getCookie
 * `` name
 * &` 类型：String<br/>需要读取的 cookie 名称。
 * ```
 *
 * ```getImageUrl
 * `` image_id
 * &` 类型：String<br/>图片对象的 image_id。
 * `` image_name
 * &` 类型：String<br/>图片对象的 image_name。
 * `` image_size
 * &` 类型：String<br/>输出图片的尺寸大小，例如^^^300x300^^^。
 * `` image_epoch
 * &` 类型：String<br/>图片对象的 image_epoch。
 * ```
 *
 * ```getQuery
 * `` key
 * &` 类型：String<br/>需要获取的 url 参数名称。
 * ```
 *
 * ```setQuery
 * `` key
 * &` 类型：String<br/>需要设置的 url 参数名称。
 * `` value
 * &` 类型：String<br/>需要设置的 url 参数的值。
 * `` url
 * &` 类型：String<br/>需要设置参数的 url。
 * ```
 *
 * ```inArray
 * `` element
 * &` 类型：String|Object<br/>需要检查的元素。
 * `` array
 * &` 类型：Array<br/>需要检查的数组。
 * ```
 *
 * ```forEach
 * `` collection
 * &` 类型：Array|Object<br/>需要遍历的数组或对象。
 * `` callback
 * &` 类型：Function( 单个元素 )<br/>回调函数，返回^^^false^^^可停止遍历。
 * ```
 *
 * ```isEmail
 * `` email
 * &` 类型：String<br/>需要检测是否合法的 email，合法则返回^^^true^^^，不合法则返回^^^false^^^。
 * ```
 *
 * ```isMobile
 * `` mobile
 * &` 类型：String<br/>需要检测是否合法的中国大陆手机，合法则返回^^^true^^^，不合法则返回^^^false^^^。
 * ```
 *
 * ```isUsername
 * `` username
 * &` 类型：String<br/>需要检测是否合法的用户名，合法则返回^^^true^^^，不合法则返回^^^false^^^。
 * ```
 *
 * ```isRealname
 * `` realname
 * &` 类型：String<br/>需要检测是否合法的真实姓名，合法则返回^^^true^^^，不合法则返回^^^false^^^。
 * ```
 *
 * ```orderCalculator
 * `` return
 * &` 调用此方法将返回一个计算器实例，具有以下方法：
 * &&` ^^^update(object)^^^：更新数据，参数形如^^^{item_amount: 90}^^^，可接收的^^^key^^^及其具体意义可以调用^^^help^^^方法查看
 * &&` ^^^get([callback])^^^：返回订单计算结果，可接受一个回调函数，参数为订单计算结果
 * &&` ^^^help()^^^：在控制台打印帮助信息
 * &&&
 * &&& ^^^
 * &&& var Calc = Jssdk.util.orderCalculator();
 * &&& Calc.update({
 * &&&     item_amount: 90, // 商品总金额
 * &&&     shipment_amount: 10 // 运费总金额
 * &&& });
 * &&& var final_amount;
 * &&& Calc.get(function(result) {
 * &&&     final_amount = result.final_amount; //实付金额
 * &&& });
 * &&& console.log(final_amount); // 100
 * &&& ^^^
 * ```
 *
 * @param {setCookie} `name,value[,isForever]` 设置 cookie
 * @param {getCookie} `name` 读取 cookie
 * @param {getImageUrl} `image_id,image_name,image_size,image_epoch` 将图片对象转换为 url
 * @param {getQuery} `key` 获取 url 中 search 部分的参数
 * @param {setQuery} `key,value,url` 设置 url 中 search 部分的参数
 * @param {inArray} `element,array` 检查目标对象是否在数组中
 * @param {forEach} `collection,callback` 遍历数组或对象中的所有元素
 * @param {isEmail} `email` 验证email是否合法
 * @param {isMobile} `mobile` 验证手机号码是否合法（中国大陆）
 * @param {isUsername} `username` 验证用户名是否合法
 * @param {isRealname} `realname` 验证真实姓名是否合法
 * @param {orderCalculator} 创建一个订单金额计算器
 *
 */<commit_msg>fix: repair getCookie<commit_after>// 订单金额计算器
exports.orderCalculator = require('./calculator.js');

// 设置cookie
exports.setCookie = function(name, value, isForever, domain){
  var sDomain;
  if(domain){
    sDomain = ";domain=" + domain;
  }else{
    sDomain = "";
  }
  document.cookie = name + "=" + escape(value) + sDomain + (isForever?";expires="+  (new Date(2099,12,31)).toGMTString():"") + ";path=/";
};
// 获取cookie
exports.getCookie = function(sName){
    var cookie_str = document.cookie,
        cookies = {},
        reg,
        result;
    if(!/;\s*$/.test(cookie_str)){
      cookie_str += ';';
    }
    reg = /(\S+?)=([\w\W]*?);/g;
    while(result = reg.exec(cookie_str)){
      cookies[result[1]] = decodeURIComponent(result[2]);
    }
    if(sName){
      return cookies[sName];
    }else{
      return cookies;
    }
};
// 获取图片url
exports.getImageUrl = function(image_id, image_name, image_size, image_epoch){
  if(!image_id || !image_name){
    var aDef = window.productImage.split('.');
    aDef[0] = aDef[0] + '_' + image_size;
    var sDef = aDef.join('.');
    var sPath = window.assetPath;
    if(!sPath){
      sPath = window.assetHost;
    }
    sDef = sPath + sDef;
    return sDef;
  }
  var sHost = window.assetHost;
  if(!sHost){
    sHost = window.assetPath;
  }
  sHost = sHost + image_id + '/';
  var sFileName = image_name;
  if(image_size){
    var aSplit = image_name.split('.');
    var nLen = aSplit.length;
    if(nLen > 1){
    // var sImageSize = '_' + image_size;
    // var sFileNotExt = aSplit[nLen - 2];
    // aSplit[nLen - 2] = sFileNotExt + sImageSize;
    // sFileName = aSplit.join('.');
    var sImageSize = 's_' + image_size;
    var sFileExtName = aSplit.pop();
    sFileName = sImageSize + '.' + sFileExtName;
    }else{
    //alert('文件没有后缀名？');
    }
  }
  sHost = sHost + sFileName;
  if(image_epoch){
    sHost = sHost + '?epoch=' + image_epoch;
  }
  return sHost;
};
//
exports.getProductUrl = function(sUrl, nWidth, nHeight){
  var sResUrl = sUrl;
  var aImgUrl = sUrl.split('.');
  var aExtName = ['jpg', 'jpeg', 'gif', 'png'];
  var nImgUrlLen = aImgUrl.length;
  var sExtName = aImgUrl[nImgUrlLen - 1];
  if(sExtName.indexOf('?') > -1){
    sExtName = sExtName.split('?')[0];
  }
  sExtName = sExtName.toLowerCase();
  $.each(aExtName, function(index, name){
    if(name == sExtName){
      aImgUrl[nImgUrlLen - 2] = aImgUrl[nImgUrlLen - 2] + '_' + nWidth + 'x' + nHeight;
      sResUrl = aImgUrl.join('.');
      return false;
    }
  });
  return sResUrl;
};
//
exports.getQuery = function(name, bNotEscape){
  var sUrl = window.location.search.substr(1);
  var r = sUrl.match(new RegExp("(^|&)" + name + "=([^&]*)(&|$)"));
  if(bNotEscape){
    return (r === null ? null : r[2]);
  }else{
    return (r === null ? null : unescape(r[2]));
  }
};
//
exports.setQuery = function( key , value , url ){
  var aHash = url.match(/#.*(\?|$)/ig);
  var sHash = '';
  if(aHash && aHash[0]){
    sHash = aHash[0];
    url = url.replace(sHash, '');
  }
  url = url || window.location.href;
  url = url.replace( new RegExp( '(^|\\?)' + key + '=[^&]*(&|$|#)' , 'g' ) , '?' );
  url = url.replace( new RegExp( '(^|&)' + key + '=[^&]*(?=&|$|#)' , 'g' ) , '' );
  var p = key + '=' + encodeURIComponent(value);
  var sUrl = url;
  if(!(/\?$/.test( url ))){
    sUrl = url + ( /\?/.test( url ) ? '&' : '?' );
  }
  return sUrl + p + sHash;
};
//
exports.isEmail = function(sEmail){
  var rEmail = /([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})/i;
  return rEmail.test(sEmail);
};
//
exports.isMobile = function(sPhone){
  var rPhone = /^(13|14|15|17|18)\d{9}$/;
  return rPhone.test(sPhone);
};
//
exports.isUsername = function(sUsername){
  var rUsername = /^([A-Za-z\u4e00-\u9fa5])[A-Za-z0-9\u4e00-\u9fa5_-]{3,15}$/;
  return rUsername.test(sUsername);
};
//
exports.isRealname = function(sRealname){
  var rRealname = /^.{1,255}$/;
  return rRealname.test(sRealname);
};
//
exports.yuan = function(nFen){
  var nYuan = nFen / 100;
  return nYuan;
};
//
exports.inArray = function(){
  if(!Array.prototype.indexOf){
    Array.prototype.indexOf = function(elt, from){
      var len = this.length >>> 0;
      from = Number(arguments[1]) || 0;
      from = (from < 0) ? Math.ceil(from) : Math.floor(from);
      if (from < 0)
        from += len;

      for (; from < len; from++)
      {
        if (from in this &&
          this[from] === elt)
          return from;
      }
      return -1;
    };
  }
  return arguments[1].indexOf(arguments[0]);
};
//
exports.forEach = function (collection, callback, isNotObject, scope) {
  if (Object.prototype.toString.call(collection) === '[object Object]' && !isNotObject) {
    for (var prop in collection) {
      if (Object.prototype.hasOwnProperty.call(collection, prop)) {
        if(callback.call(scope, collection[prop], prop, collection) === false){
          break;
        }
      }
    }
  } else {
    for (var i = 0, len = collection.length; i < len; i++) {
      if(callback.call(scope, collection[i], i, collection) === false){
        break;
      }
    }
  }
};

/**
 * 实用工具集合
 *
 * ```setCookie
 * `` name
 * &` 类型：String<br/>需要设置的 cookie 名称。
 * `` value
 * &` 类型：String<br/>需要设置的 cookie 值。
 * `` isForever
 * &` 类型：Boolean ( 默认值：^^^false^^^ )<br/>设置为^^^true^^^，cookie 永不过期。
 * ```
 *
 * ```getCookie
 * `` name
 * &` 类型：String<br/>需要读取的 cookie 名称。
 * ```
 *
 * ```getImageUrl
 * `` image_id
 * &` 类型：String<br/>图片对象的 image_id。
 * `` image_name
 * &` 类型：String<br/>图片对象的 image_name。
 * `` image_size
 * &` 类型：String<br/>输出图片的尺寸大小，例如^^^300x300^^^。
 * `` image_epoch
 * &` 类型：String<br/>图片对象的 image_epoch。
 * ```
 *
 * ```getQuery
 * `` key
 * &` 类型：String<br/>需要获取的 url 参数名称。
 * ```
 *
 * ```setQuery
 * `` key
 * &` 类型：String<br/>需要设置的 url 参数名称。
 * `` value
 * &` 类型：String<br/>需要设置的 url 参数的值。
 * `` url
 * &` 类型：String<br/>需要设置参数的 url。
 * ```
 *
 * ```inArray
 * `` element
 * &` 类型：String|Object<br/>需要检查的元素。
 * `` array
 * &` 类型：Array<br/>需要检查的数组。
 * ```
 *
 * ```forEach
 * `` collection
 * &` 类型：Array|Object<br/>需要遍历的数组或对象。
 * `` callback
 * &` 类型：Function( 单个元素 )<br/>回调函数，返回^^^false^^^可停止遍历。
 * ```
 *
 * ```isEmail
 * `` email
 * &` 类型：String<br/>需要检测是否合法的 email，合法则返回^^^true^^^，不合法则返回^^^false^^^。
 * ```
 *
 * ```isMobile
 * `` mobile
 * &` 类型：String<br/>需要检测是否合法的中国大陆手机，合法则返回^^^true^^^，不合法则返回^^^false^^^。
 * ```
 *
 * ```isUsername
 * `` username
 * &` 类型：String<br/>需要检测是否合法的用户名，合法则返回^^^true^^^，不合法则返回^^^false^^^。
 * ```
 *
 * ```isRealname
 * `` realname
 * &` 类型：String<br/>需要检测是否合法的真实姓名，合法则返回^^^true^^^，不合法则返回^^^false^^^。
 * ```
 *
 * ```orderCalculator
 * `` return
 * &` 调用此方法将返回一个计算器实例，具有以下方法：
 * &&` ^^^update(object)^^^：更新数据，参数形如^^^{item_amount: 90}^^^，可接收的^^^key^^^及其具体意义可以调用^^^help^^^方法查看
 * &&` ^^^get([callback])^^^：返回订单计算结果，可接受一个回调函数，参数为订单计算结果
 * &&` ^^^help()^^^：在控制台打印帮助信息
 * &&&
 * &&& ^^^
 * &&& var Calc = Jssdk.util.orderCalculator();
 * &&& Calc.update({
 * &&&     item_amount: 90, // 商品总金额
 * &&&     shipment_amount: 10 // 运费总金额
 * &&& });
 * &&& var final_amount;
 * &&& Calc.get(function(result) {
 * &&&     final_amount = result.final_amount; //实付金额
 * &&& });
 * &&& console.log(final_amount); // 100
 * &&& ^^^
 * ```
 *
 * @param {setCookie} `name,value[,isForever]` 设置 cookie
 * @param {getCookie} `name` 读取 cookie
 * @param {getImageUrl} `image_id,image_name,image_size,image_epoch` 将图片对象转换为 url
 * @param {getQuery} `key` 获取 url 中 search 部分的参数
 * @param {setQuery} `key,value,url` 设置 url 中 search 部分的参数
 * @param {inArray} `element,array` 检查目标对象是否在数组中
 * @param {forEach} `collection,callback` 遍历数组或对象中的所有元素
 * @param {isEmail} `email` 验证email是否合法
 * @param {isMobile} `mobile` 验证手机号码是否合法（中国大陆）
 * @param {isUsername} `username` 验证用户名是否合法
 * @param {isRealname} `realname` 验证真实姓名是否合法
 * @param {orderCalculator} 创建一个订单金额计算器
 *
 */
<|endoftext|>