<commit_before>/**
 * React Dropdown Tree Select
 * A lightweight, fast and highly customizable tree select component.
 * Hrusikesh Panda <hrusikesh.panda@dowjones.com>
 * Copyright (c) 2017 Dow Jones, Inc. <support@dowjones.com> (http://dowjones.com)
 * @LICENSE MIT
 */
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import cn from 'classnames/bind'
import Dropdown, { DropdownTrigger, DropdownContent } from 'react-simple-dropdown'
import TreeManager from './tree-manager'
import Tree from './tree'
import Input from './input'
import styles from './index.css'

const cx = cn.bind(styles)

class DropdownTreeSelect extends Component {
  static propTypes = {
    data: PropTypes.oneOfType([
      PropTypes.object,
      PropTypes.array
    ]).isRequired,
    placeholderText: PropTypes.string,
    showDropdown: PropTypes.bool,
    onChange: PropTypes.func,
    onAction: PropTypes.func
  }

  constructor (props) {
    super(props)
    this.state = {dropdownActive: this.props.showDropdown || false, searchModeOn: false}

    this.onInputChange = this.onInputChange.bind(this)
    this.onDrowdownHide = this.onDrowdownHide.bind(this)
    this.onCheckboxChange = this.onCheckboxChange.bind(this)
    this.notifyChange = this.notifyChange.bind(this)
    this.onTagRemove = this.onTagRemove.bind(this)
    this.onNodeToggle = this.onNodeToggle.bind(this)
  }

  notifyChange (data) {
    typeof this.props.onChange === 'function' && this.props.onChange(data)
  }

  createList (tree) {
    this.treeManager = new TreeManager(tree)
    return this.treeManager.tree
  }

  resetSearch = () => {
    // restore the tree to its pre-search state
    this.setState({tree: this.treeManager.restoreNodes(), searchModeOn: false, allNodesHidden: false})
    // clear the search criteria and avoid react controlled/uncontrolled warning
    this.searchInput.value = ''
  }

  componentWillMount () {
    const tree = this.createList(this.props.data)
    const tags = this.treeManager.getTags()
    this.setState({tree, tags})
  }

  componentWillReceiveProps (nextProps) {
    const tree = this.createList(nextProps.data)
    const tags = this.treeManager.getTags()
    this.setState({tree, tags})
  }

  onDrowdownHide () {
    // needed when you click an item in tree and then click back in the input box.
    // react-simple-dropdown behavior is toggle since its single select only
    // but we want the drawer to remain open in this scenario as we support multi select
    if (this.keepDropdownActive) {
      this.dropdown.show()
    } else {
      this.resetSearch()
    }
  }

  onInputChange (value) {
    const {allNodesHidden, tree} = this.treeManager.filterTree(value)
    const searchModeOn = value.length > 0

    this.setState({tree, searchModeOn, allNodesHidden})
  }

  onTagRemove (id) {
    this.onCheckboxChange(id, false)
  }

  onNodeToggle (id) {
    this.treeManager.toggleNodeExpandState(id)
    this.setState({ tree: this.treeManager.tree })
  }

  onCheckboxChange (id, checked) {
    this.treeManager.setNodeCheckedState(id, checked)
    const tags = this.treeManager.getTags()
    this.setState({tree: this.treeManager.tree, tags})
    this.notifyChange(tags)
  }

  onAction = (actionId, nodeId) => {
    typeof this.props.onAction === 'function' && this.props.onAction(actionId, this.treeManager.getNodeById(nodeId))
  }

  render () {
    return (

        <Dropdown ref={el => { this.dropdown = el }} onHide={this.onDrowdownHide}>
          <DropdownTrigger className={cx('dropdown-trigger')}>
            <Input
              inputRef={el => { this.searchInput = el }}
              tags={this.state.tags}
              placeholderText={this.props.placeholderText}
              onInputChange={this.onInputChange}
              onFocus={() => { this.keepDropdownActive = true }}
              onBlur={() => { this.keepDropdownActive = false }}
              onTagRemove={this.onTagRemove} />
          </DropdownTrigger>
          <DropdownContent className={cx('dropdown-content')}>
            {this.state.allNodesHidden
              ? No matches found
              : (<Tree data={this.state.tree}
                       searchModeOn={this.state.searchModeOn}
                       onAction={this.onAction}
                       onCheckboxChange={this.onCheckboxChange}
                       onNodeToggle={this.onNodeToggle} />)
            }
          </DropdownContent>
        </Dropdown>

    )
  }
}

export default DropdownTreeSelect
<commit_msg>Preserve comments while minifying<commit_after>/*!
 * React Dropdown Tree Select
 * A lightweight, fast and highly customizable tree select component.
 * Hrusikesh Panda <hrusikesh.panda@dowjones.com>
 * Copyright (c) 2017 Dow Jones, Inc. <support@dowjones.com> (http://dowjones.com)
 * license MIT
 * see https://github.com/dowjones/react-dropdown-tree-select
 */
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import cn from 'classnames/bind'
import Dropdown, { DropdownTrigger, DropdownContent } from 'react-simple-dropdown'
import TreeManager from './tree-manager'
import Tree from './tree'
import Input from './input'
import styles from './index.css'

const cx = cn.bind(styles)

class DropdownTreeSelect extends Component {
  static propTypes = {
    data: PropTypes.oneOfType([
      PropTypes.object,
      PropTypes.array
    ]).isRequired,
    placeholderText: PropTypes.string,
    showDropdown: PropTypes.bool,
    onChange: PropTypes.func,
    onAction: PropTypes.func
  }

  constructor (props) {
    super(props)
    this.state = {dropdownActive: this.props.showDropdown || false, searchModeOn: false}

    this.onInputChange = this.onInputChange.bind(this)
    this.onDrowdownHide = this.onDrowdownHide.bind(this)
    this.onCheckboxChange = this.onCheckboxChange.bind(this)
    this.notifyChange = this.notifyChange.bind(this)
    this.onTagRemove = this.onTagRemove.bind(this)
    this.onNodeToggle = this.onNodeToggle.bind(this)
  }

  notifyChange (data) {
    typeof this.props.onChange === 'function' && this.props.onChange(data)
  }

  createList (tree) {
    this.treeManager = new TreeManager(tree)
    return this.treeManager.tree
  }

  resetSearch = () => {
    // restore the tree to its pre-search state
    this.setState({tree: this.treeManager.restoreNodes(), searchModeOn: false, allNodesHidden: false})
    // clear the search criteria and avoid react controlled/uncontrolled warning
    this.searchInput.value = ''
  }

  componentWillMount () {
    const tree = this.createList(this.props.data)
    const tags = this.treeManager.getTags()
    this.setState({tree, tags})
  }

  componentWillReceiveProps (nextProps) {
    const tree = this.createList(nextProps.data)
    const tags = this.treeManager.getTags()
    this.setState({tree, tags})
  }

  onDrowdownHide () {
    // needed when you click an item in tree and then click back in the input box.
    // react-simple-dropdown behavior is toggle since its single select only
    // but we want the drawer to remain open in this scenario as we support multi select
    if (this.keepDropdownActive) {
      this.dropdown.show()
    } else {
      this.resetSearch()
    }
  }

  onInputChange (value) {
    const {allNodesHidden, tree} = this.treeManager.filterTree(value)
    const searchModeOn = value.length > 0

    this.setState({tree, searchModeOn, allNodesHidden})
  }

  onTagRemove (id) {
    this.onCheckboxChange(id, false)
  }

  onNodeToggle (id) {
    this.treeManager.toggleNodeExpandState(id)
    this.setState({ tree: this.treeManager.tree })
  }

  onCheckboxChange (id, checked) {
    this.treeManager.setNodeCheckedState(id, checked)
    const tags = this.treeManager.getTags()
    this.setState({tree: this.treeManager.tree, tags})
    this.notifyChange(tags)
  }

  onAction = (actionId, nodeId) => {
    typeof this.props.onAction === 'function' && this.props.onAction(actionId, this.treeManager.getNodeById(nodeId))
  }

  render () {
    return (

        <Dropdown ref={el => { this.dropdown = el }} onHide={this.onDrowdownHide}>
          <DropdownTrigger className={cx('dropdown-trigger')}>
            <Input
              inputRef={el => { this.searchInput = el }}
              tags={this.state.tags}
              placeholderText={this.props.placeholderText}
              onInputChange={this.onInputChange}
              onFocus={() => { this.keepDropdownActive = true }}
              onBlur={() => { this.keepDropdownActive = false }}
              onTagRemove={this.onTagRemove} />
          </DropdownTrigger>
          <DropdownContent className={cx('dropdown-content')}>
            {this.state.allNodesHidden
              ? No matches found
              : (<Tree data={this.state.tree}
                       searchModeOn={this.state.searchModeOn}
                       onAction={this.onAction}
                       onCheckboxChange={this.onCheckboxChange}
                       onNodeToggle={this.onNodeToggle} />)
            }
          </DropdownContent>
        </Dropdown>

    )
  }
}

export default DropdownTreeSelect
<|endoftext|>


<commit_before>'use strict';

const https = require('https');
const querystring = require('querystring');

const VERSION = 'v1';
const BASEURL = 'api.football-data.org';
const HEADERS = {
    auth: 'X-Auth-Token',
    response: 'X-Response-Control'
};
const METADATA = {
    context: 'x-application-context',
    response: 'x-response-control',
    version: 'x-api-version',
    client: 'x-authenticated-client',
    reset: 'x-requestcounter-reset',
    available: 'x-requests-available'
};

class FootballData {
    constructor(options) {
        this.options = options || {};
    }

    static leagueAbbrevations() {
        return {
            BL1: '1. Bundesliga',
            BL2: '2. Bundesliga',
            BL3: '3. Bundesliga',
            DFB: 'DFB-Pokal',
            PL: 'Premiere League',
            EL1: 'League One',
            ELC: 'Championship',
            FAC: 'FA-Cup',
            SA: 'Serie A',
            SB: 'Serie B',
            PD: 'Primera Division',
            SD: 'Segunda Division',
            CDR: 'Copa del Rey',
            FL1: 'Ligue 1',
            FL2: 'Ligue 2',
            DED: 'Eredivisie',
            PPL: 'Primeira Liga',
            GSL: 'Primeira Liga',
            CL: 'Champions-League',
            EL: 'UEFA-Cup',
            EC: 'European-Cup of Nations',
            WC: 'World-Cup'
        };
    }

    static filters() {
        return {
            id: /^[0-9]+$/,
            matchday: /^[1-4]*[0-9]*$/,
            season: /^\d\d\d\d$/,
            head2head: /^[0-9]+$/,
            venue: /^away|home$/,
            league: /^[\w\d]{2,4}(,[\w\d]{2,4})*$/,
            timeFrame: /^(p|n)[1-9][0-9]?$/
        };
    }

    static options() {
        return {
            auth: /^[a-z0-9]+$/,
            response: /^(full|minified|compressed)$/
        };
    }

    static buildMetaData(headers) {
        const meta = {
            timestamp: Date.now()
        };
        if (headers) {
            const keys = Object.keys(METADATA);
            keys.forEach((type) => {
                if (Object.prototype.hasOwnProperty.call(headers, METADATA[type])) {
                    if (isNaN(headers[METADATA[type]])) {
                        meta[type] = headers[METADATA[type]];
                    } else {
                        meta[type] = parseInt(headers[METADATA[type]]);
                    }
                }
            });
        }

        return meta;
    }

    static buildQueryFilters(whitelist, filters) {
        if (!Array.isArray(whitelist) || !(filters instanceof Object)) {
            return '';
        }

        const queryObject = Object.assign({}, filters);

        const keys = Object.keys(queryObject);
        keys.forEach((filter) => {
            if (whitelist.indexOf(filter) === -1 || !FootballData.filters()[filter].test(queryObject[filter])) {
                delete queryObject[filter];
            }
        });

        const query = querystring.stringify(queryObject);

        return query.length >= 1 ? `?${query}` : '';
    }

    get(options) {
        return new Promise((resolve, reject) => {
            https.get(options, (res) => {
                const status = res.statusCode;
                const contentType = res.headers['content-type'];

                if (!/^application\/json/.test(contentType)) {
                    res.resume();
                    reject({
                        status: 406,
                        error: `Invalid content-type. Expected application/json but received ${contentType}`
                    });
                }

                res.setEncoding('utf8');
                let raw = '';
                res.on('data', (chunk) => { raw += chunk; });
                res.on('end', () => {
                    try {
                        const data = JSON.parse(raw);
                        if (status === 200) {
                            const response = { data };
                            if (this.options.meta) {
                                response.meta = FootballData.buildMetaData(res.headers);
                            }
                            resolve(response);
                        } else {
                            reject({ status, error: data.error });
                        }
                    } catch (e) {
                        reject({ status, error: 'Parsing Failed!' });
                    }
                });
            }).on('error', (e) => {
                reject({ status: 9000, error: e.message });
            });
        });
    }

