<commit_before>/*
 * Copyright (c) 2013, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

/*jslint node:true, nomen: true */

/**
The `express-yui.server` extension that provides a set of features
to control a YUI instance on the server side.

@module yui
@submodule server
**/

'use strict';

var libpath = require('path'),
    utils = require('./utils'),
    groups = {};

/**
The `express-yui.server` extension that provides a set of features
to control a YUI instance on the server side.

@class server
@static
@uses *path, utils
@extensionfor yui
*/
module.exports = {

    /**
    Provisions a group and its modules to be attached into Y instance when needed or
    updates the current Y instance by re-attaching the updated group.

    @method attachModules
    @protected
    @param {string} groupName The bundle/group name to be attached.
    @param {array} groupModules The list of modules for the group.
    @chainable
    **/
    attachModules: function (groupName, groupModules) {
        var YUIEnv = this.YUI && this.YUI.Env,
            version = this.version,
            YEnv = this._Y && this._Y.Env,
            module;

        groups[groupName] = {
            modules: groupModules
        };

        if (YEnv && YUIEnv) {
            for (module in groupModules) {
                if (groupModules.hasOwnProperty(module)) {
                    // if the module was attached already, we should clean up the loader internal hashes
                    if (YEnv._attached && YEnv._attached[module]) {
                        // instance entries
                        delete YEnv._attached[module];
                        delete YEnv._used[module];
                        delete YEnv._loader.loaded[module];
                        delete YEnv._loader.inserted[module];
                        delete YEnv._loader.required[module];
                        // global entries
                        delete YUIEnv._loaded[version][module];
                        delete YUIEnv.mods[module];
                        // TODO: can we optimize this? delete is evil
                    }
                }
            }
        }

        return this;
    },

    /**
    Creates a YUI Instance and attaches all registered modules for all registered
    groups into it, and optional attaches some more modules my mimicing the original
    YUI.use method.

    @method use
    @protected
    @return {Object} Y instance
    **/
    use: function () {
        var config = this.config(),
            Y = this._Y,
            groupName,
            obj,
            modules,
            callback;

        modules = Array.prototype.slice.call(arguments, 0);

        // in case a callback is passed
        if (modules.length > 0 && (typeof modules[modules.length - 1] === 'function')) {
            callback = modules.pop();
        }

        for (groupName in groups) {
            if (groups.hasOwnProperty(groupName) && (config.groups && config.groups.hasOwnProperty(groupName))) {
                obj = { groups: {}, useSync: true };
                obj.groups[groupName] = utils.extend(groups[groupName], utils.clone(config.groups[groupName]), {
                    base: libpath.join(this._groupFolderMap[groupName], '/'),
                    combine: false
                });
                modules = modules.concat(Object.keys(groups[groupName].modules || {}));
            }
        }

        if (!Y) {
            config = utils.clone(config);
            config.groups = {}; // disabling the groups that will be added later on
            Y = this._Y = this.YUI(config, {
                base: libpath.normalize(this.path + '/'),
                combine: false,
                useSync: true
            }, obj);
        } else if (obj) {
            Y.applyConfig(obj);
        }

        if (modules.length) {
            // console.log('attaching modules: ' + Object.keys(groups[groupName].modules || {}));
            // TODO: control loading issues
            Y.use(modules);
            groups = {}; // reseting the queue
        }

        if (callback) {
            callback(Y);
        }

        return Y;

    }

};
<commit_msg>adding control for loading issues into server component<commit_after>/*
 * Copyright (c) 2013, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

/*jslint node:true, nomen: true */

/**
The `express-yui.server` extension that provides a set of features
to control a YUI instance on the server side.

@module yui
@submodule server
**/

'use strict';

var libpath = require('path'),
    utils = require('./utils'),
    groups = {};

/**
The `express-yui.server` extension that provides a set of features
to control a YUI instance on the server side.

@class server
@static
@uses *path, utils
@extensionfor yui
*/
module.exports = {

    /**
    Provisions a group and its modules to be attached into Y instance when needed or
    updates the current Y instance by re-attaching the updated group.

    @method attachModules
    @protected
    @param {string} groupName The bundle/group name to be attached.
    @param {array} groupModules The list of modules for the group.
    @chainable
    **/
    attachModules: function (groupName, groupModules) {
        var YUIEnv = this.YUI && this.YUI.Env,
            version = this.version,
            YEnv = this._Y && this._Y.Env,
            module;

        groups[groupName] = {
            modules: groupModules
        };

        if (YEnv && YUIEnv) {
            for (module in groupModules) {
                if (groupModules.hasOwnProperty(module)) {
                    // if the module was attached already, we should clean up the loader internal hashes
                    if (YEnv._attached && YEnv._attached[module]) {
                        // instance entries
                        delete YEnv._attached[module];
                        delete YEnv._used[module];
                        delete YEnv._loader.loaded[module];
                        delete YEnv._loader.inserted[module];
                        delete YEnv._loader.required[module];
                        // global entries
                        delete YUIEnv._loaded[version][module];
                        delete YUIEnv.mods[module];
                        // TODO: can we optimize this? delete is evil
                    }
                }
            }
        }

        return this;
    },

    /**
    Creates a YUI Instance and attaches all registered modules for all registered
    groups into it, and optional attaches some more modules my mimicing the original
    YUI.use method.

    @method use
    @protected
    @return {Object} Y instance
    **/
    use: function () {
        var config = this.config(),
            Y = this._Y,
            groupName,
            obj,
            modules,
            callback;

        modules = Array.prototype.slice.call(arguments, 0);

        // in case a callback is passed
        if (modules.length > 0 && (typeof modules[modules.length - 1] === 'function')) {
            callback = modules.pop();
        }

        for (groupName in groups) {
            if (groups.hasOwnProperty(groupName) && (config.groups && config.groups.hasOwnProperty(groupName))) {
                obj = { groups: {}, useSync: true };
                obj.groups[groupName] = utils.extend(groups[groupName], utils.clone(config.groups[groupName]), {
                    base: libpath.join(this._groupFolderMap[groupName], '/'),
                    combine: false
                });
                modules = modules.concat(Object.keys(groups[groupName].modules || {}));
            }
        }

        if (!Y) {
            config = utils.clone(config);
            config.groups = {}; // disabling the groups that will be added later on
            // TODO: control loading issues
            Y = this._Y = this.YUI(config, {
                base: libpath.normalize(this.path + '/'),
                combine: false,
                useSync: true
            }, obj);
        } else if (obj) {
            Y.applyConfig(obj);
        }

        if (modules.length) {
            try {
                Y.use(modules);
            } catch (e) {
                console.error('error attaching modules: ' + modules);
                console.error(e);
                console.error(e.stack);
            } finally {
                groups = {}; // reseting the queue
            }
        }

        if (callback) {
            callback(Y);
        }

        return Y;

    }

};
<|endoftext|>


<commit_before>import React from 'react';
import classNames from 'classnames';
import { connect } from 'react-redux';
import { clamp, debounce, pick } from 'lodash';
import { fromJS } from 'immutable';

import { drag } from 'd3-drag';
import { event as d3Event, select } from 'd3-selection';

import Logo from '../components/logo';
import ZoomControl from '../components/zoom-control';
import { cacheZoomState } from '../actions/app-actions';
import { zoomFactor } from '../utils/zoom-utils';
import { applyTransform, inverseTransform } from '../utils/transform-utils';
import { activeTopologyZoomCacheKeyPathSelector } from '../selectors/zooming';
import {
  canvasMarginsSelector,
  canvasWidthSelector,
  canvasHeightSelector,
} from '../selectors/canvas';

import { ZOOM_CACHE_DEBOUNCE_INTERVAL } from '../constants/timer';
import { CONTENT_INCLUDED, CONTENT_COVERING } from '../constants/naming';

class ZoomableCanvas extends React.Component {
  constructor(props, context) {
    super(props, context);

    this.state = {
      isPanning: false,
      contentMinX: 0,
      contentMaxX: 0,
      contentMinY: 0,
      contentMaxY: 0,
      translateX: 0,
      translateY: 0,
      minScale: 1,
      maxScale: 1,
      scaleX: 1,
      scaleY: 1,
    };

    this.debouncedCacheZoom = debounce(this.cacheZoom.bind(this), ZOOM_CACHE_DEBOUNCE_INTERVAL);
    this.handleZoomControlAction = this.handleZoomControlAction.bind(this);
    this.canChangeZoom = this.canChangeZoom.bind(this);

    this.handleZoom = this.handleZoom.bind(this);
    this.handlePanStart = this.handlePanStart.bind(this);
    this.handlePanEnd = this.handlePanEnd.bind(this);
    this.handlePan = this.handlePan.bind(this);
  }

  componentDidMount() {
    this.svg = select('.zoomable-canvas svg');
    this.drag = drag()
      .on('start', this.handlePanStart)
      .on('end', this.handlePanEnd)
      .on('drag', this.handlePan);
    this.svg.call(this.drag);

    this.zoomRestored = false;

    this.updateZoomLimits(this.props);
    this.restoreZoomState(this.props);
  }

  componentWillUnmount() {
    this.debouncedCacheZoom.cancel();
  }

  componentWillReceiveProps(nextProps) {
    const layoutChanged = nextProps.layoutId !== this.props.layoutId;

    // If the layout has changed (either active topology or its options) or
    // relayouting has been requested, stop pending zoom caching event and
    // ask for the new zoom settings to be restored again from the cache.
    if (layoutChanged || nextProps.forceRelayout) {
      this.debouncedCacheZoom.cancel();
      this.zoomRestored = false;
    }

    this.updateZoomLimits(nextProps);
    if (!this.zoomRestored) {
      this.restoreZoomState(nextProps);
    }
  }