    buildHeaders() {
        const headers = {};

        const keys = Object.keys(HEADERS);
        keys.forEach((type) => {
            if (this.options[type] && FootballData.options()[type].test(this.options[type])) {
                headers[HEADERS[type]] = this.options[type];
            }
        });

        return headers;
    }

    buildOptions(path) {
        return {
            hostname: BASEURL,
            path: `/${VERSION}/${path}`,
            headers: this.buildHeaders()
        };
    }

    competitions(filters) {
        return this.get(
            this.buildOptions(`competitions/${FootballData.buildQueryFilters(['season'], filters)}`)
        );
    }
}

module.exports = FootballData;
<commit_msg>added documentation<commit_after>'use strict';

/**
 * @file index.js
 *
 * @author fewieden
 * @license MIT
 *
 * @see  https://github.com/fewieden/node-football-data-api
 */

/**
 * @external https
 * @see https://nodejs.org/api/https.html
 */
const https = require('https');

/**
 * @external querystring
 * @see https://nodejs.org/api/querystring.html
 */
const querystring = require('querystring');

/**
 * API version that's beeing used.
 * @const
 * @type {string}
 */
const VERSION = 'v1';

/**
 * Base url of the API.
 * @const
 * @type {string}
 */
const BASEURL = 'api.football-data.org';

/**
 * All request headers.
 * @const
 * @type {Object.<string, string>}
 */
const HEADERS = {
    auth: 'X-Auth-Token',
    response: 'X-Response-Control'
};

/**
 * All response headers.
 * @const
 * @type {Object.<string, string>}
 */
const METADATA = {
    context: 'x-application-context',
    response: 'x-response-control',
    version: 'x-api-version',
    client: 'x-authenticated-client',
    reset: 'x-requestcounter-reset',
    available: 'x-requests-available'
};

/**
 * Class representing the football-data API.
 *
 * @requires external:https
 * @requires external:querystring
 */
class FootballData {
    /**
     * Constructor for FootballData class.
     *
     * @param {Object=} options - Options for FootballData.
     * @param {string=} options.auth - Option to use API key to allow more requests.
     * @param {boolean=} options.meta - Option to return meta data with response.
     */
    constructor(options) {
        /**
         * @default {}
         */
        this.options = options || {};
    }

    /**
     * Returns all available league abbrevations and their corresponding names.
     *
     * @returns {Object.<string, string>} Keys are the abbrevations and values represent their name.
     */
    static leagueAbbrevations() {
        return {
            BL1: '1. Bundesliga',
            BL2: '2. Bundesliga',
            BL3: '3. Bundesliga',
            DFB: 'DFB-Pokal',
            PL: 'Premiere League',
            EL1: 'League One',
            ELC: 'Championship',
            FAC: 'FA-Cup',
            SA: 'Serie A',
            SB: 'Serie B',
            PD: 'Primera Division',
            SD: 'Segunda Division',
            CDR: 'Copa del Rey',
            FL1: 'Ligue 1',
            FL2: 'Ligue 2',
            DED: 'Eredivisie',
            PPL: 'Primeira Liga',
            GSL: 'Primeira Liga',
            CL: 'Champions-League',
            EL: 'UEFA-Cup',
            EC: 'European-Cup of Nations',
            WC: 'World-Cup'
        };
    }

    /**
     * Returns all available filters for data querys.
     *
     * @returns {Object.<string, RegExp>} Keys are the filter names and values represent their valid regular expression.
     */
    static filters() {
        return {
            id: /^[0-9]+$/,
            matchday: /^[1-4]*[0-9]*$/,
            season: /^\d\d\d\d$/,
            head2head: /^[0-9]+$/,
            venue: /^away|home$/,
            league: /^[\w\d]{2,4}(,[\w\d]{2,4})*$/,
            timeFrame: /^(p|n)[1-9][0-9]?$/
        };
    }

    /**
     * Returns all available class options.
     *
     * @returns {Object.<string, RegExp>} Keys are the option names and values represent their valid regular expression.
     */
    static options() {
        return {
            auth: /^[a-z0-9]+$/,
            response: /^(full|minified|compressed)$/
        };
    }

    /**
     * Builds response meta data based on response headers.
     *
     * @param {Object.<string, string>} headers - Response headers
     * @returns {Object.<string, string|int>} Contains at least request timestamp.
     *
     * @example Headers
     * {
     *   'x-application-context': 'production',
     *   'x-response-control': 'full',
     *   'x-api-version': 'v1',
     *   'x-authenticated-client': 'anonymous',
     *   'x-requestcounter-reset': '4057',
     *   'x-requests-available': '50'
     * }
     *
     * @example Return
     * {
     *   timestamp: 1,
     *   context: 'production',
     *   response: 'full',
     *   version: 'v1',
     *   client: 'anonymous',
     *   reset: 4057,
     *   available: 50
     * }
     */
    static buildMetaData(headers) {
        const meta = {
            timestamp: Date.now()
        };
        if (headers) {
            const keys = Object.keys(METADATA);
            keys.forEach((type) => {
                if (Object.prototype.hasOwnProperty.call(headers, METADATA[type])) {
                    if (isNaN(headers[METADATA[type]])) {
                        meta[type] = headers[METADATA[type]];
                    } else {
                        meta[type] = parseInt(headers[METADATA[type]]);
                    }
                }
            });
        }

        return meta;
    }

    /**
     * Builds querystring filter based on whitelist.
     *
     * @param {string[]} whitelist - Allowed filter parameter.
     * @param {Object.<string, *>} filters - Query filter
     * @returns {string} Querystring or empty string if filter doesn't match the criteria.
     *
     * @example Whitelist
     * ['season']
     *
     * @example Filters
     * {
     *   season: 2017
     * }
     *
     * @example Return
     * '?season=2017'
     */
    static buildQueryFilters(whitelist, filters) {
        if (!Array.isArray(whitelist) || !(filters instanceof Object)) {
            return '';
        }

        const queryObject = Object.assign({}, filters);

        const keys = Object.keys(queryObject);
        keys.forEach((filter) => {
            if (whitelist.indexOf(filter) === -1 || !FootballData.filters()[filter].test(queryObject[filter])) {
                delete queryObject[filter];
            }
        });

        const query = querystring.stringify(queryObject);

        return query.length >= 1 ? `?${query}` : '';
    }

    /**
     * Performs https get request API call.
     *
     * @param {Object} options - Https request options
     * @returns {Promise} Rejects on error with error object.
     * Resolves on success data.
     *
     * @example Options
     * {
     *   hostname: 'api.football-data.org',
     *   path: '/v1/competitions/',
     *   headers: {
     *     'X-Auth-Token': 'YOUR_API_KEY',
     *     'X-Response-Control': 'full'
     *   }
     * }
     *
     * @example Rejecting
     * {
     *   status: 400,
     *   error: 'Bad Request'
     * }
     *
     * @example Resolving
     * {
     *   data: [
     *     {
     *       id: 394,
     *       caption: '1. Bundesliga 2015/16',
     *       league: 'BL1',
     *       year: '2015',
     *       numberOfTeams: 18,
     *       numberOfGames: 306,
     *       lastUpdated: '2015-10-25T19:06:29Z'
     *     },
     *     {
     *       id: 395,
     *       caption: '2. Bundesliga 2015/16',
     *       league: 'BL2"',
     *       year: '2015',
     *       numberOfTeams: 18,
     *       numberOfGames: 306,
     *       lastUpdated: '2015-10-25T19:06:59Z'
     *     },
     *     ...
     *   ]
     * }
     */
    get(options) {
        return new Promise((resolve, reject) => {
            https.get(options, (res) => {
                const status = res.statusCode;
                const contentType = res.headers['content-type'];

                if (!/^application\/json/.test(contentType)) {
                    res.resume();
                    reject({
                        status: 406,
                        error: `Invalid content-type. Expected application/json but received ${contentType}`
                    });
                }

                res.setEncoding('utf8');
                let raw = '';
                res.on('data', (chunk) => { raw += chunk; });
                res.on('end', () => {
                    try {
                        const data = JSON.parse(raw);
                        if (status === 200) {
                            const response = { data };
                            if (this.options.meta) {
                                response.meta = FootballData.buildMetaData(res.headers);
                            }
                            resolve(response);
                        } else {
                            reject({ status, error: data.error });
                        }
                    } catch (e) {
                        reject({ status, error: 'Parsing Failed!' });
                    }
                });
            }).on('error', (e) => {
                reject({ status: 9000, error: e.message });
            });
        });
    }

    /**
     * Builds https request headers.
     *
     * @returns {Object.<string, string>}
     *
     * @example Return
     * {
     *   'X-Auth-Token': 'YOUR_API_KEY',
     *   'X-Response-Control': 'full'
     * }
     */
    buildHeaders() {
        const headers = {};

        const keys = Object.keys(HEADERS);
        keys.forEach((type) => {
            if (this.options[type] && FootballData.options()[type].test(this.options[type])) {
                headers[HEADERS[type]] = this.options[type];
            }
        });

        return headers;
    }

    /**
     * Builds https request options.
     *
     * @param {string} route - API route
     * @returns {{hostname: string, path: string, headers: Object.<string, string>}}
     *
     * @example Route
     * 'competitions/'
     *
     * @example Return
     * {
     *   hostname: 'api.football-data.org',
     *   path: '/v1/competitions/',
     *   headers: {
     *     'X-Auth-Token': 'YOUR_API_KEY',
     *     'X-Response-Control': 'full'
     *   }
     * }
     */
    buildOptions(route) {
        return {
            hostname: BASEURL,
            path: `/${VERSION}/${route}`,
            headers: this.buildHeaders()
        };
    }

    /**
     * Shorthand function for get() on competitions route /v1/competitions/.
     * @param {Object.<string, *>} filters - Query filter
     * @returns {Promise} Returns get() response.
     */
    competitions(filters) {
        return this.get(
            this.buildOptions(`competitions/${FootballData.buildQueryFilters(['season'], filters)}`)
        );
    }
}

module.exports = FootballData;
<|endoftext|>


<commit_before>"use strict";

var d3 = require('d3');

var Layer = module.exports = function() {
    var layerPath = "";
    var layerType = "";
    var layerVisibility = true;
    var layerActive = true;
    var layerRenderMode = "canvas";
    var layerClass = "default";
    var layerLabel = "unlabeled";
    var layerXCoord = function(d) {return d["x"]};
    var layerYCoord = function(d) {return d["y"]};
    var layerG;
    var layerObject;
    var layerFeatures;
    var layerTileType = "mapbox";
    var layerSpecific = "all";
    var layerMarkerSize = 5;
    var layerMarkerColor;
    var layerCluster = false;
    var clickableFeatures = false;
    var d3Modal;
    var layerDataset;

    var layerDispatch = d3.dispatch('load','recluster');

    var layer = function() {

    }

    layer.path = function(newPath) {
	if (!arguments.length) return layerPath;
	layerPath = newPath;
	return this;
    }

    layer.type = function(newType) {
	if (!arguments.length) return layerType;
	layerType = newType;
	return this;

    }

    layer.visibility = function(newVisibility) {
    	if (!arguments.length) return layerVisibility;
	layerVisibility = newVisibility;
	return this;
    }

    layer.renderMode = function(newMode) {
    	if (!arguments.length) return layerRenderMode;
	layerRenderMode = newMode;
	return this;
    }

    layer.clickableFeatures = function(newState) {
    	if (!arguments.length) return clickableFeatures;
	clickableFeatures = newState;
	return this;
    }
    layer.modal = function(newModal) {
	if (!arguments.length) return d3Modal;
	d3Modal = newModal;
	return this;
    }

    layer.x = function(newX) {
    	if (!arguments.length) return layerXCoord;
	if (typeof newX == "function") {
	    layerXCoord = newX;
	}
//A number
	else if (typeof newX == "number") {
	    layerXCoord = function(d) {return newX}
	}
//Otherwise assume a top-level attribute name
	else {
	    layerXCoord = function(d) {return d[newX]}
	}
	return this;
    }

    layer.y = function(newY) {
    	if (!arguments.length) return layerYCoord;
	if (typeof newY == "function") {
	    layerYCoord = newY;
	}
//A number
	else if (typeof newY == "number") {
	    layerYCoord = function(d) {return newY}
	}
//Otherwise assume a top-level attribute name
	else {
	    layerYCoord = function(d) {return d[newY]}
	}
	return this;
    }

    layer.markerSize = function(newSize) {
    	if (!arguments.length) return layerMarkerSize;
	if (typeof newSize == "function") {
	    layerMarkerSize = newSize;
	}
//A number
	else if (typeof newSize == "number") {
	    layerMarkerSize = function(d) {return newSize}
	}
//Otherwise assume a top-level attribute name
	else {
	    layerMarkerSize = function(d) {return d[newSize]}
	}
	return this;
    }

    layer.markerColor = function(newColor) {
    	if (!arguments.length) return layerMarkerColor;
	if (typeof newColor == "function") {
	    layerMarkerColor = newColor;
	}
//Else set color
	else {
	    layerMarkerColor = function(d) {return newColor}
	}
	return this;
    }

    layer.cssClass = function(newClass) {
    	if (!arguments.length) return layerClass;
	layerClass = newClass;
	return this;
    }

    layer.g = function(newG) {
    	if (!arguments.length) return layerG;
	layerG = newG;
	return this;
    }

    layer.object = function(newObject) {
    	if (!arguments.length) return layerObject;
	layerObject = newObject;
	layerDispatch.load();
	return this;
    }

    layer.features = function(newFeatures) {
    	if (!arguments.length) return layerFeatures;
	layerFeatures = newFeatures;
	return this;
    }
    layer.tileType = function(newType) {
    	if (!arguments.length) return layerTileType;
	layerTileType = newType;
	return this;
    }
    layer.label = function(newLabel) {
    	if (!arguments.length) return layerLabel;
	layerLabel = newLabel;
	return this;
    }
    layer.specificFeature = function(newSpecific) {
    	if (!arguments.length) return layerSpecific;
	layerSpecific = newSpecific;
	return this;
    }

    layer.dataset = function(newDataset) {
    	if (!arguments.length) return layerDataset;
	layerDataset = newDataset;
	return this;
    }

    layer.cluster = function(newClusterSetting) {
    	if (!arguments.length) return layerCluster;
	layerCluster = newClusterSetting;
	return this;
    }

    layer.recluster = function() {
	layerDispatch.recluster();
    }

    layer.clusterLayer = function() {
	return layerObject.qtreeLayer;
    }

    d3.rebind(layer, layerDispatch, "on");
    return layer;
}

Layer.topojson = function() {
    return Layer().type("topojson");
}

Layer.geojson = function() {
    return Layer().type("geojson");
}

Layer.csv = function() {
    return Layer().type("csv");
}

Layer.xyArray = function() {
    return Layer().type("xyarray");
}

Layer.featureArray = function() {
    return Layer().type("featurearray");
}

Layer.tile = function() {
    return Layer().type("tile");
}
<commit_msg>Fixed markerSize bug<commit_after>"use strict";

var d3 = require('d3');

var Layer = module.exports = function() {
    var layerPath = "";
    var layerType = "";
    var layerVisibility = true;
    var layerActive = true;
    var layerRenderMode = "canvas";
    var layerClass = "default";
    var layerLabel = "unlabeled";
    var layerXCoord = function(d) {return d["x"]};
    var layerYCoord = function(d) {return d["y"]};
    var layerG;
    var layerObject;
    var layerFeatures;
    var layerTileType = "mapbox";
    var layerSpecific = "all";
    var layerMarkerSize = function() {return 5};
    var layerMarkerColor;
    var layerCluster = false;
    var clickableFeatures = false;
    var d3Modal;
    var layerDataset;

    var layerDispatch = d3.dispatch('load','recluster');

    var layer = function() {

    }

    layer.path = function(newPath) {
	if (!arguments.length) return layerPath;
	layerPath = newPath;
	return this;
    }

    layer.type = function(newType) {
	if (!arguments.length) return layerType;
	layerType = newType;
	return this;

    }

    layer.visibility = function(newVisibility) {
    	if (!arguments.length) return layerVisibility;
	layerVisibility = newVisibility;
	return this;
    }

    layer.renderMode = function(newMode) {
    	if (!arguments.length) return layerRenderMode;
	layerRenderMode = newMode;
	return this;
    }

    layer.clickableFeatures = function(newState) {
    	if (!arguments.length) return clickableFeatures;
	clickableFeatures = newState;
	return this;
    }
    layer.modal = function(newModal) {
	if (!arguments.length) return d3Modal;
	d3Modal = newModal;
	return this;
    }

    layer.x = function(newX) {
    	if (!arguments.length) return layerXCoord;
	if (typeof newX == "function") {
	    layerXCoord = newX;
	}
//A number
	else if (typeof newX == "number") {
	    layerXCoord = function(d) {return newX}
	}
//Otherwise assume a top-level attribute name
	else {
	    layerXCoord = function(d) {return d[newX]}
	}
	return this;
    }

    layer.y = function(newY) {
    	if (!arguments.length) return layerYCoord;
	if (typeof newY == "function") {
	    layerYCoord = newY;
	}
//A number
	else if (typeof newY == "number") {
	    layerYCoord = function(d) {return newY}
	}
//Otherwise assume a top-level attribute name
	else {
	    layerYCoord = function(d) {return d[newY]}
	}
	return this;
    }

    layer.markerSize = function(newSize) {
    	if (!arguments.length) return layerMarkerSize;
	if (typeof newSize == "function") {
	    layerMarkerSize = newSize;
	}
//A number
	else if (typeof newSize == "number") {
	    layerMarkerSize = function(d) {return newSize}
	}
//Otherwise assume a top-level attribute name
	else {
	    layerMarkerSize = function(d) {return d[newSize]}
	}
	return this;
    }

    layer.markerColor = function(newColor) {
    	if (!arguments.length) return layerMarkerColor;
	if (typeof newColor == "function") {
	    layerMarkerColor = newColor;
	}
//Else set color
	else {
	    layerMarkerColor = function(d) {return newColor}
	}
	return this;
    }

    layer.cssClass = function(newClass) {
    	if (!arguments.length) return layerClass;
	layerClass = newClass;
	return this;
    }

    layer.g = function(newG) {
    	if (!arguments.length) return layerG;
	layerG = newG;
	return this;
    }

    layer.object = function(newObject) {
    	if (!arguments.length) return layerObject;
	layerObject = newObject;
	layerDispatch.load();
	return this;
    }

    layer.features = function(newFeatures) {
    	if (!arguments.length) return layerFeatures;
	layerFeatures = newFeatures;
	return this;
    }
    layer.tileType = function(newType) {
    	if (!arguments.length) return layerTileType;
	layerTileType = newType;
	return this;
    }
    layer.label = function(newLabel) {
    	if (!arguments.length) return layerLabel;
	layerLabel = newLabel;
	return this;
    }
    layer.specificFeature = function(newSpecific) {
    	if (!arguments.length) return layerSpecific;
	layerSpecific = newSpecific;
	return this;
    }

    layer.dataset = function(newDataset) {
    	if (!arguments.length) return layerDataset;
	layerDataset = newDataset;
	return this;
    }

    layer.cluster = function(newClusterSetting) {
    	if (!arguments.length) return layerCluster;
	layerCluster = newClusterSetting;
	return this;
    }

    layer.recluster = function() {
	layerDispatch.recluster();
    }

    layer.clusterLayer = function() {
	return layerObject.qtreeLayer;
    }

    d3.rebind(layer, layerDispatch, "on");
    return layer;
}

Layer.topojson = function() {
    return Layer().type("topojson");
}

Layer.geojson = function() {
    return Layer().type("geojson");
}

Layer.csv = function() {
    return Layer().type("csv");
}

Layer.xyArray = function() {
    return Layer().type("xyarray");
}

Layer.featureArray = function() {
    return Layer().type("featurearray");
}

Layer.tile = function() {
    return Layer().type("tile");
}
<|endoftext|>


<commit_before>import webpack from 'webpack';
import webpackDevMiddleware from 'webpack-dev-middleware';
import webpackHotMiddleware from 'webpack-hot-middleware';
import httpProxyMiddleware from 'http-proxy-middleware';
import express from 'express';
import http from 'http';
import { spawn } from 'child_process';
import fs from 'fs';
import path from 'path';
import mkdirp from 'mkdirp';
import minilog from 'minilog';
import _ from 'lodash';
import crypto from 'crypto';
import VirtualModules from 'webpack-virtual-modules';
import waitOn from 'wait-on';
import { Android, Config, Project, ProjectSettings, Exp, UrlUtils } from 'xdl';
import devToolsMiddleware from 'haul-cli/src/server/middleware/devToolsMiddleware';
import liveReloadMiddleware from 'haul-cli/src/server/middleware/liveReloadMiddleware';
import statusPageMiddleware from 'haul-cli/src/server/middleware/statusPageMiddleware';
import symbolicateMiddleware from 'haul-cli/src/server/middleware/symbolicateMiddleware';
import openInEditorMiddleware from 'haul-cli/src/server/middleware/openInEditorMiddleware';
import loggerMiddleware from 'haul-cli/src/server/middleware/loggerMiddleware';
import missingBundleMiddleware from 'haul-cli/src/server/middleware/missingBundleMiddleware';
import systraceMiddleware from 'haul-cli/src/server/middleware/systraceMiddleware';
import rawBodyMiddleware from 'haul-cli/src/server/middleware/rawBodyMiddleware';
import bodyParser from 'body-parser';
import WebSocketProxy from 'haul-cli/src/server/util/WebsocketProxy';
import ConcatSource from 'webpack-sources/lib/ConcatSource';
import RawSource from 'webpack-sources/lib/RawSource';
import which from 'which';

import pkg from '../package.json';
// eslint-disable-next-line import/default
import configs from './webpack.config';

minilog.enable();

const logBack = minilog('webpack-for-backend');

const [serverConfig, clientConfig, dllConfig, androidConfig, iOSConfig] = configs;
const __WINDOWS__ = /^win/.test(process.platform);

let server;
let startBackend = false;
let backendFirstStart = true;

process.on('exit', () => {
  if (server) {
    server.kill('SIGTERM');
  }
});

function runServer(path) {
  if (startBackend) {
    startBackend = false;
    backendFirstStart = false;
    logBack('Starting backend');
    server = spawn('node', [path], { stdio: [0, 1, 2] });
    server.on('exit', code => {
      if (code === 250) {
        // App requested full reload
        startBackend = true;
      }
      logBack('Backend has been stopped');
      server = undefined;
      runServer(path);
    });
  }
}

function webpackReporter(outputPath, log, err, stats) {
  if (err) {
    log(err.stack);
    throw new Error("Build error");
  }
  if (stats) {
    log(stats.toString({
      hash: false,
      version: false,
      timings: true,
      assets: false,
      chunks: false,
      modules: false,
      reasons: false,
      children: false,
      source: true,
      errors: true,
      errorDetails: true,
      warnings: true,
      publicPath: false,
      colors: true
    }));

    if (!__DEV__) {
      mkdirp.sync(outputPath);
      fs.writeFileSync(path.join(outputPath, 'stats.json'), JSON.stringify(stats.toJson()));
    }
  }
}

var frontendVirtualModules = new VirtualModules({ 'node_modules/backend_reload.js': '' });

function startClient(config, platform) {
  const logger = minilog(`webpack-for-${config.name}`);
  try {
    const reporter = (...args) => webpackReporter(config.output.path, logger, ...args);

    config.plugins.push(frontendVirtualModules);

    if (__DEV__) {
      if (pkg.app.reactHotLoader) {
        config.entry[Object.keys(config.entry)[0]].unshift('react-hot-loader/patch');
      }
      config.entry[Object.keys(config.entry)[0]].unshift(
        `webpack-hot-middleware/client?http://localhost:${clientConfig.devServer.port}/`);
      config.plugins.push(new webpack.HotModuleReplacementPlugin(),
        new webpack.NoEmitOnErrorsPlugin());
      startWebpackDevServer(config, platform, reporter, logger);
    } else {
      const compiler = webpack(config);

      compiler.run(reporter);
    }
  } catch (err) {
    logger(err.message, err.stack);
  }
}

let backendReloadCount = 0;
function increaseBackendReloadCount() {
  backendReloadCount++;
  frontendVirtualModules.writeModule('node_modules/backend_reload.js',
    `var count = ${backendReloadCount};\n`);
}

function startServer() {
  try {
    const reporter = (...args) => webpackReporter(serverConfig.output.path, logBack, ...args);

    if (__DEV__) {
      if (__WINDOWS__) {
        serverConfig.entry.index.push('webpack/hot/poll?1000');
      } else {
        serverConfig.entry.index.push('webpack/hot/signal.js');
      }
      serverConfig.plugins.push(new webpack.HotModuleReplacementPlugin(),
        new webpack.NoEmitOnErrorsPlugin());
    }

    const compiler = webpack(serverConfig);

    if (__DEV__) {
      compiler.plugin('compilation', compilation => {
        compilation.plugin('after-optimize-assets', assets => {
          // Patch webpack-generated original source files path, by stripping hash after filename
          const mapKey = _.findKey(assets, (v, k) => k.endsWith('.map'));
          if (mapKey) {
            var srcMap = JSON.parse(assets[mapKey]._value);
            for (var idx in srcMap.sources) {
              srcMap.sources[idx] = srcMap.sources[idx].split(';')[0];
            }
            assets[mapKey]._value = JSON.stringify(srcMap);
          }
        });
      });

      compiler.watch({}, reporter);

      compiler.plugin('done', stats => {
        const { output } = serverConfig;
        startBackend = true;
        if (server) {
          if (!__WINDOWS__) {
            server.kill('SIGUSR2');
          }

          if (pkg.app.frontendRefreshOnBackendChange) {
            for (let module of stats.compilation.modules) {
              if (module.built && module.resource &&
                module.resource.indexOf(path.resolve('./src/server')) === 0) {
                // Force front-end refresh on back-end change
                logBack.debug('Force front-end current page refresh, due to change in backend at:', module.resource);
                increaseBackendReloadCount();
                break;
              }
            }
          }
        } else {
          runServer(path.join(output.path, 'index.js'));
        }
      });
    } else {
      compiler.run(reporter);
    }
  } catch (err) {
    logBack(err.message, err.stack);
  }
}