  handleZoomControlAction(scale) {
    // Get the center of the SVG and zoom around it.
    const { top, bottom, left, right } = this.svg.node().getBoundingClientRect();
    const centerOfCanvas = {
      x: (left + right) / 2,
      y: (top + bottom) / 2,
    };
    // Zoom factor diff is obtained by dividing the new zoom scale with the old one.
    this.zoomAtPositionByFactor(centerOfCanvas, scale / this.state.scaleX);
  }

  render() {
    const className = classNames({ panning: this.state.isPanning });

    return (

        <svg className={className} onClick={this.props.onClick} onWheel={this.handleZoom}>
          <Logo transform="translate(24,24) scale(0.25)" />
          <g className="zoom-content">
            {this.props.children(this.state)}
          </g>
        </svg>
        {this.canChangeZoom() && <ZoomControl
          zoomAction={this.handleZoomControlAction}
          minScale={this.state.minScale}
          maxScale={this.state.maxScale}
          scale={this.state.scaleX}
        />}

    );
  }

  // Decides which part of the zoom state is cachable depending
  // on the horizontal/vertical degrees of freedom.
  cachableState(state = this.state) {
    const cachableFields = []
      .concat(this.props.fixHorizontal ? [] : ['scaleX', 'translateX'])
      .concat(this.props.fixVertical ? [] : ['scaleY', 'translateY']);

    return pick(state, cachableFields);
  }

  cacheZoom() {
    this.props.cacheZoomState(fromJS(this.cachableState()));
  }

  updateZoomLimits(props) {
    this.setState(props.layoutLimits.toJS());
  }

  // Restore the zooming settings
  restoreZoomState(props) {
    if (!props.layoutZoomState.isEmpty()) {
      const zoomState = props.layoutZoomState.toJS();

      // Update the state variables.
      this.setState(zoomState);
      this.zoomRestored = true;
    }
  }

  canChangeZoom() {
    const { disabled, layoutLimits } = this.props;
    const canvasHasContent = !layoutLimits.isEmpty();
    return !disabled && canvasHasContent;
  }

  handlePanStart() {
    this.setState({ isPanning: true });
  }

  handlePanEnd() {
    this.setState({ isPanning: false });
  }

  handlePan() {
    let state = { ...this.state };
    // Apply the translation respecting the boundaries.
    state = this.clampedTranslation({ ...state,
      translateX: this.state.translateX + d3Event.dx,
      translateY: this.state.translateY + d3Event.dy,
    });
    this.updateState(state);
  }

  handleZoom(ev) {
    if (this.canChangeZoom()) {
      // Get the exact mouse cursor position in the SVG and zoom around it.
      const { top, left } = this.svg.node().getBoundingClientRect();
      const mousePosition = {
        x: ev.clientX - left,
        y: ev.clientY - top,
      };
      this.zoomAtPositionByFactor(mousePosition, zoomFactor(ev));
    }
  }

  clampedTranslation(state) {
    const { width, height, canvasMargins, boundContent, layoutLimits } = this.props;
    const { contentMinX, contentMaxX, contentMinY, contentMaxY } = layoutLimits.toJS();

    if (boundContent) {
      // If the content is required to be bounded in any way, the translation will
      // be adjusted so that certain constraints between the viewport and displayed
      // content bounding box are met.
      const viewportMin = { x: canvasMargins.left, y: canvasMargins.top };
      const viewportMax = { x: canvasMargins.left + width, y: canvasMargins.top + height };
      const contentMin = applyTransform(state, { x: contentMinX, y: contentMinY });
      const contentMax = applyTransform(state, { x: contentMaxX, y: contentMaxY });

      switch (boundContent) {
        case CONTENT_COVERING:
          // These lines will adjust the translation by 'minimal effort' in
          // such a way that the content always FULLY covers the viewport,
          // i.e. that the viewport rectangle is always fully contained in
          // the content bounding box rectangle - the assumption made here
          // is that that can always be done.
          state.translateX += Math.max(0, viewportMax.x - contentMax.x);
          state.translateX -= Math.max(0, contentMin.x - viewportMin.x);
          state.translateY += Math.max(0, viewportMax.y - contentMax.y);
          state.translateY -= Math.max(0, contentMin.y - viewportMin.y);
          break;
        case CONTENT_INCLUDED:
          // These lines will adjust the translation by 'minimal effort' in
          // such a way that the content is always at least PARTLY contained
          // within the viewport, i.e. that the intersection between the
          // viewport and the content bounding box always exists.
          state.translateX -= Math.max(0, contentMin.x - viewportMax.x);
          state.translateX += Math.max(0, viewportMin.x - contentMax.x);
          state.translateY -= Math.max(0, contentMin.y - viewportMax.y);
          state.translateY += Math.max(0, viewportMin.y - contentMax.y);
          break;
        default:
          break;
      }
    }

    return state;
  }

  zoomAtPositionByFactor(position, factor) {
    // Update the scales by the given factor, respecting the zoom limits.
    const { minScale, maxScale } = this.state;
    const scaleX = clamp(this.state.scaleX * factor, minScale, maxScale);
    const scaleY = clamp(this.state.scaleY * factor, minScale, maxScale);
    let state = { ...this.state, scaleX, scaleY };

    // Get the position in the coordinates before the transition and use it
    // to adjust the translation part of the new transition (respecting the
    // translation limits). Adapted from:
    // https://github.com/d3/d3-zoom/blob/807f02c7a5fe496fbd08cc3417b62905a8ce95fa/src/zoom.js#L251
    const inversePosition = inverseTransform(this.state, position);
    state = this.clampedTranslation({ ...state,
      translateX: position.x - (inversePosition.x * scaleX),
      translateY: position.y - (inversePosition.y * scaleY),
    });

    this.updateState(state);
  }

  updateState(state) {
    this.setState(this.cachableState(state));
    this.debouncedCacheZoom();
  }
}

function mapStateToProps(state, props) {
  return {
    width: canvasWidthSelector(state),
    height: canvasHeightSelector(state),
    canvasMargins: canvasMarginsSelector(state),
    layoutZoomState: props.zoomStateSelector(state),
    layoutLimits: props.limitsSelector(state),
    layoutId: JSON.stringify(activeTopologyZoomCacheKeyPathSelector(state)),
    forceRelayout: state.get('forceRelayout'),
  };
}

export default connect(
  mapStateToProps,
  { cacheZoomState }
)(ZoomableCanvas);
<commit_msg>Addressed small @foot's comments.<commit_after>import React from 'react';
import classNames from 'classnames';
import { connect } from 'react-redux';
import { clamp, debounce, pick } from 'lodash';
import { fromJS } from 'immutable';

import { drag } from 'd3-drag';
import { event as d3Event, select } from 'd3-selection';

import Logo from '../components/logo';
import ZoomControl from '../components/zoom-control';
import { cacheZoomState } from '../actions/app-actions';
import { zoomFactor } from '../utils/zoom-utils';
import { applyTransform, inverseTransform } from '../utils/transform-utils';
import { activeTopologyZoomCacheKeyPathSelector } from '../selectors/zooming';
import {
  canvasMarginsSelector,
  canvasWidthSelector,
  canvasHeightSelector,
} from '../selectors/canvas';

import { ZOOM_CACHE_DEBOUNCE_INTERVAL } from '../constants/timer';
import { CONTENT_INCLUDED, CONTENT_COVERING } from '../constants/naming';

class ZoomableCanvas extends React.Component {
  constructor(props, context) {
    super(props, context);

    this.state = {
      isPanning: false,
      contentMinX: 0,
      contentMaxX: 0,
      contentMinY: 0,
      contentMaxY: 0,
      translateX: 0,
      translateY: 0,
      minScale: 1,
      maxScale: 1,
      scaleX: 1,
      scaleY: 1,
    };

    this.debouncedCacheZoom = debounce(this.cacheZoom.bind(this), ZOOM_CACHE_DEBOUNCE_INTERVAL);
    this.handleZoomControlAction = this.handleZoomControlAction.bind(this);
    this.canChangeZoom = this.canChangeZoom.bind(this);

    this.handleZoom = this.handleZoom.bind(this);
    this.handlePanStart = this.handlePanStart.bind(this);
    this.handlePanEnd = this.handlePanEnd.bind(this);
    this.handlePan = this.handlePan.bind(this);
  }

  componentDidMount() {
    this.svg = select('.zoomable-canvas svg');
    this.drag = drag()
      .on('start', this.handlePanStart)
      .on('end', this.handlePanEnd)
      .on('drag', this.handlePan);
    this.svg.call(this.drag);

    this.zoomRestored = false;

    this.updateZoomLimits(this.props);
    this.restoreZoomState(this.props);
  }

  componentWillUnmount() {
    this.debouncedCacheZoom.cancel();
  }

  componentWillReceiveProps(nextProps) {
    const layoutChanged = nextProps.layoutId !== this.props.layoutId;

    // If the layout has changed (either active topology or its options) or
    // relayouting has been requested, stop pending zoom caching event and
    // ask for the new zoom settings to be restored again from the cache.
    if (layoutChanged || nextProps.forceRelayout) {
      this.debouncedCacheZoom.cancel();
      this.zoomRestored = false;
    }

    this.updateZoomLimits(nextProps);
    if (!this.zoomRestored) {
      this.restoreZoomState(nextProps);
    }
  }

  handleZoomControlAction(scale) {
    // Get the center of the SVG and zoom around it.
    const { top, bottom, left, right } = this.svg.node().getBoundingClientRect();
    const centerOfCanvas = {
      x: (left + right) / 2,
      y: (top + bottom) / 2,
    };
    // Zoom factor diff is obtained by dividing the new zoom scale with the old one.
    this.zoomAtPositionByFactor(centerOfCanvas, scale / this.state.scaleX);
  }