function startWebpackDevServer(config, platform, reporter, logger) {
  const configOutputPath = config.output.path;
  config.output.path = '/';

  config.plugins.push(frontendVirtualModules);

  let compiler = webpack(config);

  compiler.plugin('after-emit', (compilation, callback) => {
    if (backendFirstStart) {
      logger.debug("Webpack dev server is waiting for backend to start...");
      waitOn({ resources: [`tcp:localhost:${pkg.app.apiPort}`] }, err => {
        if (err) {
          logger.error(err);
        } else {
          logger.debug("Backend has been started, resuming webpack dev server...");
          callback();
        }
      });
    } else {
      callback();
    }
  });
  if (pkg.app.webpackDll && platform !== 'web') {
    compiler.plugin('after-compile', (compilation, callback) => {
      let vendorHashesJson = JSON.parse(fs.readFileSync(path.join(pkg.app.frontendBuildDir, 'vendor_dll_hashes.json')));
      Object.keys(compilation.assets).forEach(key => {
        if (key.endsWith('.bundle')) {
          const vendorContents = fs.readFileSync(path.join(pkg.app.frontendBuildDir, vendorHashesJson.name)).toString();
          compilation.assets[key] = new ConcatSource(new RawSource(vendorContents), compilation.assets[key]);
        }
      });
      callback();
    });
  }
  compiler.plugin('done', stats => {
    const dir = configOutputPath;
    mkdirp.sync(dir);
    if (stats.compilation.assets['assets.json']) {
      const assetsMap = JSON.parse(stats.compilation.assets['assets.json'].source());
      _.each(stats.toJson().assetsByChunkName, (assets, bundle) => {
        const bundleJs = assets.constructor === Array ? assets[0] : assets;
        assetsMap[`${bundle}.js`] = bundleJs;
        if (assets.length > 1) {
          assetsMap[`${bundle}.js.map`] = `${bundleJs}.map`;
        }
      });
      if (pkg.app.webpackDll) {
        let vendorHashesJson = JSON.parse(fs.readFileSync(path.join(pkg.app.frontendBuildDir, 'vendor_dll_hashes.json')));
        assetsMap['vendor.js'] = vendorHashesJson.name;
      }
      fs.writeFileSync(path.join(dir, 'assets.json'), JSON.stringify(assetsMap));
    }
  });

  const app = express();

  const httpServer = http.createServer(app);

  app.use((req, res, next) => {
    console.log("req:", req.url);
    next();
  });

  if (platform !== 'web') {
    const debuggerProxy = new WebSocketProxy(httpServer, '/debugger-proxy');

    app.use(rawBodyMiddleware)
      .use(bodyParser.text())
      .use(devToolsMiddleware(debuggerProxy))
      .use(liveReloadMiddleware(compiler))
      .use(statusPageMiddleware)
      .use(symbolicateMiddleware(compiler))
      .use(openInEditorMiddleware())
      .use('/systrace', systraceMiddleware)
      .use(loggerMiddleware);
  }

  app.use(webpackDevMiddleware(compiler, _.merge({}, config.devServer, {
    reporter({state, stats}) {
      if (state) {
        logger("bundle is now VALID.");
      } else {
        logger("bundle is now INVALID.");
      }
      reporter(null, stats);
    }
  })))
  .use(webpackHotMiddleware(compiler, { log: false }));

  if (config.devServer.proxy) {
    Object.keys(config.devServer.proxy).forEach(key => {
      app.use(httpProxyMiddleware(key, config.devServer.proxy[key]));
    });
  }
  if (platform !== 'web') {
    app.use(missingBundleMiddleware);
  }

  logger(`Webpack ${config.name} dev server listening on ${config.devServer.port}`);
  app.listen(config.devServer.port);
}

function useWebpackDll() {
  console.log("Using Webpack DLL vendor bundle");
  const jsonPath = path.join('..', pkg.app.frontendBuildDir, 'vendor_dll.json');
  [clientConfig, androidConfig, iOSConfig].forEach(config =>
    config.plugins.push(new webpack.DllReferencePlugin({
      context: process.cwd(),
      manifest: require(jsonPath) // eslint-disable-line import/no-dynamic-require
    }))
  );
  serverConfig.plugins.push(new webpack.DllReferencePlugin({
    context: process.cwd(),
    manifest: require(jsonPath) // eslint-disable-line import/no-dynamic-require
  }));
}

function isDllValid() {
  try {
    const hashesPath = path.join(pkg.app.frontendBuildDir, 'vendor_dll_hashes.json');
    if (!fs.existsSync(hashesPath)) {
      console.warn("Vendor DLL does not exists");
      return false;
    }
    let meta = JSON.parse(fs.readFileSync(hashesPath));
    if (!fs.existsSync(path.join(pkg.app.frontendBuildDir, meta.name))) {
      console.warn("Vendor DLL does not exists");
      return false;
    }
    if (!_.isEqual(meta.modules, dllConfig.entry.vendor)) {
      console.warn('Modules bundled into vendor DLL changed, need to rebuild it');
      return false;
    }

    let json = JSON.parse(fs.readFileSync(path.join(pkg.app.frontendBuildDir, 'vendor_dll.json')));

    for (let filename of Object.keys(json.content)) {
      if (filename.indexOf(' ') < 0) {
        if (!fs.existsSync(filename)) {
          console.warn("Vendor bundle need to be regenerated, file: " + filename + " is missing.");
          return false;
        }
        const hash = crypto.createHash('md5').update(fs.readFileSync(filename)).digest('hex');
        if (meta.hashes[filename] !== hash) {
          console.warn(`Hash for vendor DLL file ${filename} changed, need to rebuild vendor bundle`);
          return false;
        }
      }
    }

    return true;
  } catch (e) {
    console.warn('Error checking vendor bundle, regenerating it...', e);

    return false;
  }
}

function buildDll() {
  return new Promise((done) => {
    if (!isDllValid()) {
      console.log("Generating vendor DLL bundle...");

      const compiler = webpack(dllConfig);

      compiler.run((err, stats) => {
        let json = JSON.parse(fs.readFileSync(path.join(pkg.app.frontendBuildDir, 'vendor_dll.json')));
        const vendorKey = _.findKey(stats.compilation.assets,
          (v, key) => key.startsWith('vendor') && key.endsWith('_dll.js'));
        const meta = { name: vendorKey, hashes: {}, modules: dllConfig.entry.vendor };
        for (let filename of Object.keys(json.content)) {
          if (filename.indexOf(' ') < 0) {
            meta.hashes[filename] = crypto.createHash('md5').update(fs.readFileSync(filename)).digest('hex');
            fs.writeFileSync(path.join(pkg.app.frontendBuildDir, 'vendor_dll_hashes.json'), JSON.stringify(meta));
          }
        }
        done();
      });
    } else {
      done();
    }
  });
}

async function startExpoServer() {
  try {
    Config.validation.reactNativeVersionWarnings = false;
    Config.developerTool = 'crna';
    Config.offline = true;
    Exp.determineEntryPointAsync = () => 'index.android';

    const projectRoot = path.resolve('.');
    await Project.startExpoServerAsync(projectRoot);
    await ProjectSettings.setPackagerInfoAsync(projectRoot, {
      packagerPort: 3010
    });

    const address = await UrlUtils.constructManifestUrlAsync(projectRoot);
    console.log("Expo address:", address);
    which('adb', (err, result) => {
      console.log("Using adb at:", result);
    });
    const { success, error } = await Android.openProjectAsync(projectRoot);
    if (!success) {
      console.log(error.message);
    }
  } catch (e) {
    console.error(e.stack);
  }
}

function startWebpack() {
  startExpoServer();
  startServer();
  startClient(clientConfig, "web");
  startClient(androidConfig, "android");
  // startClient(iOSConfig, "ios");
}

if (!__DEV__ || !pkg.app.webpackDll) {
  startWebpack();
} else {
  buildDll().then(function() {
    useWebpackDll();
    startWebpack();
  });
}
<commit_msg>Add support for running Expo server for iOS<commit_after>import webpack from 'webpack';
import webpackDevMiddleware from 'webpack-dev-middleware';
import webpackHotMiddleware from 'webpack-hot-middleware';
import httpProxyMiddleware from 'http-proxy-middleware';
import express from 'express';
import http from 'http';
import { spawn } from 'child_process';
import fs from 'fs';
import path from 'path';
import mkdirp from 'mkdirp';
import minilog from 'minilog';
import _ from 'lodash';
import crypto from 'crypto';
import VirtualModules from 'webpack-virtual-modules';
import waitOn from 'wait-on';
import { Android, Simulator, Config, Project, ProjectSettings, Exp, UrlUtils } from 'xdl';
import devToolsMiddleware from 'haul-cli/src/server/middleware/devToolsMiddleware';
import liveReloadMiddleware from 'haul-cli/src/server/middleware/liveReloadMiddleware';
import statusPageMiddleware from 'haul-cli/src/server/middleware/statusPageMiddleware';
import symbolicateMiddleware from 'haul-cli/src/server/middleware/symbolicateMiddleware';
import openInEditorMiddleware from 'haul-cli/src/server/middleware/openInEditorMiddleware';
import loggerMiddleware from 'haul-cli/src/server/middleware/loggerMiddleware';
import missingBundleMiddleware from 'haul-cli/src/server/middleware/missingBundleMiddleware';
import systraceMiddleware from 'haul-cli/src/server/middleware/systraceMiddleware';
import rawBodyMiddleware from 'haul-cli/src/server/middleware/rawBodyMiddleware';
import bodyParser from 'body-parser';
import WebSocketProxy from 'haul-cli/src/server/util/WebsocketProxy';
import ConcatSource from 'webpack-sources/lib/ConcatSource';
import RawSource from 'webpack-sources/lib/RawSource';
import which from 'which';

import pkg from '../package.json';
// eslint-disable-next-line import/default
import configs from './webpack.config';

minilog.enable();

const logBack = minilog('webpack-for-backend');

const [serverConfig, clientConfig, dllConfig, androidConfig, iOSConfig] = configs;
const __WINDOWS__ = /^win/.test(process.platform);

let server;
let startBackend = false;
let backendFirstStart = true;

process.on('exit', () => {
  if (server) {
    server.kill('SIGTERM');
  }
});

function runServer(path) {
  if (startBackend) {
    startBackend = false;
    backendFirstStart = false;
    logBack('Starting backend');
    server = spawn('node', [path], { stdio: [0, 1, 2] });
    server.on('exit', code => {
      if (code === 250) {
        // App requested full reload
        startBackend = true;
      }
      logBack('Backend has been stopped');
      server = undefined;
      runServer(path);
    });
  }
}

function webpackReporter(outputPath, log, err, stats) {
  if (err) {
    log(err.stack);
    throw new Error("Build error");
  }
  if (stats) {
    log(stats.toString({
      hash: false,
      version: false,
      timings: true,
      assets: false,
      chunks: false,
      modules: false,
      reasons: false,
      children: false,
      source: true,
      errors: true,
      errorDetails: true,
      warnings: true,
      publicPath: false,
      colors: true
    }));

    if (!__DEV__) {
      mkdirp.sync(outputPath);
      fs.writeFileSync(path.join(outputPath, 'stats.json'), JSON.stringify(stats.toJson()));
    }
  }
}

var frontendVirtualModules = new VirtualModules({ 'node_modules/backend_reload.js': '' });

function startClient(config, platform) {
  const logger = minilog(`webpack-for-${config.name}`);
  try {
    const reporter = (...args) => webpackReporter(config.output.path, logger, ...args);

    config.plugins.push(frontendVirtualModules);

    if (__DEV__) {
      if (['android', 'ios'].indexOf(platform) >= 0) {
        startExpoServer(config, platform);
      }
      if (pkg.app.reactHotLoader) {
        config.entry[Object.keys(config.entry)[0]].unshift('react-hot-loader/patch');
      }
      config.entry[Object.keys(config.entry)[0]].unshift(
        `webpack-hot-middleware/client?http://localhost:${clientConfig.devServer.port}/`);
      config.plugins.push(new webpack.HotModuleReplacementPlugin(),
        new webpack.NoEmitOnErrorsPlugin());
      startWebpackDevServer(config, platform, reporter, logger);
    } else {
      const compiler = webpack(config);

      compiler.run(reporter);
    }
  } catch (err) {
    logger(err.message, err.stack);
  }
}

let backendReloadCount = 0;
function increaseBackendReloadCount() {
  backendReloadCount++;
  frontendVirtualModules.writeModule('node_modules/backend_reload.js',
    `var count = ${backendReloadCount};\n`);
}

function startServer() {
  try {
    const reporter = (...args) => webpackReporter(serverConfig.output.path, logBack, ...args);

    if (__DEV__) {
      if (__WINDOWS__) {
        serverConfig.entry.index.push('webpack/hot/poll?1000');
      } else {
        serverConfig.entry.index.push('webpack/hot/signal.js');
      }
      serverConfig.plugins.push(new webpack.HotModuleReplacementPlugin(),
        new webpack.NoEmitOnErrorsPlugin());
    }

    const compiler = webpack(serverConfig);

    if (__DEV__) {
      compiler.plugin('compilation', compilation => {
        compilation.plugin('after-optimize-assets', assets => {
          // Patch webpack-generated original source files path, by stripping hash after filename
          const mapKey = _.findKey(assets, (v, k) => k.endsWith('.map'));
          if (mapKey) {
            var srcMap = JSON.parse(assets[mapKey]._value);
            for (var idx in srcMap.sources) {
              srcMap.sources[idx] = srcMap.sources[idx].split(';')[0];
            }
            assets[mapKey]._value = JSON.stringify(srcMap);
          }
        });
      });

      compiler.watch({}, reporter);

      compiler.plugin('done', stats => {
        const { output } = serverConfig;
        startBackend = true;
        if (server) {
          if (!__WINDOWS__) {
            server.kill('SIGUSR2');
          }

          if (pkg.app.frontendRefreshOnBackendChange) {
            for (let module of stats.compilation.modules) {
              if (module.built && module.resource &&
                module.resource.indexOf(path.resolve('./src/server')) === 0) {
                // Force front-end refresh on back-end change
                logBack.debug('Force front-end current page refresh, due to change in backend at:', module.resource);
                increaseBackendReloadCount();
                break;
              }
            }
          }
        } else {
          runServer(path.join(output.path, 'index.js'));
        }
      });
    } else {
      compiler.run(reporter);
    }
  } catch (err) {
    logBack(err.message, err.stack);
  }
}

function startWebpackDevServer(config, platform, reporter, logger) {
  const configOutputPath = config.output.path;
  config.output.path = '/';

  config.plugins.push(frontendVirtualModules);

  let compiler = webpack(config);

  compiler.plugin('after-emit', (compilation, callback) => {
    if (backendFirstStart) {
      logger.debug("Webpack dev server is waiting for backend to start...");
      waitOn({ resources: [`tcp:localhost:${pkg.app.apiPort}`] }, err => {
        if (err) {
          logger.error(err);
        } else {
          logger.debug("Backend has been started, resuming webpack dev server...");
          callback();
        }
      });
    } else {
      callback();
    }
  });
  if (pkg.app.webpackDll && platform !== 'web') {
    compiler.plugin('after-compile', (compilation, callback) => {
      let vendorHashesJson = JSON.parse(fs.readFileSync(path.join(pkg.app.frontendBuildDir, 'vendor_dll_hashes.json')));
      Object.keys(compilation.assets).forEach(key => {
        if (key.endsWith('.bundle')) {
          const vendorContents = fs.readFileSync(path.join(pkg.app.frontendBuildDir, vendorHashesJson.name)).toString();
          compilation.assets[key] = new ConcatSource(new RawSource(vendorContents), compilation.assets[key]);
        }
      });
      callback();
    });
  }
  compiler.plugin('done', stats => {
    const dir = configOutputPath;
    mkdirp.sync(dir);
    if (stats.compilation.assets['assets.json']) {
      const assetsMap = JSON.parse(stats.compilation.assets['assets.json'].source());
      _.each(stats.toJson().assetsByChunkName, (assets, bundle) => {
        const bundleJs = assets.constructor === Array ? assets[0] : assets;
        assetsMap[`${bundle}.js`] = bundleJs;
        if (assets.length > 1) {
          assetsMap[`${bundle}.js.map`] = `${bundleJs}.map`;
        }
      });
      if (pkg.app.webpackDll) {
        let vendorHashesJson = JSON.parse(fs.readFileSync(path.join(pkg.app.frontendBuildDir, 'vendor_dll_hashes.json')));
        assetsMap['vendor.js'] = vendorHashesJson.name;
      }
      fs.writeFileSync(path.join(dir, 'assets.json'), JSON.stringify(assetsMap));
    }
  });

  const app = express();

  const httpServer = http.createServer(app);

  app.use((req, res, next) => {
    console.log("req:", req.url);
    next();
  });

  if (platform !== 'web') {
    const debuggerProxy = new WebSocketProxy(httpServer, '/debugger-proxy');

    app.use(rawBodyMiddleware)
      .use(bodyParser.text())
      .use(devToolsMiddleware(debuggerProxy))
      .use(liveReloadMiddleware(compiler))
      .use(statusPageMiddleware)
      .use(symbolicateMiddleware(compiler))
      .use(openInEditorMiddleware())
      .use('/systrace', systraceMiddleware)
      .use(loggerMiddleware);
  }

  app.use(webpackDevMiddleware(compiler, _.merge({}, config.devServer, {
    reporter({state, stats}) {
      if (state) {
        logger("bundle is now VALID.");
      } else {
        logger("bundle is now INVALID.");
      }
      reporter(null, stats);
    }
  })))
  .use(webpackHotMiddleware(compiler, { log: false }));

  if (config.devServer.proxy) {
    Object.keys(config.devServer.proxy).forEach(key => {
      app.use(httpProxyMiddleware(key, config.devServer.proxy[key]));
    });
  }
  if (platform !== 'web') {
    app.use(missingBundleMiddleware);
  }

  logger(`Webpack ${config.name} dev server listening on ${config.devServer.port}`);
  app.listen(config.devServer.port);
}

function useWebpackDll() {
  console.log("Using Webpack DLL vendor bundle");
  const jsonPath = path.join('..', pkg.app.frontendBuildDir, 'vendor_dll.json');
  [clientConfig, androidConfig, iOSConfig].forEach(config =>
    config.plugins.push(new webpack.DllReferencePlugin({
      context: process.cwd(),
      manifest: require(jsonPath) // eslint-disable-line import/no-dynamic-require
    }))
  );
  serverConfig.plugins.push(new webpack.DllReferencePlugin({
    context: process.cwd(),
    manifest: require(jsonPath) // eslint-disable-line import/no-dynamic-require
  }));
}

function isDllValid() {
  try {
    const hashesPath = path.join(pkg.app.frontendBuildDir, 'vendor_dll_hashes.json');
    if (!fs.existsSync(hashesPath)) {
      console.warn("Vendor DLL does not exists");
      return false;
    }
    let meta = JSON.parse(fs.readFileSync(hashesPath));
    if (!fs.existsSync(path.join(pkg.app.frontendBuildDir, meta.name))) {
      console.warn("Vendor DLL does not exists");
      return false;
    }
    if (!_.isEqual(meta.modules, dllConfig.entry.vendor)) {
      console.warn('Modules bundled into vendor DLL changed, need to rebuild it');
      return false;
    }

    let json = JSON.parse(fs.readFileSync(path.join(pkg.app.frontendBuildDir, 'vendor_dll.json')));

    for (let filename of Object.keys(json.content)) {
      if (filename.indexOf(' ') < 0) {
        if (!fs.existsSync(filename)) {
          console.warn("Vendor bundle need to be regenerated, file: " + filename + " is missing.");
          return false;
        }
        const hash = crypto.createHash('md5').update(fs.readFileSync(filename)).digest('hex');
        if (meta.hashes[filename] !== hash) {
          console.warn(`Hash for vendor DLL file ${filename} changed, need to rebuild vendor bundle`);
          return false;
        }
      }
    }

    return true;
  } catch (e) {
    console.warn('Error checking vendor bundle, regenerating it...', e);

    return false;
  }
}

function buildDll() {
  return new Promise((done) => {
    if (!isDllValid()) {
      console.log("Generating vendor DLL bundle...");

      const compiler = webpack(dllConfig);

      compiler.run((err, stats) => {
        let json = JSON.parse(fs.readFileSync(path.join(pkg.app.frontendBuildDir, 'vendor_dll.json')));
        const vendorKey = _.findKey(stats.compilation.assets,
          (v, key) => key.startsWith('vendor') && key.endsWith('_dll.js'));
        const meta = { name: vendorKey, hashes: {}, modules: dllConfig.entry.vendor };
        for (let filename of Object.keys(json.content)) {
          if (filename.indexOf(' ') < 0) {
            meta.hashes[filename] = crypto.createHash('md5').update(fs.readFileSync(filename)).digest('hex');
            fs.writeFileSync(path.join(pkg.app.frontendBuildDir, 'vendor_dll_hashes.json'), JSON.stringify(meta));
          }
        }
        done();
      });
    } else {
      done();
    }
  });
}

async function startExpoServer(config, platform) {
  try {
    if (platform === 'android') {
      which('adb', (err, result) => {
        console.log("Using adb at:", result);
      });
      spawn('adb', ['reverse', 'tcp:8080', 'tcp:8080'], {stdio: [0, 1, 2]});
    }

    Config.validation.reactNativeVersionWarnings = false;
    Config.developerTool = 'crna';
    Config.offline = true;
    Exp.determineEntryPointAsync = () => `index.${platform}`;

    const projectRoot = path.resolve('.');
    await Project.startExpoServerAsync(projectRoot);
    await ProjectSettings.setPackagerInfoAsync(projectRoot, {
      packagerPort: config.devServer.port
    });

    const address = await UrlUtils.constructManifestUrlAsync(projectRoot);
    console.log("Expo address:", address);
    if (platform === 'android') {
      const { success, error } = await Android.openProjectAsync(projectRoot);

      if (!success) {
        console.error(error.message);
      }
    } else if (platform === 'ios') {
      const localAddress = await UrlUtils.constructManifestUrlAsync(projectRoot, {
        hostType: 'localhost',
      });
      const { success, msg } = await Simulator.openUrlInSimulatorSafeAsync(localAddress);

      if (!success) {
        console.error(error.message);
      }
    }
  } catch (e) {
    console.error(e.stack);
  }
}

function startWebpack() {
  startServer();
  startClient(clientConfig, "web");
  startClient(androidConfig, "android");
  // startClient(iOSConfig, "ios");
}

if (!__DEV__ || !pkg.app.webpackDll) {
  startWebpack();
} else {
  buildDll().then(function() {
    useWebpackDll();
    startWebpack();
  });
}
<|endoftext|>


<commit_before>/**
 * Stack
 * notation key
 * a                    = function 'a'
 * [a]                  = an instance of Stack with the function 'a'
 * <action> => <result> = a transformation of the Stack/Stack sequence
 * <action> // <result> = a return value
 * <action> || <result> = the effect of the <action>
 * [a,b,c]              = an array of functions 'a', 'b', 'c'
 * [identity]            = an instance of Stack with 'identity' function
 * [a[b]]               = an instance of Stack with function 'a' and a next [b]
 * [a[b[c]]]            = an instance of Stack with the head [a] and tail [c]
 * {x}                  = some value x
 * [{x},{y}]            = an array of values {x} and {y}
 * a(x)                 = function 'a' invoked with argument {x}
 * a(x, y)              = function 'a' invoked with arguments {x} and {y}
 * ?                    = an object
 * &&                   = logical and
 */