  render() {
    const className = classNames({ panning: this.state.isPanning });

    return (

        <svg className={className} onClick={this.props.onClick} onWheel={this.handleZoom}>
          <Logo transform="translate(24,24) scale(0.25)" />
          <g className="zoom-content">
            {this.props.children(this.state)}
          </g>
        </svg>
        {this.canChangeZoom() && <ZoomControl
          zoomAction={this.handleZoomControlAction}
          minScale={this.state.minScale}
          maxScale={this.state.maxScale}
          scale={this.state.scaleX}
        />}

    );
  }

  // Decides which part of the zoom state is cachable depending
  // on the horizontal/vertical degrees of freedom.
  cachableState(state = this.state) {
    const cachableFields = []
      .concat(this.props.fixHorizontal ? [] : ['scaleX', 'translateX'])
      .concat(this.props.fixVertical ? [] : ['scaleY', 'translateY']);

    return pick(state, cachableFields);
  }

  cacheZoom() {
    this.props.cacheZoomState(fromJS(this.cachableState()));
  }

  updateZoomLimits(props) {
    this.setState(props.layoutLimits.toJS());
  }

  // Restore the zooming settings
  restoreZoomState(props) {
    if (!props.layoutZoomState.isEmpty()) {
      const zoomState = props.layoutZoomState.toJS();

      // Update the state variables.
      this.setState(zoomState);
      this.zoomRestored = true;
    }
  }

  canChangeZoom() {
    const { disabled, layoutLimits } = this.props;
    const canvasHasContent = !layoutLimits.isEmpty();
    return !disabled && canvasHasContent;
  }

  handlePanStart() {
    this.setState({ isPanning: true });
  }

  handlePanEnd() {
    this.setState({ isPanning: false });
  }

  handlePan() {
    let state = this.state;
    // Apply the translation respecting the boundaries.
    state = this.clampedTranslation({ ...state,
      translateX: this.state.translateX + d3Event.dx,
      translateY: this.state.translateY + d3Event.dy,
    });
    this.updateState(state);
  }

  handleZoom(ev) {
    if (this.canChangeZoom()) {
      // Get the exact mouse cursor position in the SVG and zoom around it.
      const { top, left } = this.svg.node().getBoundingClientRect();
      const mousePosition = {
        x: ev.clientX - left,
        y: ev.clientY - top,
      };
      this.zoomAtPositionByFactor(mousePosition, zoomFactor(ev));
    }
    ev.preventDefault();
  }

  clampedTranslation(state) {
    const { width, height, canvasMargins, boundContent, layoutLimits } = this.props;
    const { contentMinX, contentMaxX, contentMinY, contentMaxY } = layoutLimits.toJS();

    if (boundContent) {
      // If the content is required to be bounded in any way, the translation will
      // be adjusted so that certain constraints between the viewport and displayed
      // content bounding box are met.
      const viewportMin = { x: canvasMargins.left, y: canvasMargins.top };
      const viewportMax = { x: canvasMargins.left + width, y: canvasMargins.top + height };
      const contentMin = applyTransform(state, { x: contentMinX, y: contentMinY });
      const contentMax = applyTransform(state, { x: contentMaxX, y: contentMaxY });

      switch (boundContent) {
        case CONTENT_COVERING:
          // These lines will adjust the translation by 'minimal effort' in
          // such a way that the content always FULLY covers the viewport,
          // i.e. that the viewport rectangle is always fully contained in
          // the content bounding box rectangle - the assumption made here
          // is that that can always be done.
          state.translateX += Math.max(0, viewportMax.x - contentMax.x);
          state.translateX -= Math.max(0, contentMin.x - viewportMin.x);
          state.translateY += Math.max(0, viewportMax.y - contentMax.y);
          state.translateY -= Math.max(0, contentMin.y - viewportMin.y);
          break;
        case CONTENT_INCLUDED:
          // These lines will adjust the translation by 'minimal effort' in
          // such a way that the content is always at least PARTLY contained
          // within the viewport, i.e. that the intersection between the
          // viewport and the content bounding box always exists.
          state.translateX -= Math.max(0, contentMin.x - viewportMax.x);
          state.translateX += Math.max(0, viewportMin.x - contentMax.x);
          state.translateY -= Math.max(0, contentMin.y - viewportMax.y);
          state.translateY += Math.max(0, viewportMin.y - contentMax.y);
          break;
        default:
          break;
      }
    }

    return state;
  }

  zoomAtPositionByFactor(position, factor) {
    // Update the scales by the given factor, respecting the zoom limits.
    const { minScale, maxScale } = this.state;
    const scaleX = clamp(this.state.scaleX * factor, minScale, maxScale);
    const scaleY = clamp(this.state.scaleY * factor, minScale, maxScale);
    let state = { ...this.state, scaleX, scaleY };

    // Get the position in the coordinates before the transition and use it
    // to adjust the translation part of the new transition (respecting the
    // translation limits). Adapted from:
    // https://github.com/d3/d3-zoom/blob/807f02c7a5fe496fbd08cc3417b62905a8ce95fa/src/zoom.js#L251
    const inversePosition = inverseTransform(this.state, position);
    state = this.clampedTranslation({ ...state,
      translateX: position.x - (inversePosition.x * scaleX),
      translateY: position.y - (inversePosition.y * scaleY),
    });

    this.updateState(state);
  }

  updateState(state) {
    this.setState(this.cachableState(state));
    this.debouncedCacheZoom();
  }
}

function mapStateToProps(state, props) {
  return {
    width: canvasWidthSelector(state),
    height: canvasHeightSelector(state),
    canvasMargins: canvasMarginsSelector(state),
    layoutZoomState: props.zoomStateSelector(state),
    layoutLimits: props.limitsSelector(state),
    layoutId: JSON.stringify(activeTopologyZoomCacheKeyPathSelector(state)),
    forceRelayout: state.get('forceRelayout'),
  };
}

export default connect(
  mapStateToProps,
  { cacheZoomState }
)(ZoomableCanvas);
<|endoftext|>


<commit_before>var _ = require('lodash')
var fs = require('fs')
var gzip = require('gzip-size')
var filesize = require('filesize')
var cssstats = require('cssstats')

var module = require('tachyons-white-space/package.json')
var moduleCss = fs.readFileSync('node_modules/tachyons-white-space/tachyons-white-space.min.css', 'utf8')
var moduleObj = cssstats(moduleCss)
var moduleSize = filesize(moduleObj.gzipSize)

var srcCSS = fs.readFileSync('./src/_white-space.css', 'utf8')

var template = fs.readFileSync('./templates/docs/white-space/index.html', 'utf8')
var tpl = _.template(template)
var html = tpl({
  moduleVersion: module.version,
  moduleSize: moduleSize,
  moduleObj: moduleObj,
  srcCSS: srcCSS
})

fs.writeFileSync('./docs/typography/white-space/index.html', html)
<commit_msg>Update with reference to global nav partial<commit_after>var _ = require('lodash')
var fs = require('fs')
var gzip = require('gzip-size')
var filesize = require('filesize')
var cssstats = require('cssstats')

var module = require('tachyons-white-space/package.json')
var moduleCss = fs.readFileSync('node_modules/tachyons-white-space/tachyons-white-space.min.css', 'utf8')
var moduleObj = cssstats(moduleCss)
var moduleSize = filesize(moduleObj.gzipSize)

var srcCSS = fs.readFileSync('./src/_white-space.css', 'utf8')
var navDocs = fs.readFileSync('./templates/nav_docs.html', 'utf8')

var template = fs.readFileSync('./templates/docs/white-space/index.html', 'utf8')
var tpl = _.template(template)
var html = tpl({
  moduleVersion: module.version,
  moduleSize: moduleSize,
  moduleObj: moduleObj,
  srcCSS: srcCSS,
  navDocs: navDocs
})

fs.writeFileSync('./docs/typography/white-space/index.html', html)
<|endoftext|>


<commit_before>/*jslint node: true */
'use strict';

var http = require('http');
var express = require('express');
var mongoose = require('mongoose');
//var MongoStore = require('connect-mongo')(express);
var uuid = require('node-uuid');
var s3 = require('connect-s3');
var passport = require('passport');

var routes = require('./routes');
var postgres = require('./postgres');

// Basic app variables
var server;
var app = express();
var db = null;

// ID generator
var idgen = uuid.v1;

// Use color-coded dev logging for development environments
// On production, we'll rely on the Heroku router's logging for now
if ('development' === process.env.NODE_ENV) {
  app.use(express.logger('dev'));
}

// Have Express wrap the response in a function for JSONP requests
// https://github.com/visionmedia/express/issues/664
app.set('jsonp callback', true);

// Use a compact JSON representation
app.set('json spaces', 0);

// Allows clients to simulate DELETE and PUT
// (some clients don't support those verbs)
// http://stackoverflow.com/questions/8378338/what-does-connect-js-methodoverride-do
app.use(express.methodOverride());

// IE 8 and 9 can't post application/json for cross-origin requests, so we
// accept text/plain treat it as JSON.
// TODO: if we need to accept text/plain in the future, then we need to adjust
// this
function textParser(req, res, next) {
  if (req._body) { return next(); }
  req.body = req.body || {};

  // For GET/HEAD, there's no body to parse.
  if ('GET' === req.method || 'HEAD' === req.method) { return next(); }

  // Check for text/plain content type
  var type = req.headers['content-type'];
  if (type === undefined || 'text/plain' !== type.split(';')[0]) { return next(); }

  // Flag as parsed
  req._body = true;

  console.log('Got text/plain');

  // Parse text/plain as if it was JSON
  var buf = '';
  req.setEncoding('utf8');
  req.on('data', function(chunk){
    buf += chunk;
  });
  req.on('end', function(){
    try {
      if (!buf.length) {
        req.body = {};
      } else {
        req.body = JSON.parse(buf);
      }
      next();
    } catch (err) {
      err.status = 400;
      next(err);
    }
  });
}

// Actually have Express parse text/plain as JSON
app.use(textParser);

// Default to text/plain if no content-type was provided.
app.use(function(req, res, next) {
  if (req.body) { return next(); }
  if ('GET' === req.method || 'HEAD' === req.method) { return next(); }

  if (!req.headers['content-type']) {
    req.body = {};
    textParser(req, res, next);
  } else {
    next();
  }
});

app.use(express.json());
app.use(express.urlencoded());

// Keep extensions, so we can properly guess MIME types later.
// TODO: We should get the MIME type from the upload headers.
app.use(express.multipart({
  keepExtensions: true
}));

// Let's compress everything!
app.use(express.compress());

// Add common headers
app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Mime-Type, X-Requested-With, X-File-Name, Content-Type");
  next();
});

function setupAuth(settings, db) {
  // Authentication-related middleware
  app.use(express.cookieParser());
  app.use(express.session({
    secret: 'superTopSecret',
    store: new MongoStore({
      db: 'localdata_beta',
      mongoose_connection: db,
      maxAge: 300000
    })
  }));

  // Initialize Passport. Also use passport.session() middleware, to support
  // persistent login sessions (recommended).
  app.use(passport.initialize());
  app.use(passport.session());
}

function setupRoutes(settings) {
  routes.setup(app, settings);

  // Serve the mobile collection app from /mobile
  app.use(s3({
    pathPrefix: '/mobile',
    remotePrefix: settings.mobilePrefix
  }));

  // Serve the ringleader's administration/dashboard app from /
  app.use(s3({
    pathPrefix: '/',
    remotePrefix: settings.adminPrefix
  }));
}

// We're done with our preflight stuff.
// Now, we start listening for requests.
function startServer(port, cb) {
  server = http.createServer(app);
  server.listen(port, function (err) {
    console.log('Listening on ' + port);
    if (cb !== undefined) { cb(err); }
  });
}

function run(settings, cb) {
  // Set up the database object
  if (db === null || db.readyState === 0) {
    console.log('Using the following settings:');
    console.log('Port: ' + settings.port);
    console.log('Mongo host: ' + settings.mongo_host);
    console.log('Mongo port: ' + settings.mongo_port);
    console.log('Mongo db: ' + settings.mongo_db);
    console.log('Mongo user: ' + settings.mongo_user);
    console.log('Postgresql host: ' + settings.psqlHost);
    console.log('Postgresql db: ' + settings.psqlName);
    console.log('Postgresql user: ' + settings.psqlUser);

    var opts = {
      db: {
        w: 1,
        safe: true,
        native_parser: settings.mongo_native_parser
      }
    };

    if (settings.mongo_user !== undefined) {
      opts.user = settings.mongo_user;
      opts.pass = settings.mongo_password;
    }

    mongoose.connect(settings.mongo_host, settings.mongo_db, settings.mongo_port, opts);
    postgres.setup(settings);

    setupRoutes(settings);

    db = mongoose.connection;
    db.on('error', function (error) {
      console.log('ERROR: ' + error.message);
    });
    db.once('open', function () {
      setupAuth(settings, db);
      startServer(settings.port, cb);
    });
  }
}

function stop() {
  server.close();
  db.close();
  postgres.close();
  console.log('Stopped server');
}

module.exports = {
  run: run,
  stop: stop
};

// If this was run directly, run!
if (require.main === module) {
  run(require('./settings.js'));
}
<commit_msg>Mostly working<commit_after>/*jslint node: true */
'use strict';

var http = require('http');
var express = require('express');
var mongoose = require('mongoose');
var MongoStore = require('connect-mongo')(express);
var uuid = require('node-uuid');
var s3 = require('connect-s3');
var passport = require('passport');

var routes = require('./routes');
var postgres = require('./postgres');

// Basic app variables
var server;
var app = express();
var db = null;

// ID generator
var idgen = uuid.v1;

// Use color-coded dev logging for development environments
// On production, we'll rely on the Heroku router's logging for now
if ('development' === process.env.NODE_ENV) {
  app.use(express.logger('dev'));
}

// Have Express wrap the response in a function for JSONP requests
// https://github.com/visionmedia/express/issues/664
app.set('jsonp callback', true);

// Use a compact JSON representation
app.set('json spaces', 0);

// Allows clients to simulate DELETE and PUT
// (some clients don't support those verbs)
// http://stackoverflow.com/questions/8378338/what-does-connect-js-methodoverride-do
app.use(express.methodOverride());

// IE 8 and 9 can't post application/json for cross-origin requests, so we
// accept text/plain treat it as JSON.
// TODO: if we need to accept text/plain in the future, then we need to adjust
// this
function textParser(req, res, next) {
  if (req._body) { return next(); }
  req.body = req.body || {};

  // For GET/HEAD, there's no body to parse.
  if ('GET' === req.method || 'HEAD' === req.method) { return next(); }

  // Check for text/plain content type
  var type = req.headers['content-type'];
  if (type === undefined || 'text/plain' !== type.split(';')[0]) { return next(); }

  // Flag as parsed
  req._body = true;

  console.log('Got text/plain');

  // Parse text/plain as if it was JSON
  var buf = '';
  req.setEncoding('utf8');
  req.on('data', function(chunk){
    buf += chunk;
  });
  req.on('end', function(){
    try {
      if (!buf.length) {
        req.body = {};
      } else {
        req.body = JSON.parse(buf);
      }
      next();
    } catch (err) {
      err.status = 400;
      next(err);
    }
  });
}

// Actually have Express parse text/plain as JSON
app.use(textParser);

// Default to text/plain if no content-type was provided.
app.use(function(req, res, next) {
  if (req.body) { return next(); }
  if ('GET' === req.method || 'HEAD' === req.method) { return next(); }

  if (!req.headers['content-type']) {
    req.body = {};
    textParser(req, res, next);
  } else {
    next();
  }
});

app.use(express.json());
app.use(express.urlencoded());

// Keep extensions, so we can properly guess MIME types later.
// TODO: We should get the MIME type from the upload headers.
app.use(express.multipart({
  keepExtensions: true
}));

// Let's compress everything!
app.use(express.compress());

// Add common headers
app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Mime-Type, X-Requested-With, X-File-Name, Content-Type");
  next();
});

function setupAuth(settings, db) {
  // Authentication-related middleware
  app.use(express.cookieParser());
  app.use(express.session({
    secret: settings.secret,
    store: new MongoStore({
      db: 'localdata_beta',
      mongoose_connection: db,
      maxAge: 300000
    })
  }));

  // Initialize Passport. Also use passport.session() middleware, to support
  // persistent login sessions (recommended).
  app.use(passport.initialize());
  app.use(passport.session());
}

function setupRoutes(settings) {
  routes.setup(app, settings);

  // Serve the mobile collection app from /mobile
  app.use(s3({
    pathPrefix: '/mobile',
    remotePrefix: settings.mobilePrefix
  }));

  // Serve the ringleader's administration/dashboard app from /
  app.use(s3({
    pathPrefix: '/',
    remotePrefix: settings.adminPrefix
  }));
}

// We're done with our preflight stuff.
// Now, we start listening for requests.
function startServer(port, cb) {
  server = http.createServer(app);
  server.listen(port, function (err) {
    console.log('Listening on ' + port);
    if (cb !== undefined) { cb(err); }
  });
}

function run(settings, cb) {
  // Set up the database object
  if (db === null || db.readyState === 0) {
    console.log('Using the following settings:');
    console.log('Port: ' + settings.port);
    console.log('Mongo host: ' + settings.mongo_host);
    console.log('Mongo port: ' + settings.mongo_port);
    console.log('Mongo db: ' + settings.mongo_db);
    console.log('Mongo user: ' + settings.mongo_user);
    console.log('Postgresql host: ' + settings.psqlHost);
    console.log('Postgresql db: ' + settings.psqlName);
    console.log('Postgresql user: ' + settings.psqlUser);

    var opts = {
      db: {
        w: 1,
        safe: true,
        native_parser: settings.mongo_native_parser
      }
    };

    if (settings.mongo_user !== undefined) {
      opts.user = settings.mongo_user;
      opts.pass = settings.mongo_password;
    }

    mongoose.connect(settings.mongo_host, settings.mongo_db, settings.mongo_port, opts);
    postgres.setup(settings);

    db = mongoose.connection;
    db.on('error', function (error) {
      console.log('ERROR: ' + error.message);
    });
    db.once('open', function () {
      setupAuth(settings, db);
      setupRoutes(settings); // Needs to happen AFTER setupAuth
      startServer(settings.port, cb);
    });
  }
}

function stop() {
  server.close();
  db.close();
  postgres.close();
  console.log('Stopped server');
}

module.exports = {
  run: run,
  stop: stop
};

// If this was run directly, run!
if (require.main === module) {
  run(require('./settings.js'));
}
<|endoftext|>


<commit_before>/*L.Map.mergeOptions({
	editControl: true
});*/