(function(global, undef) {
    function merge(a, b) {
        Array.prototype.push.apply(a, b);
        return a;
    }
    function makeArray(val) {
        return Array.isArray(val) ? val : val ? [val] : [];
    }
    function identity(val) {
        return arguments.length > 1 ? arguments : val;
    }
    function trampoline(fn) {
        return function () {
            var bounce = fn.apply(this, arguments);
            while (typeof bounce === "function") {
                bounce = bounce();
            }
            return bounce;
        };
    }
    function recur(matcher, transformer) {
        return trampoline(function recurring() {
            var self = this;
            var args = arguments;
            return function () {
                return matcher.apply(self, args) && self ||
                    self.next && recurring.apply(self.next, transformer ? transformer.apply(this, args) : args);
            };
        });
    }
    function iterate(action, accumulator, limit) {
        return trampoline(function iterating() {
            var self = this;
            var args = arguments;
            return function () {
                var val = action.apply(self, args);
                if (limit && limit.call(self, val)) {
                    return val;
                }
                return self.next ? iterating.apply(self.next, accumulator ? accumulator.apply(self, merge([val], args)) : args) : val;
            };
        });
    }
    /**
     * Stack
     * Stack() => [identity] // [identity]
     * Stack(a) => [a] // [a]
     * Stack([a,b,c]) => [c[b[a]]] // [c[b[a]]]
     * Stack(a, [b]) => [a[b]] // [a[b]]
     * @param fn {Function|Array}
     * @param [next {Stack}]
     * @returns {Stack}
     * @constructor
     */
    function Stack(fn, next) {
        var arr;
        if (Array.isArray(fn)) {
            arr = fn.slice(0);
            return arr.reduce(function (stack, f) {
                return stack.push(f);
            }, new Stack(arr.shift()));
        }
        if (!(this instanceof Stack)) {
            return new Stack(fn, next);
        }
        this.fn = fn || identity;
        this.next = next || undef;
    }

    /**
     * mung
     * @param prop
     * @param rename
     * @static
     * @returns Stack
     */
    Stack.mung = function (prop, rename) {
        this.prototype[rename] = this.prototype[prop];
        return this;
    };
    /**
     * push
     * [a].push(b) => [b[a]].push(c) => [c[b[a]]] // [c[b[a]]]
     * @param fn {Function}
     * @returns {Stack}
     */
    Stack.prototype.push = function(fn) {
        return new Stack(fn, this);
    };
    /**
     * insert
     * [a].insert(b) => [a[b]] // [b].insert(c) => [a[b[c]]] // [c]
     * @param fn
     * @returns {Stack}
     */
    Stack.prototype.insert = function (fn) {
        return this.next = new Stack(fn, this.next);
    };
    /**
     * index
     * [a[b[c]]].index(1) // [b]
     * @param idx
     * @returns {Stack|undefined}
     */
    Stack.prototype.index = recur(function (i) {
        return i===0;
    }, function (i) {
        i--;
        return arguments;
    });

    /**
     * priorNext
     * [a[b[c[d]]]].priorNext([d]) // [b]
     * @param [stack]
     * @returns {Stack|undefined}
     */
    Stack.prototype.priorNext = recur(function (stack) {
        return this.next && this.next.next === stack;
    });
    /**
     * priorFn
     * [a[b[c]]].priorFn(b) // [a]
     * @param fn
     * @returns {Stack|undefined}
     */
    Stack.prototype.priorFn = recur(function (fn) {
        return this.next && this.next.fn === fn;
    });
    /**
     * isNext
     * [a[b]].isNext([b]) // true
     * @param stack
     * @returns {boolean}
     */
    Stack.prototype.isNext = function (stack) {
        return this.next === stack;
    };
    /**
     * isFn
     * [a].isFn(a) // true
     * @param fn
     * @returns {boolean}
     */
    Stack.prototype.isFn = function (fn) {
        return this.fn === fn;
    };
    /**
     * searchNext
     * [a[b[c]]].searchNext([c]) // [b[c]]
     * @param [stack]
     * @returns {Stack|undefined}
     */
    Stack.prototype.searchNext = recur(Stack.prototype.isNext);
    /**
     * searchFn
     * [a[b[c]]].searchFn(b) // [b]
     * @param fn
     * @returns {Stack|undefined}
     */
    Stack.prototype.searchFn = recur(Stack.prototype.isFn);
    /**
     * distribute
     * [a[b[c]]].distribute({x}) || a(x), b(x), c(x)
     * [a[b[c]]].distribute({x}, ?) || ?.a(x), ?.b(x), ?.c(x)
     * @param arg
     * @param receiver
     * @returns {undefined}
     */
    Stack.prototype.distribute = iterate(function (arg, receiver) {
        this.fn.call(receiver || self, arg);
    });
    /**
     * distributeAll
     * [a[b[c]]].distribute([{x},{y},{z}]) || a(x,y,z), b(x,y,z), c(x,y,z)
     * [a[b[c]]].distribute([{x},{y},{z}], ?) || ?.a(x,y,z), ?.b(x,y,z), ?.c(x,y,z)
     * @param args
     * @param receiver
     * @returns {undefined}
     */
    Stack.prototype.distributeAll = iterate(function (args, receiver) {
        this.fn.apply(receiver || self, args);
    });
    /**
     * call
     * [a[b[c]]].call({x}) // c(b(a(x)))
     * [a[b[c]]].call({x}, ?) // ?.c(?.b(?.a(x)))
     * @param arg
     * @param receiver
     * @returns {*}
     */
    Stack.prototype.call = iterate(function (arg, receiver) {
        return this.fn.call(receiver || this, arg);
    }, function (val, arg, receiver) {
        return [val, receiver];
    });
    /**
     * apply
     * [a[b[c]]].apply([{x},{y},{z}]) // c(b(a(x,y,z)))
     * [a[b[c]]].apply([{x},{y},{z}], ?) // ?.c(?.b(?.a(x,y,z)))
     * @param args
     * @param receiver
     * @returns {*}
     */
    Stack.prototype.apply = iterate(function (args, receiver) {
        return this.fn.apply(receiver || this, args);
    }, function (val, args, receiver) {
        return [makeArray(val), receiver];
    });
    /**
     * clone
     * [a[b[c]]].clone() // [a[b[c]]]
     * [a[b[c]]].clone(d) // [d[b[c]]]
     * [a[b[c]]].clone(null, [d]) // [a[d]]
     * [a[b[c]]].clone(d, [e]) // [d[e]]
     * @param fn
     * @param next
     * @returns {Stack}
     */
    Stack.prototype.clone = function (fn, next) {
        return new Stack(fn || this.fn, next || this.next);
    };
    /**
     * tail
     * [a[b[c]]].tail() // [c]
     * @returns {Stack|undefined}
     */
    Stack.prototype.tail = function () {
        return this.searchNext();
    };
    /**
     * unshift
     * [a[b]].unshift(c) => [a[b[c]]] // [c]
     * @param fn
     * @returns {Stack}
     */
    Stack.prototype.unshift = function (fn) {
        return this.tail().insert(fn);
    };
    /**
     * before
     * [a[b[c]]].before(b, d) => [a[d[b[c]]]] // [d[b[c]]]
     * @param a
     * @param b
     * @returns {Stack}
     */
    Stack.prototype.beforeFn = function (a, b) {
        return (this.searchFn(a || undef) || this).insert(b);
    };
    /**
     * after
     * [a[b[c]]].after(b, d) => [a[b[d[c]]]] // [b[d[c]]]
     * @param a
     * @param b
     * @returns {Stack}
     */
    Stack.prototype.before = function (a, b) {
        return (this.searchFn(a || undef) || this).insert(b);
    };
    /**
     * shift
     * [a[b[c]]].shift() => [a[b]] // [c]
     * @returns {Stack}
     */
    Stack.prototype.shift = function () {
        var p = this.priorNext();
        var removed = p.next;
        p.next = undef;
        return removed;
    };
    /**
     * [a[b[c]]].pop() => [a], [b[c]] // [a]
     * @returns {Stack}
     */
    Stack.prototype.pop = function () {
        this.next = undef;
        return this;
    };
    /**
     * some
     * [a[b[c]]].some() || !c() && !b() && !c() // true|false
     * [a[b[c]]].some({x}) || !c(x) && !b(x) && !c(x) // true|false
     * @param arg
     * @param receiver
     * @returns {boolean}
     */
    Stack.prototype.some = iterate(function (arg, receiver) {
        return this.fn.call(receiver || self, arg);
    }, null, identity);
    /**
     * every
     * [a[b[c]]].every() || c() && b() && c() // true|false
     * [a[b[c]]].every({x}) || c(x) && b(x) && c(x) // true|false
     * @param arg
     * @param receiver
     * @returns {boolean}
     */
    Stack.prototype.every = iterate(function (arg, receiver) {
        return this.fn.call(receiver || this, arg);
    }, null, function (val) {
        return val === false;
    });
    /**
     * [a].push(b) = [a].after(b) = [a].composedWith(b) => [b[a]] // [b[a]]
     * [a].insert(b) = [a].before(b) = [a].then(b) => [a[b]] // [b]
     * [a[b]].isNext([b]) = [a[b]].composes([b]) // true
     * [a].isFn(a) = [a].with(a) = [a].uses(a) // true
     * [a[b]].searchNext([b]) =
     */
    Stack.mung("push", "of")
        .mung("insert", "to")
        .mung("insert", "compose");

//        .mung("isNext", "follows")
//        .mung("isFn", "with")
//        .mung("isFn", "uses")
//        .mung("searchNext", "of")
//        .mung("searchFn", "using")
//        .mung("priorNext", "previousActsOn")
//        .mung("priorFn", "composedWith");

    global.Stack = Stack;
}(this));
<commit_msg>Update stack.js<commit_after>/**
 * Stack
 * notation key
 * a                    = function 'a'
 * [a]                  = an instance of Stack with the function 'a'
 * <action> => <result> = a transformation of the Stack/Stack sequence
 * <action> // <result> = a return value
 * <action> || <result> = the effect of the <action>
 * [a,b,c]              = an array of functions 'a', 'b', 'c'
 * [identity]            = an instance of Stack with 'identity' function
 * [a[b]]               = an instance of Stack with function 'a' and a next [b]
 * [a[b[c]]]            = an instance of Stack with the head [a] and tail [c]
 * {x}                  = some value x
 * [{x},{y}]            = an array of values {x} and {y}
 * a(x)                 = function 'a' invoked with argument {x}
 * a(x, y)              = function 'a' invoked with arguments {x} and {y}
 * ?                    = an object
 * &&                   = logical and
 */