L.EditToolbar = L.Toolbar.extend({
	statics: {
		TYPE: 'edit'
	},

	options: {
		edit: {
			selectedPathOptions: {
				dashArray: '10, 10',

				fill: true,
				fillColor: '#fe57a1',
				fillOpacity: 0.1,

				// Whether to user the existing layers color
				maintainColor: false
			}
		},
		remove: {},
		poly: null,
		featureGroup: null /* REQUIRED! TODO: perhaps if not set then all layers on the map are selectable? */
	},

	initialize: function (options) {
		// Need to set this manually since null is an acceptable value here
		if (options.edit) {
			if (typeof options.edit.selectedPathOptions === 'undefined') {
				options.edit.selectedPathOptions = this.options.edit.selectedPathOptions;
			}
			options.edit.selectedPathOptions = L.extend({}, this.options.edit.selectedPathOptions, options.edit.selectedPathOptions);
		}

		if (options.remove) {
			options.remove = L.extend({}, this.options.remove, options.remove);
		}

		if (options.poly) {
			options.poly = L.extend({}, this.options.poly, options.poly);
		}

		this._toolbarClass = 'leaflet-draw-edit';
		L.Toolbar.prototype.initialize.call(this, options);

		this._selectedFeatureCount = 0;
	},

	getModeHandlers: function (map) {
		var featureGroup = this.options.featureGroup;
		return [
			{
				enabled: this.options.edit,
				handler: new L.EditToolbar.Edit(map, {
					featureGroup: featureGroup,
					selectedPathOptions: this.options.edit.selectedPathOptions,
					poly : this.options.poly
				}),
				title: L.drawLocal.edit.toolbar.buttons.edit
			},
			{
				enabled: this.options.remove,
				handler: new L.EditToolbar.Delete(map, {
					featureGroup: featureGroup
				}),
				title: L.drawLocal.edit.toolbar.buttons.remove
			}
		];
	},

	getActions: function () {
		return [
			{
				title: L.drawLocal.edit.toolbar.actions.save.title,
				text: L.drawLocal.edit.toolbar.actions.save.text,
				callback: this._save,
				context: this
			},
			{
				title: L.drawLocal.edit.toolbar.actions.cancel.title,
				text: L.drawLocal.edit.toolbar.actions.cancel.text,
				callback: this.disable,
				context: this
			}
		];
	},

	addToolbar: function (map) {
		var container = L.Toolbar.prototype.addToolbar.call(this, map);

		this._checkDisabled();

		this.options.featureGroup.on('layeradd layerremove', this._checkDisabled, this);

		return container;
	},

	removeToolbar: function () {
		this.options.featureGroup.off('layeradd layerremove', this._checkDisabled, this);

		L.Toolbar.prototype.removeToolbar.call(this);
	},

	disable: function () {
		if (!this.enabled()) { return; }

		this._activeMode.handler.revertLayers();

		L.Toolbar.prototype.disable.call(this);
	},

	_save: function () {
		this._activeMode.handler.save();
		this._activeMode.handler.disable();
	},

	_checkDisabled: function () {
		var featureGroup = this.options.featureGroup,
			hasLayers = featureGroup.getLayers().length !== 0,
			button;

		if (this.options.edit) {
			button = this._modes[L.EditToolbar.Edit.TYPE].button;

			if (hasLayers) {
				L.DomUtil.removeClass(button, 'leaflet-disabled');
			} else {
				L.DomUtil.addClass(button, 'leaflet-disabled');
			}

			button.setAttribute(
				'title',
				hasLayers ?
				L.drawLocal.edit.toolbar.buttons.edit
				: L.drawLocal.edit.toolbar.buttons.editDisabled
			);
		}

		if (this.options.remove) {
			button = this._modes[L.EditToolbar.Delete.TYPE].button;

			if (hasLayers) {
				L.DomUtil.removeClass(button, 'leaflet-disabled');
			} else {
				L.DomUtil.addClass(button, 'leaflet-disabled');
			}

			button.setAttribute(
				'title',
				hasLayers ?
				L.drawLocal.edit.toolbar.buttons.remove
				: L.drawLocal.edit.toolbar.buttons.removeDisabled
			);
		}
	}
});
<commit_msg>Check activeMode has not been removed<commit_after>/*L.Map.mergeOptions({
	editControl: true
});*/

L.EditToolbar = L.Toolbar.extend({
	statics: {
		TYPE: 'edit'
	},

	options: {
		edit: {
			selectedPathOptions: {
				dashArray: '10, 10',

				fill: true,
				fillColor: '#fe57a1',
				fillOpacity: 0.1,

				// Whether to user the existing layers color
				maintainColor: false
			}
		},
		remove: {},
		poly: null,
		featureGroup: null /* REQUIRED! TODO: perhaps if not set then all layers on the map are selectable? */
	},

	initialize: function (options) {
		// Need to set this manually since null is an acceptable value here
		if (options.edit) {
			if (typeof options.edit.selectedPathOptions === 'undefined') {
				options.edit.selectedPathOptions = this.options.edit.selectedPathOptions;
			}
			options.edit.selectedPathOptions = L.extend({}, this.options.edit.selectedPathOptions, options.edit.selectedPathOptions);
		}

		if (options.remove) {
			options.remove = L.extend({}, this.options.remove, options.remove);
		}

		if (options.poly) {
			options.poly = L.extend({}, this.options.poly, options.poly);
		}

		this._toolbarClass = 'leaflet-draw-edit';
		L.Toolbar.prototype.initialize.call(this, options);

		this._selectedFeatureCount = 0;
	},

	getModeHandlers: function (map) {
		var featureGroup = this.options.featureGroup;
		return [
			{
				enabled: this.options.edit,
				handler: new L.EditToolbar.Edit(map, {
					featureGroup: featureGroup,
					selectedPathOptions: this.options.edit.selectedPathOptions,
					poly : this.options.poly
				}),
				title: L.drawLocal.edit.toolbar.buttons.edit
			},
			{
				enabled: this.options.remove,
				handler: new L.EditToolbar.Delete(map, {
					featureGroup: featureGroup
				}),
				title: L.drawLocal.edit.toolbar.buttons.remove
			}
		];
	},

	getActions: function () {
		return [
			{
				title: L.drawLocal.edit.toolbar.actions.save.title,
				text: L.drawLocal.edit.toolbar.actions.save.text,
				callback: this._save,
				context: this
			},
			{
				title: L.drawLocal.edit.toolbar.actions.cancel.title,
				text: L.drawLocal.edit.toolbar.actions.cancel.text,
				callback: this.disable,
				context: this
			}
		];
	},

	addToolbar: function (map) {
		var container = L.Toolbar.prototype.addToolbar.call(this, map);

		this._checkDisabled();

		this.options.featureGroup.on('layeradd layerremove', this._checkDisabled, this);

		return container;
	},

	removeToolbar: function () {
		this.options.featureGroup.off('layeradd layerremove', this._checkDisabled, this);

		L.Toolbar.prototype.removeToolbar.call(this);
	},

	disable: function () {
		if (!this.enabled()) { return; }

		this._activeMode.handler.revertLayers();

		L.Toolbar.prototype.disable.call(this);
	},

	_save: function () {
		this._activeMode.handler.save();
		if (this._activeMode) {
			this._activeMode.handler.disable();
		}
	},

	_checkDisabled: function () {
		var featureGroup = this.options.featureGroup,
			hasLayers = featureGroup.getLayers().length !== 0,
			button;

		if (this.options.edit) {
			button = this._modes[L.EditToolbar.Edit.TYPE].button;

			if (hasLayers) {
				L.DomUtil.removeClass(button, 'leaflet-disabled');
			} else {
				L.DomUtil.addClass(button, 'leaflet-disabled');
			}

			button.setAttribute(
				'title',
				hasLayers ?
				L.drawLocal.edit.toolbar.buttons.edit
				: L.drawLocal.edit.toolbar.buttons.editDisabled
			);
		}

		if (this.options.remove) {
			button = this._modes[L.EditToolbar.Delete.TYPE].button;

			if (hasLayers) {
				L.DomUtil.removeClass(button, 'leaflet-disabled');
			} else {
				L.DomUtil.addClass(button, 'leaflet-disabled');
			}

			button.setAttribute(
				'title',
				hasLayers ?
				L.drawLocal.edit.toolbar.buttons.remove
				: L.drawLocal.edit.toolbar.buttons.removeDisabled
			);
		}
	}
});
<|endoftext|>


<commit_before>const social = {
	bindings: {},
	controller: function () {
		let ctrl = this;
		ctrl.social = null;

		ctrl.$onInit = function () {

		};

	},
	template: `
	`
};

angular.module('RowdyMermaid-site.social')
	.component('social', social);

social.$inject = [];
<commit_msg>added parallax jumbotron to social page<commit_after>const social = {
	bindings: {},
	controller: function () {
		let ctrl = this;
		ctrl.social = null;

        ctrl.imageUrl = "/images/closeUpSticker.jpg";
        ctrl.title = "SOCIAL FEED";

		ctrl.$onInit = function () {

		};

	},
	template: `
	<parallax-jumbotron image-url="$ctrl.imageUrl" title="$ctrl.title"></parallax-jumbotron>
	`
};

angular.module('RowdyMermaid-site.social')
	.component('social', social);

social.$inject = [];
<|endoftext|>


<commit_before>/*
* Copyright (c) 2012 Walmart. All rights reserved. Copyrights licensed under the New BSD License.
* See LICENSE file included with this code project for license terms.
*/

// Load modules

var Express = require('express');
var MAC = require('mac');
var Utils = require('./utils');
var Err = require('./error');
var Log = require('./log');
var Process = require('./process');
var Validation = require('./validation');
var Defaults = require('./defaults');

// Declare internals

var internals = {

    // Servers instances by uri or name

    servers: {}
};

// Create and configure server instance