(function(global, undef) {
    function merge(a, b) {
        Array.prototype.push.apply(a, b);
        return a;
    }
    function makeArray(val) {
        return Array.isArray(val) ? val : val ? [val] : [];
    }
    function identity(val) {
        return arguments.length > 1 ? arguments : val;
    }
    function isFalse(val) {
        return val === false;
    }
    function call(arg, receiver) {
        return this.fn.call(receiver || this, arg);
    }
    function trampoline(fn) {
        return function () {
            var bounce = fn.apply(this, arguments);
            while (typeof bounce === "function") {
                bounce = bounce();
            }
            return bounce;
        };
    }
    function recur(matcher, transformer) {
        return trampoline(function recurring() {
            var self = this;
            var args = arguments;
            return function () {
                return matcher.apply(self, args) && self ||
                    self.next && recurring.apply(self.next, transformer ? transformer.apply(this, args) : args);
            };
        });
    }
    function iterate(action, accumulator, limit) {
        return trampoline(function iterating() {
            var self = this;
            var args = arguments;
            return function () {
                var val = action.apply(self, args);
                if (limit && limit.call(self, val)) {
                    return val;
                }
                return self.next ? iterating.apply(self.next, accumulator ? accumulator.apply(self, merge([val], args)) : args) : val;
            };
        });
    }
    /**
     * Stack
     * Stack() => [identity] // [identity]
     * Stack(a) => [a] // [a]
     * Stack([a,b,c]) => [c[b[a]]] // [c[b[a]]]
     * Stack(a, [b]) => [a[b]] // [a[b]]
     * @param fn {Function|Array}
     * @param [next {Stack}]
     * @returns {Stack}
     * @constructor
     */
    function Stack(fn, next) {
        var arr;
        if (Array.isArray(fn)) {
            arr = fn.slice(0);
            return arr.reduce(function (stack, f) {
                return stack.push(f);
            }, new Stack(arr.shift()));
        }
        if (!(this instanceof Stack)) {
            return new Stack(fn, next);
        }
        this.fn = fn || identity;
        this.next = next || undef;
    }

    /**
     * mung
     * @param prop
     * @param rename
     * @static
     * @returns Stack
     */
    Stack.mung = function (prop, rename) {
        this.prototype[rename] = this.prototype[prop];
        return this;
    };
    /**
     * push
     * [a].push(b) => [b[a]].push(c) => [c[b[a]]] // [c[b[a]]]
     * @param fn {Function}
     * @returns {Stack}
     */
    Stack.prototype.push = function(fn) {
        return new Stack(fn, this);
    };
    /**
     * insert
     * [a].insert(b) => [a[b]] // [b].insert(c) => [a[b[c]]] // [c]
     * @param fn
     * @returns {Stack}
     */
    Stack.prototype.insert = function (fn) {
        return this.next = new Stack(fn, this.next);
    };
    /**
     * index
     * [a[b[c]]].index(1) // [b]
     * @param idx
     * @returns {Stack|undefined}
     */
    Stack.prototype.index = recur(function (i) {
        return i===0;
    }, function (i) {
        i--;
        return arguments;
    });

    /**
     * priorNext
     * [a[b[c[d]]]].priorNext([d]) // [b]
     * @param [stack]
     * @returns {Stack|undefined}
     */
    Stack.prototype.priorNext = recur(function (stack) {
        return this.next && this.next.next === stack;
    });
    /**
     * priorFn
     * [a[b[c]]].priorFn(b) // [a]
     * @param fn
     * @returns {Stack|undefined}
     */
    Stack.prototype.priorFn = recur(function (fn) {
        return this.next && this.next.fn === fn;
    });
    /**
     * isNext
     * [a[b]].isNext([b]) // true
     * @param stack
     * @returns {boolean}
     */
    Stack.prototype.isNext = function (stack) {
        return this.next === stack;
    };
    /**
     * isFn
     * [a].isFn(a) // true
     * @param fn
     * @returns {boolean}
     */
    Stack.prototype.isFn = function (fn) {
        return this.fn === fn;
    };
    /**
     * searchNext
     * [a[b[c]]].searchNext([c]) // [b[c]]
     * @param [stack]
     * @returns {Stack|undefined}
     */
    Stack.prototype.searchNext = recur(Stack.prototype.isNext);
    /**
     * searchFn
     * [a[b[c]]].searchFn(b) // [b]
     * @param fn
     * @returns {Stack|undefined}
     */
    Stack.prototype.searchFn = recur(Stack.prototype.isFn);
    /**
     * distribute
     * [a[b[c]]].distribute({x}) || a(x), b(x), c(x)
     * [a[b[c]]].distribute({x}, ?) || ?.a(x), ?.b(x), ?.c(x)
     * @param arg
     * @param receiver
     * @returns {undefined}
     */
    Stack.prototype.distribute = iterate(function (arg, receiver) {
        this.fn.call(receiver || self, arg);
    });
    /**
     * distributeAll
     * [a[b[c]]].distribute([{x},{y},{z}]) || a(x,y,z), b(x,y,z), c(x,y,z)
     * [a[b[c]]].distribute([{x},{y},{z}], ?) || ?.a(x,y,z), ?.b(x,y,z), ?.c(x,y,z)
     * @param args
     * @param receiver
     * @returns {undefined}
     */
    Stack.prototype.distributeAll = iterate(function (args, receiver) {
        this.fn.apply(receiver || self, args);
    });
    /**
     * call
     * [a[b[c]]].call({x}) // c(b(a(x)))
     * [a[b[c]]].call({x}, ?) // ?.c(?.b(?.a(x)))
     * @param arg
     * @param receiver
     * @returns {*}
     */
    Stack.prototype.call = iterate(call, function (val, arg, receiver) {
        return [val, receiver];
    });
    /**
     * apply
     * [a[b[c]]].apply([{x},{y},{z}]) // c(b(a(x,y,z)))
     * [a[b[c]]].apply([{x},{y},{z}], ?) // ?.c(?.b(?.a(x,y,z)))
     * @param args
     * @param receiver
     * @returns {*}
     */
    Stack.prototype.apply = iterate(function (args, receiver) {
        return this.fn.apply(receiver || this, args);
    }, function (val, args, receiver) {
        return [makeArray(val), receiver];
    });
    /**
     * clone
     * [a[b[c]]].clone() // [a[b[c]]]
     * [a[b[c]]].clone(d) // [d[b[c]]]
     * [a[b[c]]].clone(null, [d]) // [a[d]]
     * [a[b[c]]].clone(d, [e]) // [d[e]]
     * @param fn
     * @param next
     * @returns {Stack}
     */
    Stack.prototype.clone = function (fn, next) {
        return new Stack(fn || this.fn, next || this.next);
    };
    /**
     * tail
     * [a[b[c]]].tail() // [c]
     * @returns {Stack|undefined}
     */
    Stack.prototype.tail = function () {
        return this.searchNext();
    };
    /**
     * unshift
     * [a[b]].unshift(c) => [a[b[c]]] // [c]
     * @param fn
     * @returns {Stack}
     */
    Stack.prototype.unshift = function (fn) {
        return this.tail().insert(fn);
    };
    /**
     * before
     * [a[b[c]]].before(b, d) => [a[d[b[c]]]] // [d[b[c]]]
     * @param a
     * @param b
     * @returns {Stack}
     */
    Stack.prototype.beforeFn = function (a, b) {
        return (this.searchFn(a || undef) || this).insert(b);
    };
    /**
     * after
     * [a[b[c]]].after(b, d) => [a[b[d[c]]]] // [b[d[c]]]
     * @param a
     * @param b
     * @returns {Stack}
     */
    Stack.prototype.before = function (a, b) {
        return (this.searchFn(a || undef) || this).insert(b);
    };
    /**
     * shift
     * [a[b[c]]].shift() => [a[b]] // [c]
     * @returns {Stack}
     */
    Stack.prototype.shift = function () {
        var p = this.priorNext();
        var removed = p.next;
        p.next = undef;
        return removed;
    };
    /**
     * [a[b[c]]].pop() => [a], [b[c]] // [a]
     * @returns {Stack}
     */
    Stack.prototype.pop = function () {
        this.next = undef;
        return this;
    };
    /**
     * some
     * [a[b[c]]].some() || !c() && !b() && !c() // true|false
     * [a[b[c]]].some({x}) || !c(x) && !b(x) && !c(x) // true|false
     * @param arg
     * @param receiver
     * @returns {boolean}
     */
    Stack.prototype.some = iterate(call, null, identity);
    /**
     * every
     * [a[b[c]]].every() || c() && b() && c() // true|false
     * [a[b[c]]].every({x}) || c(x) && b(x) && c(x) // true|false
     * @param arg
     * @param receiver
     * @returns {boolean}
     */
    Stack.prototype.every = iterate(call, null, isFalse);
    /**
     * [a].push(b) = [a].after(b) = [a].composedWith(b) => [b[a]] // [b[a]]
     * [a].insert(b) = [a].before(b) = [a].then(b) => [a[b]] // [b]
     * [a[b]].isNext([b]) = [a[b]].composes([b]) // true
     * [a].isFn(a) = [a].with(a) = [a].uses(a) // true
     * [a[b]].searchNext([b]) =
     */
    Stack.mung("push", "of")
        .mung("insert", "to")
        .mung("insert", "compose");

//        .mung("isNext", "follows")
//        .mung("isFn", "with")
//        .mung("isFn", "uses")
//        .mung("searchNext", "of")
//        .mung("searchFn", "using")
//        .mung("priorNext", "previousActsOn")
//        .mung("priorFn", "composedWith");

    global.Stack = Stack;
}(this));
<|endoftext|>