exports.create = function (host, port, options, routes) {

    // Create server object

    var server = {

        // Private members
        // ----------------------------------------------------------------

        settings: Utils.merge(Utils.clone(Defaults.server), options || {}),
        express: null,

        // Initialize server
        // ----------------------------------------------------------------

        initialize: function () {

            // Set basic configuration

            server.settings.host = host.toLowerCase();
            server.settings.port = port;
            server.settings.name = (server.settings.name ? server.settings.name.toLowerCase() : (server.settings.host + ':' + server.settings.port));
            server.settings.uri = (server.settings.tls ? 'https://' : 'http://') + server.settings.host + ':' + server.settings.port + '/';

            // Verify no existing instances using the same uri or name

            if (internals.servers[server.settings.name]) {

                Log.err('Cannot configure multiple server instances using the same name or uri');
                process.exit(1);
            }

            // Create server

            if (server.settings.tls) {

                var tls = {

                    key: Fs.readFileSync(server.settings.tls.key),
                    cert: Fs.readFileSync(server.settings.tls.cert)
                };

                server.express = Express.createServer(tls);
            }
            else {

                server.express = Express.createServer();
            }

            // Configure Express

            server.express.configure(function () {

                server.express.use(server.settings.ext.onPreRoute);
                server.express.use(server.preRoute);                                                        // Pre-Routes Middleware
                server.express.use(server.settings.ext.onPreHandler);
                server.express.use(server.express.router);                                                  // Load Routes
                server.express.use(server.settings.ext.onPostHandler);
                server.express.use(server.postRoute);                                                       // Post-Routes Middleware
                server.express.use(server.settings.ext.onPostRoute);
            });

            // Override generic OPTIONS route

            server.express.options(/.+/, function (req, res, next) {

                res.hapi.result = ' ';
                server.postRoute(req, res, next);
            });

            // Add to instance list

            internals.servers[server.settings.name] = server;

            // Add routes

            if (routes) {

                server.public.addRoutes(routes);
            }
        },

        // Route pre-processor
        // ----------------------------------------------------------------

        preRoute: function (req, res, next) {

            Log.info('Received', req);

            req.hapi = {};
            res.hapi = {};

            res.hapi.wasProcessed = false;

            next();
        },

        // Set default response headers and send response
        // ----------------------------------------------------------------

        postRoute: function (req, res, next) {

            if (res.hapi.isReplied !== true) {

                res.header('Access-Control-Allow-Origin', '*');
                res.header('Access-Control-Allow-Methods', 'GET, HEAD, POST, PUT, DELETE, OPTIONS');
                res.header('Access-Control-Allow-Headers', 'Authorization, Content-Type, If-None-Match');
                res.header('Access-Control-Max-Age', server.settings.cors.maxAge);

                res.header('Cache-Control', 'must-revalidate');

                if (res.hapi.result) {

                    var rev = null;                         // Need to set to something useful
                    if (req.method === 'GET' && rev) {

                        res.header('ETag', rev);

                        var condition = internals.parseCondition(req.headers['if-none-match']);

                        if (condition[rev] ||
                            condition['*']) {

                            res.send('', 304);
                        }
                        else {

                            res.send(res.hapi.result);
                        }
                    }
                    else if (res.hapi.options.created) {

                        res.send(res.hapi.result, { 'Location': server.settings.uri + res.hapi.options.created }, 201);
                    }
                    else {

                        res.send(res.hapi.result);
                    }

                    Log.info('Replied', req);
                }
                else {

                    var error = res.hapi.error || Err.notFound('No such path or method');

                    if (error.type === 'oauth') {

                        res.send({ error: error.error, error_description: error.text }, error.code);
                    }
                    else {

                        res.send({ error: error.text, message: error.message, code: error.code }, error.code);
                    }

                    if (res.hapi.error) {

                        Log.err(res.hapi.error, req);
                    }
                    else {

                        Log.info(error, req);
                    }
                }

                res.hapi.isReplied = true;
            }
        },

        // Public members

        public: {

            // Start server listener
            // ----------------------------------------------------------------

            start: function () {

                server.express.listen(server.settings.port, server.settings.host);
                Log.info(Process.settings.name + ' Server instance started at ' + server.settings.uri);
            },

            // Stop server
            // ----------------------------------------------------------------

            stop: function () {

                server.express.close();
                Log.info(Process.settings.name + ' Server instance stopped at ' + server.settings.uri);
            },

            // Add server route
            // ----------------------------------------------------------------

            addRoute: function (config) {

                var handler = function (req, res, next) {

                    res.hapi.wasProcessed = true;

                    // Authentication

                    internals.authenticate(req, res, config, server, function (err) {

                        if (err === null) {

                            // Query parameters

                            Validation.validateQuery(req, config.query ? Utils.map(config.query) : null, function (err) {

                                if (err === null) {

                                    // Load payload

                                    internals.processBody(req, config.payload || (config.schema ? 'parse' : null), server, function (err) {

                                        if (err === null) {

                                            // Validate payload schema

                                            Validation.validateData(req, config.schema || null, function (err) {

                                                if (err === null) {

                                                    // Route handler

                                                    if (config.handler) {

                                                        // Move req stuff into hapi object

                                                        req.hapi.url = req.url;
                                                        req.hapi.query = req.query;
                                                        req.hapi.params = req.params;

                                                        config.handler(req.hapi, function (result, options) {

                                                            if (result instanceof Error) {

                                                                res.hapi.error = result;
                                                            }
                                                            else {

                                                                res.hapi.result = result;
                                                            }

                                                            res.hapi.options = options || {};
                                                            next();
                                                        });
                                                    }
                                                    else {

                                                        res.hapi.error = Err.internal('Route missing handler');
                                                        next();
                                                    }
                                                }
                                                else {

                                                    res.hapi.error = err;
                                                    next();
                                                }
                                            });
                                        }
                                        else {

                                            res.hapi.error = err;
                                            next();
                                        }
                                    });
                                }
                                else {

                                    res.hapi.error = err;
                                    next();
                                }
                            });
                        }
                        else {

                            res.hapi.error = err;
                            next();
                        }
                    });
                };

                // Add route to Express

                switch (config.method) {

                    case 'GET': server.express.get(config.path, handler); break;
                    case 'POST': server.express.post(config.path, handler); break;
                    case 'PUT': server.express.put(config.path, handler); break;
                    case 'DELETE': server.express.del(config.path, handler); break;
                    default: process.exit(1); break;
                }
            },

            addRoutes: function (routes) {

                for (var i = 0, il = routes.length; i < il; ++i) {

                    server.public.addRoute(routes[i]);
                }
            },

            // Access internal Express server object
            // ----------------------------------------------------------------

            getExpress: function () {

                return server.express;
            }
        }
    };

    // Initialize

    server.initialize();

    // Return public interface

    return server.public;
};

// Return server object

exports.instance = function (name) {

    if (name) {

        name = name.toLowerCase();

        var server = internals.servers[name];
        if (server) {

            return server;
        }
        else {

            return null;
        }
    }
    else {

        var names = Object.keys(internals.servers);
        if (names.length === 1) {

            return internals.servers[names[0]];
        }
        else if (names.length === 0) {

            return null;
        }
        else {

            Log.err('Cannot call Server.instance() without uri in a process with multiple server instances');
            process.exit(1);
        }
    }
};

// Return server object configuration

exports.settings = function (name) {

    var server = exports.instance(name);
    if (server) {

        return server.settings;
    }
    else {

        return null;
    }
};

// Add routes to multiple instances

exports.addRoutes = function (arg0, arg1) { // defaultInstances, routes

    // Handle optional arguments

    var defaultInstances = (arguments.length === 2 ? (arguments[0] instanceof Array ? arguments[0] : [arguments[0]]) : null);
    var routes = (arguments.length === 2 ? arguments[1] : arguments[0]);

    // Process each route

    routes = (routes instanceof Array ? routes : [routes]);
    for (var i = 0, il = routes.length; i < il; ++i) {

        var route = routes[i];
        if (route.instance || defaultInstances) {

            // Select instances

            var instances = (route.instance ? (route.instance instanceof Array ? route.instance : [route.instance]) : defaultInstances);
            for (var r = 0, rl = instances.length; r < rl; ++r) {

                var server = internals.servers[instances[r].toLowerCase()];
                if (server) {

                    server.public.addRoute(route);
                }
                else {

                    Log.err('Cannot find server instance: ' + instances[r]);
                    process.exit(1);
                }
            }
        }
        else {

            // All instances

            for (var s in internals.servers) {

                if (internals.servers.hasOwnProperty(s)) {

                    internals.servers[s].public.addRoute(route);
                }
            }
        }
    }
};

// Token Authentication

internals.authenticate = function (req, res, routeConfig, server, callback) {

    var scope = routeConfig.scope || null;
    var minTos = routeConfig.tos || server.settings.tos.min;
    var userMode = routeConfig.user || 'required';
    var isOptional = (routeConfig.authentication === 'optional');

    if (routeConfig.authentication === 'none') {

        callback(null);
        return;
    }

    var getSession = function (id, callback) {

        if (server.settings.authentication.loadSessionFunc) {

            server.settings.authentication.loadSessionFunc(id, function (session) {

                callback(session);
            });
        }
        else {

            Log.err('Not configured to recieve authenticated requests');
            callback(null);
        }
    };

    MAC.authenticate(req, getSession, { isHTTPS: server.settings.tls }, function (isAuthenticated, session, err) {

        if (isAuthenticated) {

            if (session) {

                req.hapi.session = session;

                if (session.client) {

                    req.hapi.clientId = session.client;

                    // Check scope

                    if (scope === null ||
                        session.scope[scope]) {

                        req.hapi.scope = session.scope;

                        if (userMode === 'required') {

                            if (session.user) {

                                // Check TOS

                                if (minTos === 'none' ||
                                    (session.tos && session.tos >= minTos)) {

                                    req.hapi.userId = session.user;
                                    callback(null);
                                }
                                else {

                                    callback(Err.forbidden('Insufficient TOS accepted'));
                                }
                            }
                            else {

                                callback(Err.forbidden('Client token cannot be used on a user endpoint'));
                            }
                        }
                        else if (userMode === 'none') {

                            if (session.user) {

                                callback(Err.forbidden('User token cannot be used on a client endpoint'));
                            }
                            else {

                                callback(null);
                            }
                        }
                        else if (userMode === 'any') {

                            callback(null);
                        }
                        else {

                            callback(Err.internal('Unknown endpoint user mode'));
                        }
                    }
                    else {

                        callback(Err.forbidden('Insufficient token scope (\'' + scope + '\' expected for client ' + session.client + ')'));
                    }
                }
                else {

                    callback(Err.internal('Missing client identifier in authenticated token'));
                }
            }
            else {

                callback(Err.internal('Missing user object in authenticated token'));
            }
        }
        else {

            // Unauthenticated

            if (isOptional &&
                !req.headers.authorization) {

                callback(null);
            }
            else {

                res.header('WWW-Authenticate', MAC.getWWWAuthenticateHeader(err));
                callback(Err.generic(401, 'Invalid authentication', err));
            }
        }
    });
};

// Read and parse body

internals.processBody = function (req, level, server, callback) {

    // Levels are: 'none', 'raw', 'parse'
    // Default is 'parse' for POST and PUT otherwise 'none'

    level = level || (req.method === 'POST' || req.method === 'PUT' ? 'parse' : 'none');

    if (level === 'none') {

        return callback(null);
    }

    // Check content type (defaults to 'application/json')

    var contentType = req.headers['content-type'];
    if (contentType &&
        contentType.split(';')[0] !== 'application/json') {

        return callback(Err.badRequest('Unsupported content-type'));
    }

    // Check content size

    var contentLength = req.headers['content-length'];
    if (contentLength &&
        parseInt(contentLength, 10) > server.settings.payload.maxBytes) {

        return callback(Err.badRequest('Payload content length greater than maximum allowed: ' + server.settings.payload.maxBytes));
    }

    // Read incoming payload

    var payload = '';
    var isBailed = false;

    req.setEncoding('utf8');
    req.addListener('data', function (chunk) {

        if (payload.length + chunk.length <= server.settings.payload.maxBytes) {

            payload += chunk;
        }
        else {

            isBailed = true;
            return callback(Err.badRequest('Payload size greater than maximum allowed: ' + server.settings.payload.maxBytes));
        }
    });

    req.addListener('end', function () {

        if (isBailed) {

            return;
        }

        req.hapi.rawBody = payload;

        if (level === 'parse') {

            if (payload) {

                req.hapi.payload = {};

                try {

                    req.hapi.payload = JSON.parse(payload);
                }
                catch (err) {

                    return callback(Err.badRequest('Invalid JSON body'));
                }

                callback(null);
            }
        }
    });
};

// Parse If-None-Match request header