<commit_before>(function (window) {
    var document = window.document;
    <commit_msg>build modifications<commit_after>(function (window) {
    var document = window.document;

    var JS = {};
    window['JS'] = JS;<|endoftext|>


<commit_before>{
	"translatorID":"2c310a37-a4dd-48d2-82c9-bd29c53c1c76",
	"translatorType":4,
	"label":"PROLA","creator":"Eugeniy Mikhailov and Michael Berkowitz",
	"target":"https?://(?:www\\.)?(prola|prl|prb|rmp|pra|prc|prd|pre|prst-ab|prst-per|)\\.aps\\.org[^/]*/(toc|forward|searchabstract|abstract)/",
	"minVersion":"1.0.0b3.r1",
	"maxVersion":null,
	"priority":100,
	"inRepository":true,
	"lastUpdated":"2009-12-26 23:15:00"
}
// Works for most journals at http://prola.aps.org/browse.html

function detectWeb(doc, url) {
	// toc indicates table of contents, forward is a "Citing articles" page
	if (/\/toc\//.test(url) || (/\/forward\//.test(url))){
		return "multiple";
	} else {
		return "journalArticle";
	}
}

function doWeb(doc, url) {
    	var arts = new Array();
    	if (detectWeb(doc, url) == "multiple") {
	    	var items = Zotero.Utilities.getItemArray(doc, doc, "(abstract|abstractsearch)");
	    	items = Zotero.selectItems(items);
	    	for (var i in items) {
		    	arts.push(i);
	    	}
    	} else {
	    	arts = [url];
    	}

    	Zotero.Utilities.processDocuments(arts, function(newDoc) {
    		Zotero.debug(newDoc.title);
		// Use abstract only if we have one
		if (newDoc.evaluate('//div[contains(@class, "aps-abstractbox")]/p', newDoc, null, XPathResult.ANY_TYPE, null).iterateNext()) var abs = Zotero.Utilities.trimInternal(newDoc.evaluate('//div[contains(@class, "aps-abstractbox")]/p', newDoc, null, XPathResult.ANY_TYPE, null).iterateNext().textContent);
    		var urlRIS = newDoc.location.href;
		// so far several more or less  identical url possible
		// one is with "abstract" other with "searchabstract"
		urlRIS = urlRIS.replace(/(searchabstract|abstract)/,"export");
		var post = "type=ris";
		var snapurl = newDoc.location.href;
		var pdfurl = snapurl.replace(/(searchabstract|abstract)/, "pdf");
		Zotero.Utilities.HTTP.doPost(urlRIS, post, function(text) {
			// load translator for RIS
			var translator = Zotero.loadTranslator("import");
			translator.setTranslator("32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7");
			translator.setString(text);
			translator.setHandler("itemDone", function(obj, item) {
				if (item.itemID) {
					item.DOI = item.itemID;
				}
				item.attachments = [
					{url:snapurl, title:"PROLA Snapshot", mimeType:"text/html"},
					{url:pdfurl, title:"PROLA Full Text PDF", mimeType:"application/pdf"}
				];
				if (abs) item.abstractNote = abs;
				item.complete();
			});
			translator.translate();
		 }, null, 'latin1');
	}, function() {Zotero.done();});
	Zotero.wait();
}<commit_msg>updated date<commit_after>{
	"translatorID":"2c310a37-a4dd-48d2-82c9-bd29c53c1c76",
	"translatorType":4,
	"label":"PROLA","creator":"Eugeniy Mikhailov and Michael Berkowitz",
	"target":"https?://(?:www\\.)?(prola|prl|prb|rmp|pra|prc|prd|pre|prst-ab|prst-per|)\\.aps\\.org[^/]*/(toc|forward|searchabstract|abstract)/",
	"minVersion":"1.0.0b3.r1",
	"maxVersion":null,
	"priority":100,
	"inRepository":true,
	"lastUpdated":"2010-01-23 23:15:00"
}
// Works for most journals at http://prola.aps.org/browse.html

function detectWeb(doc, url) {
	// toc indicates table of contents, forward is a "Citing articles" page
	if (/\/toc\//.test(url) || (/\/forward\//.test(url))){
		return "multiple";
	} else {
		return "journalArticle";
	}
}

function doWeb(doc, url) {
    	var arts = new Array();
    	if (detectWeb(doc, url) == "multiple") {
	    	var items = Zotero.Utilities.getItemArray(doc, doc, "(abstract|abstractsearch)");
	    	items = Zotero.selectItems(items);
	    	for (var i in items) {
		    	arts.push(i);
	    	}
    	} else {
	    	arts = [url];
    	}

    	Zotero.Utilities.processDocuments(arts, function(newDoc) {
    		Zotero.debug(newDoc.title);
		// Use abstract only if we have one
		if (newDoc.evaluate('//div[contains(@class, "aps-abstractbox")]/p', newDoc, null, XPathResult.ANY_TYPE, null).iterateNext()) var abs = Zotero.Utilities.trimInternal(newDoc.evaluate('//div[contains(@class, "aps-abstractbox")]/p', newDoc, null, XPathResult.ANY_TYPE, null).iterateNext().textContent);
    		var urlRIS = newDoc.location.href;
		// so far several more or less  identical url possible
		// one is with "abstract" other with "searchabstract"
		urlRIS = urlRIS.replace(/(searchabstract|abstract)/,"export");
		var post = "type=ris";
		var snapurl = newDoc.location.href;
		var pdfurl = snapurl.replace(/(searchabstract|abstract)/, "pdf");
		Zotero.Utilities.HTTP.doPost(urlRIS, post, function(text) {
			// load translator for RIS
			var translator = Zotero.loadTranslator("import");
			translator.setTranslator("32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7");
			translator.setString(text);
			translator.setHandler("itemDone", function(obj, item) {
				if (item.itemID) {
					item.DOI = item.itemID;
				}
				item.attachments = [
					{url:snapurl, title:"PROLA Snapshot", mimeType:"text/html"},
					{url:pdfurl, title:"PROLA Full Text PDF", mimeType:"application/pdf"}
				];
				if (abs) item.abstractNote = abs;
				item.complete();
			});
			translator.translate();
		 }, null, 'latin1');
	}, function() {Zotero.done();});
	Zotero.wait();
}<|endoftext|>


<commit_before>/*requires core.js*/
/*requires load.js*/
/*requires ajax.js*/
/*requires dom.js*/
/*requires selector.js*/
/*requires ua.js*/
/*requires event.js*/
/**
 * nova.ui
 */
nova.ui = {};

// tab 切换，若没有给定 id ，则对 class 为 tab 的所有元素执行函数
nova.ui.tab = function(elm) {
    var elt = elm || ".nova-tab",
	hd = nova.dom.selector(elt + ">.hd>li"),
	bd = nova.dom.selector(elt + ">.bd>li"),
	init,
	hidden,
	toggle,
	i,
	len;

    hidden = function() {
	for (i = 0, len = bd.length; i < len; i++) {
	    nova.dom.removeClass(hd[i], "selected");
	    nova.dom.addClass(bd[i], "hidden");
	}
    };

    toggle = function(e) {
	e = e || window.event;
	var target = e.target || e.srcElement;

	// 确保焦点是

	if (nova.dom.hasClass(target, "anchor")) {
	    target = target.parentNode;
	}

	// 隐藏所有tab内容，并且删除所有选中状态
	hidden();

	// 给当前标题加上选中状态
	nova.dom.addClass(target, "selected");
	// 显示当前tab内容
	nova.dom.removeClass(bd[target.index], "hidden");
    };

    // 添加事件
    for (i = 0, len = hd.length; i < len; i++) {
	hd[i].index = i;
	nova.Event.add(hd[i], "mouseover", toggle);
    }

    // 初始化, 只显示第一个tab
    hidden();
    nova.dom.addClass(hd[0], "selected");
    nova.dom.removeClass(bd[0], "hidden");
};

// 幻灯切换
nova.ui.slide = function() {
};

// 导航
nova.ui.nav = function() {
    var item = nova.dom.selector(".nova-nav .item"),
	i,
	len;

    for (i = 0, len = item.length; i < len; i++) {
	nova.Event.add(item[i], "mouseover", function(e) {
	    nova.dom.addClass(this, "selected");
	});

	nova.Event.add(item[i], "mouseout", function(e) {
	    nova.dom.removeClass(this, "selected");
	});
    }
};

/**
 * 在页面中四处飘浮的广告
 * 遇到边界则改变飘浮方向
 * @param number width element&img's width
 * @param number height element&img's height
 * @param string img's src
 * @param string anchor href
 */
nova.ui.flow = function() {
    var doc = document,
	html = doc.documentElement,
	body = doc.body,
	opt = arguments[0],
	xPos = 300,
	yPos = 200,
	step = 1,
	delay = 30,
	height = 0,
	Hoffset = 0,
	Woffset = 0,
	yon = 0,
	xon = 0,
	pause = true,
	interval;

    //生成广告元素
    var elm = doc.createElement("div");
    nova.dom.addClass(elm, "nova-ui-flow");
    elm.innerHTML = '';
    nova.dom.setCSS([elm], {
	position: "absolute",
	zIndex: "100",
	top: yPos + "px",
	left: "2px",
	width: opt.width + "px",
	height: opt.height + "px",
	visibility: "visible"
    });

    body.appendChild(elm);

    var changePos = function () {
	width = body.clientWidth;
	height = html.clientHeight;

	Hoffset = elm.offsetHeight;
	Woffset = elm.offsetWidth;

	nova.dom.setCSS([elm], {
	    left: xPos + doc.body.scrollLeft + "px",
	    top: yPos + doc.body.scrollTop + "px"
	});

	if (yon) {
	    yPos = yPos + step;
	} else {
	    yPos = yPos - step;
	}

	if (yPos < 0) {
	    yon = 1;
	    yPos = 0;
	}

	if (yPos >= (height - Hoffset)) {
	    yon = 0;
	    yPos = (height - Hoffset);
	}

	if (xon) {
	    xPos = xPos + step;
	} else {
	    xPos = xPos - step;
	}

	if (xPos < 0) {
	    xon = 1;
	    xPos = 0;
	}

	if (xPos >= (width - Woffset)) {
	    xon = 0;
	    xPos = (width - Woffset);
	}
    };

    var pauseResume = function () {
	if (pause) {
	    clearInterval(interval);
	    pause = false;
	} else {
	    interval = setInterval(changePos, delay);
	    pause = true;
	}
    };

    nova.Event.add(elm, "mouseover", pauseResume);
    nova.Event.add(elm, "mouseout", pauseResume);

    interval = setInterval(changePos, delay);
};

/**
 * 对联广告
 * 在页面左右两侧浮动
 * 随页面滚动而滚动
 * @param number top value
 * @param array img's src
 * @param array anchor href
 */
nova.ui.flowBox = function() {
    var win = window,
	doc = document,
	opt = arguments[0];

    //滚动函数
    var scroll = function(elm) {
	var scrollTop,
	    topVal = elm.offsetTop;

	win.onscroll = function() {
	    scrollTop = doc.documentElement.scrollTop || doc.body.scrollTop;

	    nova.dom.setCSS([elm], {
		top: scrollTop + topVal + "px"
	    });
	};
    };

    //添加元素
    var box = doc.createElement("div"),
	boxFirst = doc.createElement("div"),
	boxSecond = doc.createElement("div");

    box.className = "nova-flow-box";
    boxFirst.className = "nfb-first";
    boxSecond.className = "nfb-second";

    boxFirst.innerHTML = '';
    boxSecond.innerHTML = '';

    nova.dom.setCSS([box, boxSecond], {
	position: "absolute",
	top: 0
    });

    nova.dom.setCSS([box], {
	top: opt.top + "px"
    });

    box.appendChild(boxFirst);
    box.appendChild(boxSecond);
    doc.body.appendChild(box);

    //在IE下DOM还未onload的时候图片会很小
    //导致left值计算错误
    //所以这里加入了onload
    var handl = function() {
	nova.dom.setCSS([boxSecond], {
	    left: (doc.body.clientWidth - boxSecond.clientWidth) + "px"
	});

	scroll(box);
    };

    nova.Event.add(win, "load", handl);
};

<commit_msg>to ui.flowBox () to add off event.<commit_after>/*requires core.js*/
/*requires load.js*/
/*requires ajax.js*/
/*requires dom.js*/
/*requires selector.js*/
/*requires ua.js*/
/*requires event.js*/
/**
 * nova.ui
 */
nova.ui = {};

// tab 切换，若没有给定 id ，则对 class 为 tab 的所有元素执行函数
nova.ui.tab = function(elm) {
    var elt = elm || ".nova-tab",
	hd = nova.dom.selector(elt + ">.hd>li"),
	bd = nova.dom.selector(elt + ">.bd>li"),
	init,
	hidden,
	toggle,
	i,
	len;

    hidden = function() {
	for (i = 0, len = bd.length; i < len; i++) {
	    nova.dom.removeClass(hd[i], "selected");
	    nova.dom.addClass(bd[i], "hidden");
	}
    };

    toggle = function(e) {
	e = e || window.event;
	var target = e.target || e.srcElement;

	// 确保焦点是

	if (nova.dom.hasClass(target, "anchor")) {
	    target = target.parentNode;
	}

	// 隐藏所有tab内容，并且删除所有选中状态
	hidden();

	// 给当前标题加上选中状态
	nova.dom.addClass(target, "selected");
	// 显示当前tab内容
	nova.dom.removeClass(bd[target.index], "hidden");
    };

    // 添加事件
    for (i = 0, len = hd.length; i < len; i++) {
	hd[i].index = i;
	nova.Event.add(hd[i], "mouseover", toggle);
    }

    // 初始化, 只显示第一个tab
    hidden();
    nova.dom.addClass(hd[0], "selected");
    nova.dom.removeClass(bd[0], "hidden");
};

// 幻灯切换
nova.ui.slide = function() {
};

// 导航
nova.ui.nav = function() {
    var item = nova.dom.selector(".nova-nav .item"),
	i,
	len;

    for (i = 0, len = item.length; i < len; i++) {
	nova.Event.add(item[i], "mouseover", function(e) {
	    nova.dom.addClass(this, "selected");
	});

	nova.Event.add(item[i], "mouseout", function(e) {
	    nova.dom.removeClass(this, "selected");
	});
    }
};

/**
 * 在页面中四处飘浮的广告
 * 遇到边界则改变飘浮方向
 * @param number width element&img's width
 * @param number height element&img's height
 * @param string img's src
 * @param string anchor href
 */
nova.ui.flow = function() {
    var doc = document,
	html = doc.documentElement,
	body = doc.body,
	opt = arguments[0],
	xPos = 300,
	yPos = 200,
	step = 1,
	delay = 30,
	height = 0,
	Hoffset = 0,
	Woffset = 0,
	yon = 0,
	xon = 0,
	pause = true,
	interval;

    //生成广告元素
    var elm = doc.createElement("div");
    nova.dom.addClass(elm, "nova-ui-flow");
    elm.innerHTML = '';
    nova.dom.setCSS([elm], {
	position: "absolute",
	zIndex: "100",
	top: yPos + "px",
	left: "2px",
	width: opt.width + "px",
	height: opt.height + "px",
	visibility: "visible"
    });

    body.appendChild(elm);

    var changePos = function () {
	width = body.clientWidth;
	height = html.clientHeight;

	Hoffset = elm.offsetHeight;
	Woffset = elm.offsetWidth;

	nova.dom.setCSS([elm], {
	    left: xPos + doc.body.scrollLeft + "px",
	    top: yPos + doc.body.scrollTop + "px"
	});

	if (yon) {
	    yPos = yPos + step;
	} else {
	    yPos = yPos - step;
	}

	if (yPos < 0) {
	    yon = 1;
	    yPos = 0;
	}

	if (yPos >= (height - Hoffset)) {
	    yon = 0;
	    yPos = (height - Hoffset);
	}

	if (xon) {
	    xPos = xPos + step;
	} else {
	    xPos = xPos - step;
	}

	if (xPos < 0) {
	    xon = 1;
	    xPos = 0;
	}

	if (xPos >= (width - Woffset)) {
	    xon = 0;
	    xPos = (width - Woffset);
	}
    };

    var pauseResume = function () {
	if (pause) {
	    clearInterval(interval);
	    pause = false;
	} else {
	    interval = setInterval(changePos, delay);
	    pause = true;
	}
    };

    nova.Event.add(elm, "mouseover", pauseResume);
    nova.Event.add(elm, "mouseout", pauseResume);

    interval = setInterval(changePos, delay);
};

/**
 * 对联广告
 * 在页面左右两侧浮动
 * 随页面滚动而滚动
 * @param number top value
 * @param array img's src
 * @param array anchor href
 */
nova.ui.flowBox = function() {
    var win = window,
	doc = document,
	opt = arguments[0];

    //滚动函数
    var scroll = function(elm) {
	var scrollTop,
	    topVal = elm.offsetTop;

	win.onscroll = function() {
	    scrollTop = doc.documentElement.scrollTop || doc.body.scrollTop;

	    nova.dom.setCSS([elm], {
		top: scrollTop + topVal + "px"
	    });
	};
    };

    //添加元素
    var box = doc.createElement("div"),
	boxFirst = doc.createElement("div"),
	boxSecond = doc.createElement("div"),
	boxFirstBtn = "",
	boxSecondBtn = "";

    //关闭按钮
    if (opt.close) {
	boxFirstBtn = doc.createElement("span");
	boxSecondBtn = doc.createElement("span");

	nova.dom.setCSS([boxFirstBtn, boxSecondBtn], {
	    display: "inline-block",
	    width: "32px",
	    cursor: "pointer"
	});

	boxFirstBtn.innerHTML = '关闭';
	boxSecondBtn.innerHTML = '关闭';
    }

    box.className = "nova-flow-box";
    boxFirst.className = "nfb-first";
    boxSecond.className = "nfb-second";

    boxFirst.innerHTML = '';
    boxSecond.innerHTML = '';

    nova.dom.setCSS([boxFirst, boxSecond], {
	    textAlign: "center"
    });

    boxFirst.appendChild(boxFirstBtn);
    boxSecond.appendChild(boxSecondBtn);

    nova.dom.setCSS([box, boxSecond], {
	position: "absolute",
	top: 0
    });

    nova.dom.setCSS([box], {
	top: opt.top + "px"
    });

    box.appendChild(boxFirst);
    box.appendChild(boxSecond);
    doc.body.appendChild(box);

    //关闭广告事件
    var closeHandl = function(e) {
	e = e || win.event;
	var target = e.target || e.srcElement;

	target.parentNode.innerHTML = "";
    };

    nova.Event.add(boxFirstBtn, "click", closeHandl);
    nova.Event.add(boxSecondBtn, "click", closeHandl);

    //在IE下DOM还未onload的时候图片会很小
    //导致left值计算错误
    //所以这里加入了onload
    var handl = function() {
	nova.dom.setCSS([boxSecond], {
	    left: (doc.body.clientWidth - boxSecond.clientWidth) + "px"
	});

	scroll(box);
    };

    nova.Event.add(win, "load", handl);
};

<|endoftext|>