internals.parseCondition = function (condition) {

    if (condition) {

        result = {};

        var conditionRegex = (condition.indexOf('"') !== -1 ? /(?:^|,)(?:\s*")([^"]+)(?:"\s*)/g : /(?:^|,)(?:\s*)([^\s]+)(?:\s*)/g);
        condition.replace(conditionRegex, function ($0) {

            if ($0) {

                result[$0] = true;
            }
        });

        return result;
    }
    else {

        return {};
    }
};
<commit_msg>Added var Fs into server.js<commit_after>/*
* Copyright (c) 2012 Walmart. All rights reserved. Copyrights licensed under the New BSD License.
* See LICENSE file included with this code project for license terms.
*/

// Load modules

var Express = require('express');
var MAC = require('mac');
var Utils = require('./utils');
var Err = require('./error');
var Log = require('./log');
var Process = require('./process');
var Validation = require('./validation');
var Defaults = require('./defaults');
var Fs = require('fs');

// Declare internals

var internals = {

    // Servers instances by uri or name

    servers: {}
};

// Create and configure server instance

exports.create = function (host, port, options, routes) {

    // Create server object

    var server = {

        // Private members
        // ----------------------------------------------------------------

        settings: Utils.merge(Utils.clone(Defaults.server), options || {}),
        express: null,

        // Initialize server
        // ----------------------------------------------------------------

        initialize: function () {

            // Set basic configuration

            server.settings.host = host.toLowerCase();
            server.settings.port = port;
            server.settings.name = (server.settings.name ? server.settings.name.toLowerCase() : (server.settings.host + ':' + server.settings.port));
            server.settings.uri = (server.settings.tls ? 'https://' : 'http://') + server.settings.host + ':' + server.settings.port + '/';

            // Verify no existing instances using the same uri or name

            if (internals.servers[server.settings.name]) {

                Log.err('Cannot configure multiple server instances using the same name or uri');
                process.exit(1);
            }

            // Create server

            if (server.settings.tls) {

                var tls = {

                    key: Fs.readFileSync(server.settings.tls.key),
                    cert: Fs.readFileSync(server.settings.tls.cert)
                };

                server.express = Express.createServer(tls);
            }
            else {

                server.express = Express.createServer();
            }

            // Configure Express

            server.express.configure(function () {

                server.express.use(server.settings.ext.onPreRoute);
                server.express.use(server.preRoute);                                                        // Pre-Routes Middleware
                server.express.use(server.settings.ext.onPreHandler);
                server.express.use(server.express.router);                                                  // Load Routes
                server.express.use(server.settings.ext.onPostHandler);
                server.express.use(server.postRoute);                                                       // Post-Routes Middleware
                server.express.use(server.settings.ext.onPostRoute);
            });

            // Override generic OPTIONS route

            server.express.options(/.+/, function (req, res, next) {

                res.hapi.result = ' ';
                server.postRoute(req, res, next);
            });

            // Add to instance list

            internals.servers[server.settings.name] = server;

            // Add routes

            if (routes) {

                server.public.addRoutes(routes);
            }
        },

        // Route pre-processor
        // ----------------------------------------------------------------

        preRoute: function (req, res, next) {

            Log.info('Received', req);

            req.hapi = {};
            res.hapi = {};

            res.hapi.wasProcessed = false;

            next();
        },

        // Set default response headers and send response
        // ----------------------------------------------------------------

        postRoute: function (req, res, next) {

            if (res.hapi.isReplied !== true) {

                res.header('Access-Control-Allow-Origin', '*');
                res.header('Access-Control-Allow-Methods', 'GET, HEAD, POST, PUT, DELETE, OPTIONS');
                res.header('Access-Control-Allow-Headers', 'Authorization, Content-Type, If-None-Match');
                res.header('Access-Control-Max-Age', server.settings.cors.maxAge);

                res.header('Cache-Control', 'must-revalidate');

                if (res.hapi.result) {

                    var rev = null;                         // Need to set to something useful
                    if (req.method === 'GET' && rev) {

                        res.header('ETag', rev);

                        var condition = internals.parseCondition(req.headers['if-none-match']);

                        if (condition[rev] ||
                            condition['*']) {

                            res.send('', 304);
                        }
                        else {

                            res.send(res.hapi.result);
                        }
                    }
                    else if (res.hapi.options.created) {

                        res.send(res.hapi.result, { 'Location': server.settings.uri + res.hapi.options.created }, 201);
                    }
                    else {

                        res.send(res.hapi.result);
                    }

                    Log.info('Replied', req);
                }
                else {

                    var error = res.hapi.error || Err.notFound('No such path or method');

                    if (error.type === 'oauth') {

                        res.send({ error: error.error, error_description: error.text }, error.code);
                    }
                    else {

                        res.send({ error: error.text, message: error.message, code: error.code }, error.code);
                    }

                    if (res.hapi.error) {

                        Log.err(res.hapi.error, req);
                    }
                    else {

                        Log.info(error, req);
                    }
                }

                res.hapi.isReplied = true;
            }
        },

        // Public members

        public: {

            // Start server listener
            // ----------------------------------------------------------------

            start: function () {

                server.express.listen(server.settings.port, server.settings.host);
                Log.info(Process.settings.name + ' Server instance started at ' + server.settings.uri);
            },

            // Stop server
            // ----------------------------------------------------------------

            stop: function () {

                server.express.close();
                Log.info(Process.settings.name + ' Server instance stopped at ' + server.settings.uri);
            },

            // Add server route
            // ----------------------------------------------------------------

            addRoute: function (config) {

                var handler = function (req, res, next) {

                    res.hapi.wasProcessed = true;

                    // Authentication

                    internals.authenticate(req, res, config, server, function (err) {

                        if (err === null) {

                            // Query parameters

                            Validation.validateQuery(req, config.query ? Utils.map(config.query) : null, function (err) {

                                if (err === null) {

                                    // Load payload

                                    internals.processBody(req, config.payload || (config.schema ? 'parse' : null), server, function (err) {

                                        if (err === null) {

                                            // Validate payload schema

                                            Validation.validateData(req, config.schema || null, function (err) {

                                                if (err === null) {

                                                    // Route handler

                                                    if (config.handler) {

                                                        // Move req stuff into hapi object

                                                        req.hapi.url = req.url;
                                                        req.hapi.query = req.query;
                                                        req.hapi.params = req.params;

                                                        config.handler(req.hapi, function (result, options) {

                                                            if (result instanceof Error) {

                                                                res.hapi.error = result;
                                                            }
                                                            else {

                                                                res.hapi.result = result;
                                                            }

                                                            res.hapi.options = options || {};
                                                            next();
                                                        });
                                                    }
                                                    else {

                                                        res.hapi.error = Err.internal('Route missing handler');
                                                        next();
                                                    }
                                                }
                                                else {

                                                    res.hapi.error = err;
                                                    next();
                                                }
                                            });
                                        }
                                        else {

                                            res.hapi.error = err;
                                            next();
                                        }
                                    });
                                }
                                else {

                                    res.hapi.error = err;
                                    next();
                                }
                            });
                        }
                        else {

                            res.hapi.error = err;
                            next();
                        }
                    });
                };

                // Add route to Express

                switch (config.method) {

                    case 'GET': server.express.get(config.path, handler); break;
                    case 'POST': server.express.post(config.path, handler); break;
                    case 'PUT': server.express.put(config.path, handler); break;
                    case 'DELETE': server.express.del(config.path, handler); break;
                    default: process.exit(1); break;
                }
            },

            addRoutes: function (routes) {

                for (var i = 0, il = routes.length; i < il; ++i) {

                    server.public.addRoute(routes[i]);
                }
            },

            // Access internal Express server object
            // ----------------------------------------------------------------

            getExpress: function () {

                return server.express;
            }
        }
    };

    // Initialize

    server.initialize();

    // Return public interface

    return server.public;
};

// Return server object

exports.instance = function (name) {

    if (name) {

        name = name.toLowerCase();

        var server = internals.servers[name];
        if (server) {

            return server;
        }
        else {

            return null;
        }
    }
    else {

        var names = Object.keys(internals.servers);
        if (names.length === 1) {

            return internals.servers[names[0]];
        }
        else if (names.length === 0) {

            return null;
        }
        else {

            Log.err('Cannot call Server.instance() without uri in a process with multiple server instances');
            process.exit(1);
        }
    }
};

// Return server object configuration

exports.settings = function (name) {

    var server = exports.instance(name);
    if (server) {

        return server.settings;
    }
    else {

        return null;
    }
};

// Add routes to multiple instances

exports.addRoutes = function (arg0, arg1) { // defaultInstances, routes

    // Handle optional arguments

    var defaultInstances = (arguments.length === 2 ? (arguments[0] instanceof Array ? arguments[0] : [arguments[0]]) : null);
    var routes = (arguments.length === 2 ? arguments[1] : arguments[0]);

    // Process each route

    routes = (routes instanceof Array ? routes : [routes]);
    for (var i = 0, il = routes.length; i < il; ++i) {

        var route = routes[i];
        if (route.instance || defaultInstances) {

            // Select instances

            var instances = (route.instance ? (route.instance instanceof Array ? route.instance : [route.instance]) : defaultInstances);
            for (var r = 0, rl = instances.length; r < rl; ++r) {

                var server = internals.servers[instances[r].toLowerCase()];
                if (server) {

                    server.public.addRoute(route);
                }
                else {

                    Log.err('Cannot find server instance: ' + instances[r]);
                    process.exit(1);
                }
            }
        }
        else {

            // All instances

            for (var s in internals.servers) {

                if (internals.servers.hasOwnProperty(s)) {

                    internals.servers[s].public.addRoute(route);
                }
            }
        }
    }
};

// Token Authentication

internals.authenticate = function (req, res, routeConfig, server, callback) {

    var scope = routeConfig.scope || null;
    var minTos = routeConfig.tos || server.settings.tos.min;
    var userMode = routeConfig.user || 'required';
    var isOptional = (routeConfig.authentication === 'optional');

    if (routeConfig.authentication === 'none') {

        callback(null);
        return;
    }

    var getSession = function (id, callback) {

        if (server.settings.authentication.loadSessionFunc) {

            server.settings.authentication.loadSessionFunc(id, function (session) {

                callback(session);
            });
        }
        else {

            Log.err('Not configured to recieve authenticated requests');
            callback(null);
        }
    };

    MAC.authenticate(req, getSession, { isHTTPS: server.settings.tls }, function (isAuthenticated, session, err) {

        if (isAuthenticated) {

            if (session) {

                req.hapi.session = session;

                if (session.client) {

                    req.hapi.clientId = session.client;

                    // Check scope

                    if (scope === null ||
                        session.scope[scope]) {

                        req.hapi.scope = session.scope;

                        if (userMode === 'required') {

                            if (session.user) {

                                // Check TOS

                                if (minTos === 'none' ||
                                    (session.tos && session.tos >= minTos)) {

                                    req.hapi.userId = session.user;
                                    callback(null);
                                }
                                else {

                                    callback(Err.forbidden('Insufficient TOS accepted'));
                                }
                            }
                            else {

                                callback(Err.forbidden('Client token cannot be used on a user endpoint'));
                            }
                        }
                        else if (userMode === 'none') {

                            if (session.user) {

                                callback(Err.forbidden('User token cannot be used on a client endpoint'));
                            }
                            else {

                                callback(null);
                            }
                        }
                        else if (userMode === 'any') {

                            callback(null);
                        }
                        else {

                            callback(Err.internal('Unknown endpoint user mode'));
                        }
                    }
                    else {

                        callback(Err.forbidden('Insufficient token scope (\'' + scope + '\' expected for client ' + session.client + ')'));
                    }
                }
                else {

                    callback(Err.internal('Missing client identifier in authenticated token'));
                }
            }
            else {

                callback(Err.internal('Missing user object in authenticated token'));
            }
        }
        else {

            // Unauthenticated

            if (isOptional &&
                !req.headers.authorization) {

                callback(null);
            }
            else {

                res.header('WWW-Authenticate', MAC.getWWWAuthenticateHeader(err));
                callback(Err.generic(401, 'Invalid authentication', err));
            }
        }
    });
};

// Read and parse body

internals.processBody = function (req, level, server, callback) {

    // Levels are: 'none', 'raw', 'parse'
    // Default is 'parse' for POST and PUT otherwise 'none'

    level = level || (req.method === 'POST' || req.method === 'PUT' ? 'parse' : 'none');

    if (level === 'none') {

        return callback(null);
    }

    // Check content type (defaults to 'application/json')

    var contentType = req.headers['content-type'];
    if (contentType &&
        contentType.split(';')[0] !== 'application/json') {

        return callback(Err.badRequest('Unsupported content-type'));
    }

    // Check content size

    var contentLength = req.headers['content-length'];
    if (contentLength &&
        parseInt(contentLength, 10) > server.settings.payload.maxBytes) {

        return callback(Err.badRequest('Payload content length greater than maximum allowed: ' + server.settings.payload.maxBytes));
    }

    // Read incoming payload

    var payload = '';
    var isBailed = false;

    req.setEncoding('utf8');
    req.addListener('data', function (chunk) {

        if (payload.length + chunk.length <= server.settings.payload.maxBytes) {

            payload += chunk;
        }
        else {

            isBailed = true;
            return callback(Err.badRequest('Payload size greater than maximum allowed: ' + server.settings.payload.maxBytes));
        }
    });

    req.addListener('end', function () {

        if (isBailed) {

            return;
        }

        req.hapi.rawBody = payload;

        if (level === 'parse') {

            if (payload) {

                req.hapi.payload = {};

                try {

                    req.hapi.payload = JSON.parse(payload);
                }
                catch (err) {

                    return callback(Err.badRequest('Invalid JSON body'));
                }

                callback(null);
            }
        }
    });
};

// Parse If-None-Match request header

internals.parseCondition = function (condition) {

    if (condition) {

        result = {};

        var conditionRegex = (condition.indexOf('"') !== -1 ? /(?:^|,)(?:\s*")([^"]+)(?:"\s*)/g : /(?:^|,)(?:\s*)([^\s]+)(?:\s*)/g);
        condition.replace(conditionRegex, function ($0) {

            if ($0) {

                result[$0] = true;
            }
        });

        return result;
    }
    else {

        return {};
    }
};
<|endoftext|>


<commit_before>const electron = require('electron');
// Module to control application life.
const app = electron.app;
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;

const path = require('path');
const url = require('url');

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;

function createWindow() {
    // Create the browser window.
    mainWindow = new BrowserWindow({width: 800, height: 600});

    // and load the index.html of the app.
    const startUrl = process.env.ELECTRON_START_URL || url.format({
            pathname: path.join(__dirname, '/../build/index.html'),
            protocol: 'file:',
            slashes: true
        });
    mainWindow.loadURL(startUrl);
    // Open the DevTools.
    mainWindow.webContents.openDevTools();

    // Emitted when the window is closed.
    mainWindow.on('closed', function () {
        // Dereference the window object, usually you would store windows
        // in an array if your app supports multi windows, this is the time
        // when you should delete the corresponding element.
        mainWindow = null
    })
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);

// Quit when all windows are closed.
app.on('window-all-closed', function () {
    // On OS X it is common for applications and their menu bar
    // to stay active until the user quits explicitly with Cmd + Q
    if (process.platform !== 'darwin') {
        app.quit()
    }
});

app.on('activate', function () {
    // On OS X it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (mainWindow === null) {
        createWindow()
    }
});

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
<commit_msg>Make it load loserfruit on startup<commit_after>const electron = require('electron');
// Module to control application life.
const app = electron.app;
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;

const path = require('path');
const url = require('url');

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;

function createWindow() {
  // Create the browser window.
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: { nodeIntegration: false }
  });

  // and load the index.html of the app.
  // const startUrl = process.env.ELECTRON_START_URL ||
  //   url.format({
  //     pathname: path.join(__dirname, '/../build/index.html'),
  //     protocol: 'file:',
  //     slashes: true
  //   });
  const startUrl = 'http://twitch.com/loserfruit';
  mainWindow.loadURL(startUrl);

  // Open the DevTools.
  mainWindow.webContents.openDevTools();

  // Emitted when the window is closed.
  mainWindow.on('closed', function() {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  });
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);

// Quit when all windows are closed.
app.on('window-all-closed', function() {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', function() {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {
    createWindow();
  }
});

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
<|endoftext|>