<commit_before>iD.presets.Preset = function(id, preset, fields) {
    preset = _.clone(preset);

    preset.id = id;
    preset.fields = (preset.fields || []).map(getFields);

    function getFields(f) {
        return fields[f];
    }

    preset.matchGeometry = function(geometry) {
        return preset.geometry.indexOf(geometry) >= 0;
    };

    var matchScore = preset.matchScore || 1;
    preset.matchScore = function(entity) {
        var tags = preset.tags,
            score = 0;

        for (var t in tags) {
            if (entity.tags[t] === tags[t]) {
                score += matchScore;
            } else if (tags[t] === '*' && t in entity.tags) {
                score += matchScore / 2;
            } else {
                return -1;
            }
        }

        return score;
    };

    preset.t = function(scope, options) {
        return t('presets.presets.' + id + '.' + scope, options);
    };

    preset.name = function() {
        return preset.t('name', {'default': id});
    };

    preset.terms = function() {
        return preset.t('terms', {'default': ''}).split(',');
    };

    preset.isFallback = function() {
        return Object.keys(preset.tags).length === 0;
    };

    preset.reference = function(geometry) {
        var key = Object.keys(preset.tags)[0];

        if (geometry === 'relation' && key === 'type') {
            return {rtype: preset.tags[key]};
        }

        var reference = {key: key};

        if (preset.tags[reference.key] !== '*') {
            reference.value = preset.tags[reference.key];
        }

        return reference;
    };

    var removeTags = preset.removeTags || preset.tags;
    preset.removeTags = function(tags, geometry) {
        tags = _.omit(tags, _.keys(removeTags));

        for (var f in preset.fields) {
            var field = preset.fields[f];
            if (field.matchGeometry(geometry) && field['default'] === tags[field.key]) {
                delete tags[field.key];
            }
        }

        return tags;
    };

    var applyTags = preset.applyTags || preset.tags;
    preset.applyTags = function(tags, geometry) {
        tags = _.clone(tags);

        for (var k in applyTags) {
            if (applyTags[k] === '*') {
                tags[k] = 'yes';
            } else {
                tags[k] = applyTags[k];
            }
        }

        for (var f in preset.fields) {
            var field = preset.fields[f];
            if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field['default']) {
                tags[field.key] = field['default'];
            }
        }

        return tags;
    };

    return preset;
};
<commit_msg>Parallelism<commit_after>iD.presets.Preset = function(id, preset, fields) {
    preset = _.clone(preset);

    preset.id = id;
    preset.fields = (preset.fields || []).map(getFields);

    function getFields(f) {
        return fields[f];
    }

    preset.matchGeometry = function(geometry) {
        return preset.geometry.indexOf(geometry) >= 0;
    };

    var matchScore = preset.matchScore || 1;
    preset.matchScore = function(entity) {
        var tags = preset.tags,
            score = 0;

        for (var t in tags) {
            if (entity.tags[t] === tags[t]) {
                score += matchScore;
            } else if (tags[t] === '*' && t in entity.tags) {
                score += matchScore / 2;
            } else {
                return -1;
            }
        }

        return score;
    };

    preset.t = function(scope, options) {
        return t('presets.presets.' + id + '.' + scope, options);
    };

    preset.name = function() {
        return preset.t('name', {'default': id});
    };

    preset.terms = function() {
        return preset.t('terms', {'default': ''}).split(',');
    };

    preset.isFallback = function() {
        return Object.keys(preset.tags).length === 0;
    };

    preset.reference = function(geometry) {
        var key = Object.keys(preset.tags)[0],
            value = preset.tags[key];

        if (geometry === 'relation' && key === 'type') {
            return { rtype: value };
        } else if (value === '*') {
            return { key: key };
        } else {
            return { key: key, value: value };
        }
    };

    var removeTags = preset.removeTags || preset.tags;
    preset.removeTags = function(tags, geometry) {
        tags = _.omit(tags, _.keys(removeTags));

        for (var f in preset.fields) {
            var field = preset.fields[f];
            if (field.matchGeometry(geometry) && field['default'] === tags[field.key]) {
                delete tags[field.key];
            }
        }

        return tags;
    };

    var applyTags = preset.applyTags || preset.tags;
    preset.applyTags = function(tags, geometry) {
        tags = _.clone(tags);

        for (var k in applyTags) {
            if (applyTags[k] === '*') {
                tags[k] = 'yes';
            } else {
                tags[k] = applyTags[k];
            }
        }

        for (var f in preset.fields) {
            var field = preset.fields[f];
            if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field['default']) {
                tags[field.key] = field['default'];
            }
        }

        return tags;
    };

    return preset;
};
<|endoftext|>


<commit_before>import React, {Component} from 'react';
import gql from 'graphql-tag';
import {graphql, withApollo} from 'react-apollo';

import {find, propEq} from 'ramda'
import Cell from './cell'

class Grid extends Component {

  getPlayerValue(id) {
    if (id) {
      return find(propEq('id', id))(this.props.specificGameBoard.players).value
    }
  }

  render() {
    if (this.props.loading) {
      return
Loading...
;
    } else {
      return (

            <Cell cell={this.props.specificGameBoard.cells[0]} playerValue={this.getPlayerValue(this.props.yourPlayerId)} gameBoardId={this.props.specificGameBoard.id}/>
            <Cell cell={this.props.specificGameBoard.cells[1]} playerValue={this.getPlayerValue(this.props.yourPlayerId)} gameBoardId={this.props.specificGameBoard.id}/>
            <Cell cell={this.props.specificGameBoard.cells[2]} playerValue={this.getPlayerValue(this.props.yourPlayerId)} gameBoardId={this.props.specificGameBoard.id}/>

            <Cell cell={this.props.specificGameBoard.cells[3]} playerValue={this.getPlayerValue(this.props.yourPlayerId)} gameBoardId={this.props.specificGameBoard.id}/>
            <Cell cell={this.props.specificGameBoard.cells[4]} playerValue={this.getPlayerValue(this.props.yourPlayerId)} gameBoardId={this.props.specificGameBoard.id}/>
            <Cell cell={this.props.specificGameBoard.cells[5]} playerValue={this.getPlayerValue(this.props.yourPlayerId)} gameBoardId={this.props.specificGameBoard.id}/>

            <Cell cell={this.props.specificGameBoard.cells[6]} playerValue={this.getPlayerValue(this.props.yourPlayerId)} gameBoardId={this.props.specificGameBoard.id}/>
            <Cell cell={this.props.specificGameBoard.cells[7]} playerValue={this.getPlayerValue(this.props.yourPlayerId)} gameBoardId={this.props.specificGameBoard.id}/>
            <Cell cell={this.props.specificGameBoard.cells[8]} playerValue={this.getPlayerValue(this.props.yourPlayerId)} gameBoardId={this.props.specificGameBoard.id}/>

      );
    }
  }

  subscribe(updateCommentsQuery) {
    const SUBSCRIPTION_QUERY = gql`
        subscription OnlyNeededWithPassingVars {
            gameUpdated {
                cells{
                    id
                    value
                }
                players {
                    id
                    status
                    value
                }
            }
        }`;

    this.subscriptionObserver = this.props.client.subscribe({
      query: SUBSCRIPTION_QUERY,
      variables: {"gameBoardId": 0}
    }).subscribe({
      next(data) {
        updateCommentsQuery((previousResult, {gameBoardId}) => {
          console.log('board sub data: ', data)
          console.log('board sub previous: ', previousResult)
          // console.log('previous result', previousResult, gameBoardId)
          previousResult.specificGameBoard.cells=data.gameUpdated.cells;
          return previousResult;//updating(updatedPost, previousResult);
        });
      },
      error(err) {
        console.error('err', err);
      },
    });
  }

  componentDidMount() {
    if (this.props.loading === false) {
      this.subscribe(this.props.updateCommentsQuery);
    }
  }

  componentWillReceiveProps(nextProps) {
    if (this.subscriptionObserver) {
      this.subscriptionObserver.unsubscribe();
    }
    this.subscribe(nextProps.updateCommentsQuery);
  }

  componentWillUnmount() {
    if (this.subscriptionObserver) {
      this.subscriptionObserver.unsubscribe();
    }
  }

}

export default withApollo(graphql(gql`
    query specificGameBoard($gameBoardId: Int!) {
        specificGameBoard(gameBoardId: $gameBoardId) {
            id
            cells{
                id
                value
            }
            players {
                id
                status
                value
            }
        }
    }`, {
  props({data: {loading, specificGameBoard, updateQuery}}) {
    return {loading, specificGameBoard, updateCommentsQuery: updateQuery};
  }
})(Grid));
<commit_msg>styling fixes<commit_after>import React, {Component} from 'react';
import gql from 'graphql-tag';
import {graphql, withApollo} from 'react-apollo';

import {find, propEq} from 'ramda'
import Cell from './cell'

class Grid extends Component {

  getPlayerValue(id) {
    if (id) {
      return find(propEq('id', id))(this.props.specificGameBoard.players).value
    }
  }

  render() {
    if (this.props.loading) {
      return
Loading...
;
    } else {
      return (

            <Cell cell={this.props.specificGameBoard.cells[0]} playerValue={this.getPlayerValue(this.props.yourPlayerId)} gameBoardId={this.props.specificGameBoard.id}/>
            <Cell cell={this.props.specificGameBoard.cells[1]} playerValue={this.getPlayerValue(this.props.yourPlayerId)} gameBoardId={this.props.specificGameBoard.id}/>
            <Cell cell={this.props.specificGameBoard.cells[2]} playerValue={this.getPlayerValue(this.props.yourPlayerId)} gameBoardId={this.props.specificGameBoard.id}/>

            <Cell cell={this.props.specificGameBoard.cells[3]} playerValue={this.getPlayerValue(this.props.yourPlayerId)} gameBoardId={this.props.specificGameBoard.id}/>
            <Cell cell={this.props.specificGameBoard.cells[4]} playerValue={this.getPlayerValue(this.props.yourPlayerId)} gameBoardId={this.props.specificGameBoard.id}/>
            <Cell cell={this.props.specificGameBoard.cells[5]} playerValue={this.getPlayerValue(this.props.yourPlayerId)} gameBoardId={this.props.specificGameBoard.id}/>

            <Cell cell={this.props.specificGameBoard.cells[6]} playerValue={this.getPlayerValue(this.props.yourPlayerId)} gameBoardId={this.props.specificGameBoard.id}/>
            <Cell cell={this.props.specificGameBoard.cells[7]} playerValue={this.getPlayerValue(this.props.yourPlayerId)} gameBoardId={this.props.specificGameBoard.id}/>
            <Cell cell={this.props.specificGameBoard.cells[8]} playerValue={this.getPlayerValue(this.props.yourPlayerId)} gameBoardId={this.props.specificGameBoard.id}/>

      );
    }
  }

  subscribe(updateCommentsQuery) {
    const SUBSCRIPTION_QUERY = gql`
        subscription OnlyNeededWithPassingVars {
            gameUpdated {
                cells{
                    id
                    value
                }
                players {
                    id
                    status
                    value
                }
            }
        }`;

    this.subscriptionObserver = this.props.client.subscribe({
      query: SUBSCRIPTION_QUERY,
      variables: {"gameBoardId": 0}
    }).subscribe({
      next(data) {
        updateCommentsQuery((previousResult, {gameBoardId}) => {
          console.log('board sub data: ', data)
          console.log('board sub previous: ', previousResult)
          // console.log('previous result', previousResult, gameBoardId)
          previousResult.specificGameBoard.cells=data.gameUpdated.cells;
          return previousResult;//updating(updatedPost, previousResult);
        });
      },
      error(err) {
        console.error('err', err);
      },
    });
  }

  componentDidMount() {
    if (this.props.loading === false) {
      this.subscribe(this.props.updateCommentsQuery);
    }
  }

  componentWillReceiveProps(nextProps) {
    if (this.subscriptionObserver) {
      this.subscriptionObserver.unsubscribe();
    }
    this.subscribe(nextProps.updateCommentsQuery);
  }

  componentWillUnmount() {
    if (this.subscriptionObserver) {
      this.subscriptionObserver.unsubscribe();
    }
  }

}

export default withApollo(graphql(gql`
    query specificGameBoard($gameBoardId: Int!) {
        specificGameBoard(gameBoardId: $gameBoardId) {
            id
            cells{
                id
                value
            }
            players {
                id
                status
                value
            }
        }
    }`, {
  props({data: {loading, specificGameBoard, updateQuery}}) {
    return {loading, specificGameBoard, updateCommentsQuery: updateQuery};
  }
})(Grid));
<|endoftext|>


<commit_before>var utils = require('../utils')
var transactionStore = require('../transactionStore')

module.exports = function ($provide, traceBuffer) {
  // Controller Instrumentation
  $provide.decorator('$controller', ['$delegate', '$injector', function ($delegate, $injector) {
    return function () {
      var args = Array.prototype.slice.call(arguments)
      var controllerInfo = utils.getControllerInfoFromArgs(args)

      return utils.instrumentModule($delegate, $injector, {
        type: 'app.$controller',
        prefix: '$controller.' + controllerInfo.name
      }).apply(this, arguments)

      return $delegate.apply(this, args)
    }
  }])
}
<commit_msg>Only instrument controllers where a name is resolvable <commit_after>var utils = require('../utils')
var transactionStore = require('../transactionStore')

module.exports = function ($provide, traceBuffer) {
  // Controller Instrumentation
  $provide.decorator('$controller', ['$delegate', '$injector', function ($delegate, $injector) {
    return function () {
      var args = Array.prototype.slice.call(arguments)
      var controllerInfo = utils.getControllerInfoFromArgs(args)

      if(controllerInfo.name) { // Only instrument controllers with a name
        return utils.instrumentModule($delegate, $injector, {
          type: 'app.$controller',
          prefix: '$controller.' + controllerInfo.name
        }).apply(this, arguments)
      }

      return $delegate.apply(this, args)
    }
  }])
}
<|endoftext|>


<commit_before>var onMoodButtonClicked = function (value, variable) {

    jQuery("#sectionSendingMood").html("");
    var timestamp = Math.floor(Date.now() / 1000);
    var measurements = [
        {
            timestamp: timestamp,
            value: value
        }
    ];
    var payload = [{
        measurements: measurements,
        name: variable.name,
        source: "MoodiModo",
        category: variable.category,
        combinationOperation: variable.combinationOperation,
        unit: variable.abbreviatedUnitName
    }];

    Quantimodo.postMeasurementsV2(payload, function (response) {
        if (response.status == 201) {
            jQuery("#sectionSendingMood").html("Measurement has been posted successfully");
            window.measurementPostingResult = true;
        } else {
            jQuery("#sectionSendingMood").html("Error while posting measurement");
            window.measurementPostingResult = false;
            console.error(response);
        }
    });
};

jQuery(document).ready(function () {
    Quantimodo.getVariableByName(qmwpShortCodeDefinedVariable, function (variable) {
        if (variable && variable.abbreviatedUnitName == "/5") {
            console.debug('Tracker is set to post measurements for variable:');
            console.debug(variable);
            jQuery('#track-variable-content').toggle();
            jQuery('#track-variable-name').html(variable.name);

            jQuery('.track-icon').click(function (event) {

                onMoodButtonClicked(jQuery(event.currentTarget).data('value'), variable);
            });

        } else {
            console.error(variable);
            alert('Variable: ' + qmwpShortCodeDefinedVariable + '\n can not be tracked with this shortcode.')
        }
    });

});
<commit_msg>hound comments fixes<commit_after>var onMoodButtonClicked = function (value, variable) {

    jQuery('#sectionSendingMood').html('');
    var timestamp = Math.floor(Date.now() / 1000);
    var measurements = [
        {
            timestamp: timestamp,
            value: value
        }
    ];
    var payload = [{
        measurements: measurements,
        name: variable.name,
        source: 'MoodiModo',
        category: variable.category,
        combinationOperation: variable.combinationOperation,
        unit: variable.abbreviatedUnitName
    }];

    Quantimodo.postMeasurementsV2(payload, function (response) {
        if (response.status == 201) {
            jQuery('#sectionSendingMood').html('Measurement has been posted successfully');
            window.measurementPostingResult = true;
        } else {
            jQuery('#sectionSendingMood').html('Error while posting measurement');
            window.measurementPostingResult = false;
            console.error(response);
        }
    });
};

jQuery(document).ready(function () {
    Quantimodo.getVariableByName(qmwpShortCodeDefinedVariable, function (variable) {
        if (variable && variable.abbreviatedUnitName == '/5') {
            console.debug('Tracker is set to post measurements for variable:');
            console.debug(variable);
            jQuery('#track-variable-content').toggle();
            jQuery('#track-variable-name').html(variable.name);

            jQuery('.track-icon').click(function (event) {

                onMoodButtonClicked(jQuery(event.currentTarget).data('value'), variable);
            });

        } else {
            console.error(variable);
            alert('Variable: ' + qmwpShortCodeDefinedVariable + '\n can not be tracked with this shortcode.');
        }
    });

});
<|endoftext|>


<commit_before>/*jslint browser: true, plusplus: true */
/*global angular, jQuery */

/** @module Help
@icon question
@summary The help service allows Angular components to open and close the help panel programmatically.
 @description The help service allows other Angular components to open or close the help panel programmatically. When the widget opens, it interrogates the page to identify the current help topic and display the relevant help content. Settings for this service are controlled with the `bbHelpConfig` object.

 ### Dependencies ###

 - **[easyXDM](http://easyxdm.net/wp/) (2.4.19 or higher)** Used to make cross-domain requests to the help server

---

### bbHelp Methods ###

- `init()` Adds a global help button to the top-right corner of the page.  The appropriate `bbHelpConfig` options should be supplied before calling `init()`.
- `open()` Opens help using the specified help key.  If `init()` has not yet been called then the global add button will be added to the page before opening the help topic.
- `close()` Closes the current help topic.

### bbHelpConfig Settings ###

 - `productId` The current product identifier used to build the URL to the product's help content.
 - `url` The URL to the Help Widget that will be included.
 - `customLocales` Optional.  An array of additional locales for which the product has help content other than the default help content locale.  This array should contain strings like 'en-gb' or 'fr'.

 */

(function () {
    'use strict';

    angular.module('sky.help', ['ui.router'])
        .constant('bbHelpConfig', {
            onHelpLoaded: null,
            productId: 'Sky',
            customLocales: [],
            url: null
        })
        .factory('bbHelp', ['$q', '$state', '$window', 'bbHelpConfig', function ($q, $state, $window, bbHelpConfig) {
            var initPromise;

            function helpwidgetLoaded() {
                return !!($window.BBHELP && $window.BBHELP.HelpWidget);
            }

            function init() {
                var configOnHelpLoaded,
                    deferred;

                if (!initPromise) {
                    deferred = $q.defer();
                    initPromise = deferred.promise;

                    if (helpwidgetLoaded()) {
                        deferred.resolve();
                    } else if (bbHelpConfig.url) {
                        jQuery.ajax({
                            cache: true,
                            dataType: 'script',
                            url: bbHelpConfig.url
                        }).done(function () {
                            var config = angular.extend({}, bbHelpConfig);

                            if (!config.getCurrentHelpKey) {
                                config.getCurrentHelpKey = function () {
                                    // $state.current.helpKeyOverride outranks $state.current.pageData.helpKey
                                    if ($state.current.helpKeyOverride) {
                                        return $state.current.helpKeyOverride;
                                    }

                                    if ($state.current.pageData) {
                                        return $state.current.pageData.helpKey;
                                    }
                                    return null;
                                };
                            }

                            configOnHelpLoaded = config.onHelpLoaded;

                            config.onHelpLoaded = function () {
                                if (angular.isFunction(configOnHelpLoaded)) {
                                    configOnHelpLoaded.apply(this, arguments);
                                }

                                deferred.resolve();
                            };

                            $window.BBHELP.HelpWidget.load(config);
                        });
                    } else {
                        initPromise = null;
                        throw new Error('bbHelpConfig.url is not defined.');
                    }
                }

                return initPromise;
            }

            function open() {
                var args = arguments;

                init().then(function () {
                    $window.BBHELP.HelpWidget.open.apply($window.BBHELP.HelpWidget, args);
                });
            }

            function close() {
                if (helpwidgetLoaded()) {
                    $window.BBHELP.HelpWidget.close.apply($window.BBHELP.HelpWidget, arguments);
                }
            }

            return {
                init: init,
                open: open,
                close: close
            };
        }]);

}());
<commit_msg>first update for #8<commit_after>/*jslint browser: true, plusplus: true */
/*global angular, jQuery */

/** @module Help
@icon question
@summary The help service allows Angular components to open and close the help panel programmatically.
 @description The help service allows other Angular components to open or close the help panel programmatically. When the widget opens, it interrogates the page to identify the current help topic and display the relevant help content. Settings for this service are controlled with the `bbHelpConfig` object.

 ### Dependencies ###

 - **[easyXDM](http://easyxdm.net/wp/) (2.4.19 or higher)** Used to make cross-domain requests to the help server

---

### bbHelp Methods ###

- `init()` Adds a global help button to the top-right corner of the page.  The appropriate `bbHelpConfig` options should be supplied before calling `init()`.
- `open()` Opens help using the specified help key.  If `init()` has not yet been called then the global add button will be added to the page before opening the help topic.
- `close()` Closes the current help topic.

### bbHelpConfig Settings ###

 - `caseCentral` Optional. Can customize the Case Central URL if needed, or set to empty string to remove this link.
 - `clientId` Optional. Used to pass the client / site id to the chat session.
 - `communityUrl` Optional. Can be provided in order for a link to Community to appear.
 - `customLocales` Optional.  An array of additional locales for which the product has help content other than the default help content locale.  This array should contain strings like 'en-gb' or 'fr'.
 - `getChatData` Optional. Function that returns the appropriate chat key and website id to use for the product based on the user's locale. e.g.
   ```
   getChatData: function(userLocale) {
            if (locale === 'en-gb') {
                return {
                    key: '3674699029499270000',
                    websiteId: ' 3506212574036402816'
                };
            }
            return {
                key: ' 171147028994005462',
                websiteId: '2766361919244160000'
            };
        }
    ```
 - `getCurrentHelpKey` A function that returns the page's current help URL. This way, if a user navigates around your app, at any point clicking the help panel can call this to determine the appropriate help file to show. e.g. `function() { return 'myHelpFile.html'}`
 - `helpBaseUrl` Optional. Provide the base URL to your help files. If omitted, the productId will be inserted into the URL https://www.blackbaud.com/files/support/helpfiles/{ProductId}/content/ to construct the base URL.  This parameter override is available if help content must exist at some other path instead.
 - `knowledgebaseUrl` Optional. Can customize the knowledgebase URL if needed, or set to empty string to remove this link.
 - `onHelpLoaded` Optional. An callback function after the help panel is loaded.
 - `productId` The current product identifier used to build the URL to the product's help content.
 - `url` The URL to the Help Widget that will be included.
 - `userData` Optional. Object used to pass information about the current user to the chat session. e.g `{ emailAddress: '', firstName: '', lastName: ''}`

 */

(function () {
    'use strict';

    angular.module('sky.help', ['ui.router'])
        .constant('bbHelpConfig', {
            onHelpLoaded: null,
            productId: 'Sky',
            customLocales: [],
            url: null
        })
        .factory('bbHelp', ['$q', '$state', '$window', 'bbHelpConfig', function ($q, $state, $window, bbHelpConfig) {
            var initPromise;

            function helpwidgetLoaded() {
                return !!($window.BBHELP && $window.BBHELP.HelpWidget);
            }

            function init() {
                var configOnHelpLoaded,
                    deferred;

                if (!initPromise) {
                    deferred = $q.defer();
                    initPromise = deferred.promise;

                    if (helpwidgetLoaded()) {
                        deferred.resolve();
                    } else if (bbHelpConfig.url) {
                        jQuery.ajax({
                            cache: true,
                            dataType: 'script',
                            url: bbHelpConfig.url
                        }).done(function () {
                            var config = angular.extend({}, bbHelpConfig);

                            if (!config.getCurrentHelpKey) {
                                config.getCurrentHelpKey = function () {
                                    // $state.current.helpKeyOverride outranks $state.current.pageData.helpKey
                                    if ($state.current.helpKeyOverride) {
                                        return $state.current.helpKeyOverride;
                                    }

                                    if ($state.current.pageData) {
                                        return $state.current.pageData.helpKey;
                                    }
                                    return null;
                                };
                            }

                            configOnHelpLoaded = config.onHelpLoaded;

                            config.onHelpLoaded = function () {
                                if (angular.isFunction(configOnHelpLoaded)) {
                                    configOnHelpLoaded.apply(this, arguments);
                                }

                                deferred.resolve();
                            };

                            $window.BBHELP.HelpWidget.load(config);
                        });
                    } else {
                        initPromise = null;
                        throw new Error('bbHelpConfig.url is not defined.');
                    }
                }

                return initPromise;
            }

            function open() {
                var args = arguments;

                init().then(function () {
                    $window.BBHELP.HelpWidget.open.apply($window.BBHELP.HelpWidget, args);
                });
            }

            function close() {
                if (helpwidgetLoaded()) {
                    $window.BBHELP.HelpWidget.close.apply($window.BBHELP.HelpWidget, arguments);
                }
            }

            return {
                init: init,
                open: open,
                close: close
            };
        }]);

}());
<|endoftext|>


<commit_before>import createCommonHistory from './base';
import createEventCoordinator from './utils/eventCoordinator';
import {
  stripPrefix,
  completeHash
} from './utils/location'
import {
  getStateFromHistory,
  domExists
} from './utils/domCompat';

function getMajor(key) {
  return parseInt(key.split('.')[0], 10);
}

function diffKeys(previous, next) {
  const previousMajor = getMajor(previous);
  const nextMajor = getMajor(next);
  return nextMajor - previousMajor;
}

function decodeHashPath(path) {
  return stripPrefix(path, '#');
}

function encodeHashPath(path) {
  return completeHash(path);
}

function ensureHash() {
  if (window.location.hash === '') {
    window.history.replaceState(null, '', '#/');
  }
}

export default function HashHistory(options = {}) {
  if (!domExists()) {
    return;
  }

  const {
    subscribe,
    emit,
    removeAllSubscribers,
    createLocation,
    createPath,
    confirmNavigation,
    confirmWith,
    removeConfirmation,
    keygen
  } = createCommonHistory(options);

  const beforeDestroy = [removeAllSubscribers];

  // when true, pop will run without attempting to get user confirmation
  let reverting = false;

  ensureHash();

  function locationFromBrowser(providedState) {
    let { hash } = window.location;
    const path = decodeHashPath(hash);
    let { key, state } = providedState || getStateFromHistory();
    if (!key) {
      key = keygen.major();
      // replace with the hash we received, not the decoded path
      window.history.replaceState({ key, state }, '', hash);
    }
    return createLocation(path, key, state);
  }

  const hashHistory = {
    // location
    location: locationFromBrowser(),
    action: 'POP',
    // convenience
    createLocation,
    createPath,
    subscribe,
    confirmWith,
    removeConfirmation,
    destroy: function destroy() {
      beforeDestroy.forEach(fn => { fn(); });
    }
  };

  hashHistory.navigate = function navigate(to, state) {
    const location = createLocation(to, null, state);
    const path = createPath(location);
    const currentPath = createPath(hashHistory.location);

    if (path === currentPath) {
      hashHistory.replace(to, state);
    } else {
      hashHistory.push(to, state);
    }
  }

  hashHistory.push = function push(to, state) {
    const key = keygen.major(hashHistory.location.key);
    const location = createLocation(to, key, state);
    confirmNavigation  (
      location,
      'PUSH',
      () => {
        const path = encodeHashPath(createPath(location));
        window.history.pushState({ key, state }, '', path);

        hashHistory.location = location;
        hashHistory.action = 'PUSH';
        emit(hashHistory.location, 'PUSH');
      }
    );
  }

  hashHistory.replace = function replace(to, state) {
    // pass the current key to just increment the minor portion
    const key = keygen.minor(hashHistory.location.key);
    const location = createLocation(to, key, state);
    confirmNavigation(
      location,
      'REPLACE',
      () => {
        const path = encodeHashPath(createPath(location));
        window.history.replaceState({key, state }, '', path);

        hashHistory.location = location;
        hashHistory.action = 'REPLACE';
        emit(hashHistory.location, 'REPLACE');
      }
    );
  }

  hashHistory.go = function go(num) {
    // calling window.history.go with no value reloads the page, but
    // we will just re-emit instead
    if (!num) {
      hashHistory.action = 'POP';
      emit(hashHistory.location, 'POP');
    } else {
      window.history.go(num);
    }
  }

  function pop(state) {
    // when we are reverting a pop (the user did not confirm navigation), we
    // just need to reset the boolean and return. The browser has already taken
    // care of updating the address bar and we never touched our internal values.
    if (reverting) {
      reverting = false;
      return;
    }
    const location = locationFromBrowser(state);
    const currentKey = hashHistory.location.key;
    const diff = diffKeys(currentKey, location.key);
    confirmNavigation(
      location,
      'POP',
      () => {
        hashHistory.location = location;
        hashHistory.action = 'POP';
        emit(hashHistory.location, 'POP');
      },
      () => {
        reverting = true;

        window.history.go(-1*diff);
      }
    );
  }

  beforeDestroy.push(
    createEventCoordinator({
      hashchange: (event) => { pop(); }
    })
  );

  return hashHistory;
}
<commit_msg>Pass state to pop in hash history<commit_after>import createCommonHistory from './base';
import createEventCoordinator from './utils/eventCoordinator';
import {
  stripPrefix,
  completeHash
} from './utils/location'
import {
  getStateFromHistory,
  domExists
} from './utils/domCompat';

function getMajor(key) {
  return parseInt(key.split('.')[0], 10);
}

function diffKeys(previous, next) {
  const previousMajor = getMajor(previous);
  const nextMajor = getMajor(next);
  return nextMajor - previousMajor;
}

function decodeHashPath(path) {
  return stripPrefix(path, '#');
}

function encodeHashPath(path) {
  return completeHash(path);
}

function ensureHash() {
  if (window.location.hash === '') {
    window.history.replaceState(null, '', '#/');
  }
}

export default function HashHistory(options = {}) {
  if (!domExists()) {
    return;
  }

  const {
    subscribe,
    emit,
    removeAllSubscribers,
    createLocation,
    createPath,
    confirmNavigation,
    confirmWith,
    removeConfirmation,
    keygen
  } = createCommonHistory(options);

  const beforeDestroy = [removeAllSubscribers];

  // when true, pop will run without attempting to get user confirmation
  let reverting = false;

  ensureHash();

  function locationFromBrowser(providedState) {
    let { hash } = window.location;
    const path = decodeHashPath(hash);
    let { key, state } = providedState || getStateFromHistory();
    if (!key) {
      key = keygen.major();
      // replace with the hash we received, not the decoded path
      window.history.replaceState({ key, state }, '', hash);
    }
    return createLocation(path, key, state);
  }

  const hashHistory = {
    // location
    location: locationFromBrowser(),
    action: 'POP',
    // convenience
    createLocation,
    createPath,
    subscribe,
    confirmWith,
    removeConfirmation,
    destroy: function destroy() {
      beforeDestroy.forEach(fn => { fn(); });
    }
  };

  hashHistory.navigate = function navigate(to, state) {
    const location = createLocation(to, null, state);
    const path = createPath(location);
    const currentPath = createPath(hashHistory.location);

    if (path === currentPath) {
      hashHistory.replace(to, state);
    } else {
      hashHistory.push(to, state);
    }
  }

  hashHistory.push = function push(to, state) {
    const key = keygen.major(hashHistory.location.key);
    const location = createLocation(to, key, state);
    confirmNavigation  (
      location,
      'PUSH',
      () => {
        const path = encodeHashPath(createPath(location));
        window.history.pushState({ key, state }, '', path);

        hashHistory.location = location;
        hashHistory.action = 'PUSH';
        emit(hashHistory.location, 'PUSH');
      }
    );
  }

  hashHistory.replace = function replace(to, state) {
    // pass the current key to just increment the minor portion
    const key = keygen.minor(hashHistory.location.key);
    const location = createLocation(to, key, state);
    confirmNavigation(
      location,
      'REPLACE',
      () => {
        const path = encodeHashPath(createPath(location));
        window.history.replaceState({key, state }, '', path);

        hashHistory.location = location;
        hashHistory.action = 'REPLACE';
        emit(hashHistory.location, 'REPLACE');
      }
    );
  }

  hashHistory.go = function go(num) {
    // calling window.history.go with no value reloads the page, but
    // we will just re-emit instead
    if (!num) {
      hashHistory.action = 'POP';
      emit(hashHistory.location, 'POP');
    } else {
      window.history.go(num);
    }
  }

  function pop(state) {
    // when we are reverting a pop (the user did not confirm navigation), we
    // just need to reset the boolean and return. The browser has already taken
    // care of updating the address bar and we never touched our internal values.
    if (reverting) {
      reverting = false;
      return;
    }
    const location = locationFromBrowser(state);
    const currentKey = hashHistory.location.key;
    const diff = diffKeys(currentKey, location.key);
    confirmNavigation(
      location,
      'POP',
      () => {
        hashHistory.location = location;
        hashHistory.action = 'POP';
        emit(hashHistory.location, 'POP');
      },
      () => {
        reverting = true;

        window.history.go(-1*diff);
      }
    );
  }

  beforeDestroy.push(
    createEventCoordinator({
      hashchange: (event) => {
        pop(event.state);
      }
    })
  );

  return hashHistory;
}
<|endoftext|>


<commit_before>/*
 *  Brendan Whitfield (C) 2014
 *
 *  Solves for the OPTIMAL cut pattern (least possible loss).
 *  Solutions are traversed recursively.
 *  Solutions are judged based on their total loss and the distribution of that loss.
 */

var full_solve = {

    run:function(job) {

        var best_layout;

        //the stats for the best layout
        var best_loss; //minimize this
        var best_clumping; //TODO

        full_solve.choose_source(job, [], function(layout) {

            if(!best_layout || (loss_in_layout(layout) < best_loss))
                best_layout = layout;

        });

        return best_layout;
    },

    //WARNING: recursive
    choose_source: function(job, layout, reveal_candidate) {
        if(cuts_left(job) > 0)
        {
            //loop through every length (type) of source material
            job.sources.forEach(function(source, s) {

                if(source.quantity == 0)
                    return; //skip spent sources

                //compute a cut layout for this source
                var filled_board = full_solve.fill_board(job, make_board(job, s));

                source.quantity--; //deduct
                layout.push(filled_board);

                //recurse for the next source board
                full_solve.choose_source(job, layout, reveal_candidate);

                layout.pop();
                source.quantity++;
            });
        }
        else
        {
            //solution has been reached
            reveal_candidate(clone_layout(layout));
        }
    },

    //wrapper function around the recursive board cutter.
    //Stores and returns the best solution.
    fill_board: function(job, board) {

        var best_board; //the layout with the least loss

        full_solve.cut_board(job, board, function(filled_board) {

            //see if this solution is any better than the last
            if((!best_board) || (filled_board.space_left < best_board.space_left))
                best_board = filled_board;
        });

        return best_board;
    },

    //WARNING: recursive
    //tries to make another cut
    cut_board: function(job, board, reveal_candidate) {

        //if there's work left to do on this board
        if((space_left > 0) && (cuts_left(job) > 0))
        {
            //loop through every length (type) of cut still available
            job.cuts.forEach(function(cut, c) {

                if(cut.quantity == 0)
                    return; //skip spent cut sizes

                //if this cut size is too long for the remaining space
                if(board.space_left < cut.length)
                {
                    //there's a chance that all of the cuts we've been trying were to big.
                    //so, whenever we run into a piece that's too big, report it anyway.
                    //also handles cases where NO cuts can be made, because the board was
                    //too small to begin with.
                    reveal_candidate(clone_board(board));
                    return; //skip
                }

                //if we've made it this far, then there is enough space for our cut size

                //take note of this, so we can un-cut our board
                var old_space_left = board.space_left;

                //make the cut
                cut.quantity--; //deduct from the quantity of this cut size
                board.cut_indices.push(c);
                board.space_left -= cut.length + job.settings.kerf;
                //yes, the above can yeild negative values for a filled board
                //but, becuase of the gaurd above, we are gauranteed that
                //(board.space_left >= cut.length)

                //recurse for the next cut
                full_solve.cut_board(job, board, reveal_candidate);

                //undo the cut
                board.space_left = old_space_left;
                board.cut_indices.pop()
                cut.quantity++;
            });
        }
        else
        {
            //board has been filled, or we've finished up all of the desired cuts
            //clone, don't expose the actual object that we're fiddeling with
            reveal_candidate(clone_board(board));
        }
    },

};
<commit_msg>handled the case of an impossible layout<commit_after>/*
 *  Brendan Whitfield (C) 2014
 *
 *  Solves for the OPTIMAL cut pattern (least possible loss).
 *  Solutions are traversed recursively.
 *  Solutions are judged based on their total loss and the distribution of that loss.
 */

var full_solve = {

    run:function(job) {

        var best_layout = null;

        //the stats for the best layout
        var best_loss; //minimize this
        var best_clumping; //TODO

        full_solve.choose_source(job, [], function(layout) {

            if(!best_layout || (loss_in_layout(layout) < best_loss))
                best_layout = layout;

        });

        return best_layout;
    },

    //WARNING: recursive
    choose_source: function(job, layout, reveal_candidate) {
        if(cuts_left(job) > 0)
        {
            //loop through every length (type) of source material
            job.sources.forEach(function(source, s) {

                if(source.quantity == 0)
                    return; //skip spent sources

                //compute a cut layout for this source
                var filled_board = full_solve.fill_board(job, make_board(job, s));

                //if this board couldn't be cut... at all...
                //this can happen when all of the cut sizes are larger than the remaining boards
                if(filled_board.cut_indices.length == 0)
                {
                    //dont reveal incomplete candidates
                    return; //don't recurse
                }

                source.quantity--; //deduct
                layout.push(filled_board);

                //recurse for the next source board
                full_solve.choose_source(job, layout, reveal_candidate);

                layout.pop();
                source.quantity++;
            });
        }
        else
        {
            //solution has been reached
            reveal_candidate(clone_layout(layout));
        }
    },

    //wrapper function around the recursive board cutter.
    //Stores and returns the best solution.
    fill_board: function(job, board) {

        var best_board; //the layout with the least loss

        full_solve.cut_board(job, board, function(filled_board) {

            //see if this solution is any better than the last
            if((!best_board) || (filled_board.space_left < best_board.space_left))
                best_board = filled_board;
        });

        return best_board;
    },

    //WARNING: recursive
    //tries to make another cut
    cut_board: function(job, board, reveal_candidate) {

        //if there's work left to do on this board
        if((space_left > 0) && (cuts_left(job) > 0))
        {
            //loop through every length (type) of cut still available
            job.cuts.forEach(function(cut, c) {

                if(cut.quantity == 0)
                    return; //skip spent cut sizes

                //if this cut size is too long for the remaining space
                if(board.space_left < cut.length)
                {
                    //there's a chance that this is all we'll get out of this board.
                    //The rest is simply loss. So, whenever we run into a piece that's too big,
                    //report it anyway. Also handles cases where NO cuts could be made,
                    //because the board might have been too small for ANY of our cut sizes.
                    reveal_candidate(clone_board(board));
                    return; //don't recurse
                }

                //if we've made it this far, then there is enough space for our cut size

                //take note of this, so we can un-cut our board
                var old_space_left = board.space_left;

                //make the cut
                cut.quantity--; //deduct from the quantity of this cut size
                board.cut_indices.push(c);
                board.space_left -= cut.length + job.settings.kerf;
                //yes, the above can yeild negative values for a filled board
                //but, becuase of the gaurd above, we are gauranteed that
                //(board.space_left >= cut.length)

                //recurse for the next cut
                full_solve.cut_board(job, board, reveal_candidate);

                //undo the cut
                board.space_left = old_space_left;
                board.cut_indices.pop()
                cut.quantity++;
            });
        }
        else
        {
            //board has been filled, or we've finished up all of the desired cuts
            //clone, don't expose the actual object that we're fiddeling with
            reveal_candidate(clone_board(board));
        }
    },

};
<|endoftext|>


<commit_before>/**
 * This library calculates the current phase of the moon
 * as well as finds the dates of the recent moon phases.
 *
 * Ported from python version found here:
 * https://bazaar.launchpad.net/~keturn/py-moon-phase/trunk/annotate/head:/moon.py
 *
 * Author: Ryan Seys (https://github.com/ryanseys)
 */

'use strict'

const julian = require('./julian')

// Phases of the moon & precision
const NEW = 0 / 4.0
const FIRST = 1 / 4.0
const FULL = 2 / 4.0
const LAST = 3 / 4.0

// Astronomical Constants
// JDN stands for Julian Day Number
// Angles here are in degrees
// 1980 January 0.0 in JDN
// XXX: DateTime(1980).jdn yields 2444239.5 -- which one is right?
// XXX: even though 2444239.5 is correct for the 1 Jan 1980, 2444238.5 gives
// better accuracy results... possibly somebody chose all of the below
// constants based on the wrong epoch?
const EPOCH = 2444238.5

// Ecliptic longitude of the Sun at epoch 1980.0
const ECLIPTIC_LONGITUDE_EPOCH = 278.833540

// Ecliptic longitude of the Sun at perigee
const ECLIPTIC_LONGITUDE_PERIGEE = 282.596403

// Eccentricity of Earth's orbit
const ECCENTRICITY = 0.016718

// Semi-major axis of Earth's orbit, in kilometers
const SUN_SMAXIS = 1.49585e8

// Sun's angular size, in degrees, at semi-major axis distance
const SUN_ANGULAR_SIZE_SMAXIS = 0.533128

// Elements of the Moon's orbit, epoch 1980.0
// Moon's mean longitude at the epoch
const MOON_MEAN_LONGITUDE_EPOCH = 64.975464

// Mean longitude of the perigee at the epoch
const MOON_MEAN_PERIGEE_EPOCH = 349.383063

// Eccentricity of the Moon's orbit
const MOON_ECCENTRICITY = 0.054900

// Moon's angular size at distance a from Earth
const MOON_ANGULAR_SIZE = 0.5181

// Semi-mojor axis of the Moon's orbit, in kilometers
const MOON_SMAXIS = 384401.0

// Synodic month (new Moon to new Moon), in days
const SYNODIC_MONTH = 29.53058868

function fixangle (a) {
  return a - 360.0 * Math.floor(a / 360.0)
}

/**
 * Convert degrees to radians
 * @param  {Number} d Angle in degrees
 * @return {Number}   Angle in radians
 */
function torad (d) {
  return (Math.PI / 180.0) * d
}

/**
 * Convert radians to degrees
 * @param  {Number} r Angle in radians
 * @return {Number}   Angle in degrees
 */
function todeg (r) {
  return (180.0 / Math.PI) * r
}

function dsin (d) {
  return Math.sin(torad(d))
}

function dcos (d) {
  return Math.cos(torad(d))
}

/**
 * Solve the equation of Kepler.
 */
function kepler (m, ecc) {
  const epsilon = 1e-6

  m = torad(m)
  let e = m
  while (1) {
    const delta = e - ecc * Math.sin(e) - m
    e -= delta / (1.0 - ecc * Math.cos(e))

    if (Math.abs(delta) <= epsilon) {
      break
    }
  }

  return e
}

/**
 * Finds the phase information for specific date.
 * @param  {Date} phase_date Date to get phase information of.
 * @return {Object}          Phase data
 */
function phase (phase_date) {
  if (!phase_date) {
    phase_date = new Date()
  }
  phase_date = julian.fromDate(phase_date)

  const day = phase_date - EPOCH

  // Mean anomaly of the Sun
  // XXX: capital vars should only be used for local constants
  const N = fixangle((360 / 365.2422) * day)

  // Convert from perigee coordinates to epoch 1980
  // XXX: capital vars should only be used for local constants
  const M = fixangle(N + ECLIPTIC_LONGITUDE_EPOCH - ECLIPTIC_LONGITUDE_PERIGEE)

  // Solve Kepler's equation
  // True anomaly
  // XXX: capital vars should only be used for local constants
  let Ec = kepler(M, ECCENTRICITY)
  Ec = Math.sqrt((1 + ECCENTRICITY) / (1 - ECCENTRICITY)) * Math.tan(Ec / 2)
  Ec = 2 * todeg(Math.atan(Ec))

  // Suns's geometric ecliptic longuitude
  const lambda_sun = fixangle(Ec + ECLIPTIC_LONGITUDE_PERIGEE)

  // Orbital distance factor
  // XXX: capital vars should only be used for local constants
  const F = ((1 + ECCENTRICITY * dcos(Ec)) / (1 - ECCENTRICITY * ECCENTRICITY))

  // Distance to Sun in km
  const sun_dist = SUN_SMAXIS / F
  const sun_angular_diameter = F * SUN_ANGULAR_SIZE_SMAXIS

  // Calculation of the Moon's position

  // Moon's mean longitude
  const moon_longitude = fixangle(13.1763966 * day + MOON_MEAN_LONGITUDE_EPOCH)

  // Moon's mean anomaly
  // XXX: capital vars should only be used for local constants
  const MM = fixangle(moon_longitude - 0.1114041 * day - MOON_MEAN_PERIGEE_EPOCH)

  const evection = 1.2739 * dsin(2 * (moon_longitude - lambda_sun) - MM)

  // Annual equation
  const annual_eq = 0.1858 * dsin(M)

  // Correction term
  // XXX: capital vars should only be used for local constants
  const A3 = 0.37 * dsin(M)

  // XXX: capital vars should only be used for local constants
  const MmP = MM + evection - annual_eq - A3

  // Correction for the equation of the centre
  const mEc = 6.2886 * dsin(MmP)

  // Another correction term
  // XXX: capital vars should only be used for local constants
  const A4 = 0.214 * dsin(2 * MmP)

  // Corrected longitude
  const lP = moon_longitude + evection + mEc - annual_eq + A4

  // Variation
  const variation = 0.6583 * dsin(2 * (lP - lambda_sun))

  // True longitude
  const lPP = lP + variation

  // Calculation of the phase of the Moon

  // Age of the Moon, in degrees
  const moon_age = lPP - lambda_sun

  // Phase of the Moon
  const moon_phase = (1 - dcos(moon_age)) / 2.0

  // Calculate distance of Moon from the centre of the Earth
  const moon_dist = (MOON_SMAXIS * (1 - MOON_ECCENTRICITY * MOON_ECCENTRICITY)) / (1 + MOON_ECCENTRICITY * dcos(MmP + mEc))

  // Calculate Moon's angular diameter
  const moon_diam_frac = moon_dist / MOON_SMAXIS
  const moon_angular_diameter = MOON_ANGULAR_SIZE / moon_diam_frac

  return {
    phase: fixangle(moon_age) / 360.0,
    illuminated: moon_phase,
    age: SYNODIC_MONTH * fixangle(moon_age) / 360.0,
    distance: moon_dist,
    angular_diameter: moon_angular_diameter,
    sun_distance: sun_dist,
    sun_angular_diameter: sun_angular_diameter
  }
}

/**
 * Calculates time of the mean new Moon for a given base date.
 * This argument K to this function is the precomputed synodic month
 * index, given by:
 *   K = (year - 1900) * 12.3685
 * where year is expressed as a year and fractional year.
 * @param  {Date} sdate   Start date
 * @param  {[type]} k     [description]
 * @return {[type]}       [description]
 */
function meanphase (sdate, k) {
  // Time in Julian centuries from 1900 January 12 noon UTC
  const delta_t = (sdate - -2208945600000.0) / 86400000.0
  const t = delta_t / 36525
  return 2415020.75933 +
    SYNODIC_MONTH * k +
    (0.0001178 - 0.000000155 * t) * t * t +
    0.00033 * dsin(166.56 + (132.87 - 0.009173 * t) * t)
}

/**
 * Given a K value used to determine the mean phase of the new
 * moon, and a phase selector (0.0, 0.25, 0.5, 0.75), obtain the
 * true, corrected phase time.
 * @param  {[type]} k      [description]
 * @param  {[type]} tphase [description]
 * @return {[type]}        [description]
 */
function truephase (k, tphase) {
  // add phase to new moon time
  k = k + tphase

  // Time in Julian centuries from 1900 January 0.5
  const t = k / 1236.85

  // Mean time of phase
  let pt = 2415020.75933 +
    SYNODIC_MONTH * k +
    (0.0001178 - 0.000000155 * t) * t * t +
    0.00033 * dsin(166.56 + (132.87 - 0.009173 * t) * t)

  // Sun's mean anomaly
  const m = 359.2242 + 29.10535608 * k - (0.0000333 - 0.00000347 * t) * t * t

  // Moon's mean anomaly
  const mprime = 306.0253 + 385.81691806 * k + (0.0107306 + 0.00001236 * t) * t * t

  // Moon's argument of latitude
  const f = 21.2964 + 390.67050646 * k - (0.0016528 - 0.00000239 * t) * t * t

  if ((tphase < 0.01) || (Math.abs(tphase - 0.5) < 0.01)) {
    // Corrections for New and Full Moon
    pt += (0.1734 - 0.000393 * t) * dsin(m) +
      0.0021 * dsin(2 * m) -
      0.4068 * dsin(mprime) +
      0.0161 * dsin(2 * mprime) -
      0.0004 * dsin(3 * mprime) +
      0.0104 * dsin(2 * f) -
      0.0051 * dsin(m + mprime) -
      0.0074 * dsin(m - mprime) +
      0.0004 * dsin(2 * f + m) -
      0.0004 * dsin(2 * f - m) -
      0.0006 * dsin(2 * f + mprime) +
      0.0010 * dsin(2 * f - mprime) +
      0.0005 * dsin(m + 2 * mprime)
  } else if ((Math.abs(tphase - 0.25) < 0.01) || (Math.abs(tphase - 0.75) < 0.01)) {
    pt += (0.1721 - 0.0004 * t) * dsin(m) +
      0.0021 * dsin(2 * m) -
      0.6280 * dsin(mprime) +
      0.0089 * dsin(2 * mprime) -
      0.0004 * dsin(3 * mprime) +
      0.0079 * dsin(2 * f) -
      0.0119 * dsin(m + mprime) -
      0.0047 * dsin(m - mprime) +
      0.0003 * dsin(2 * f + m) -
      0.0004 * dsin(2 * f - m) -
      0.0006 * dsin(2 * f + mprime) +
      0.0021 * dsin(2 * f - mprime) +
      0.0003 * dsin(m + 2 * mprime) +
      0.0004 * dsin(m - 2 * mprime) -
      0.0003 * dsin(2 * m + mprime)

    // XXX: seems weird to have this be an if statement when both blocks are
    // identical save for the sign
    if (tphase < 0.5) {
      // First quarter correction
      pt += 0.0028 - 0.0004 * dcos(m) + 0.0003 * dcos(mprime)
    } else {
      // Last quarter correction
      pt += -0.0028 + 0.0004 * dcos(m) - 0.0003 * dcos(mprime)
    }
  }

  return julian.toDate(pt)
}

/**
 * Find time of phases of the moon which surround the current date.
 * Five phases are found, starting and ending with the new moons
 * which bound the current lunation.
 * @param  {Date} sdate Date to start hunting from (defaults to current date)
 * @return {Object}     Object containing recent past and future phases
 */
function phase_hunt (sdate) {
  if (!sdate) {
    sdate = new Date()
  }

  let adate = new Date(sdate.getTime() - (45 * 86400000)) // 45 days prior
  let k1 = Math.floor(12.3685 * (adate.getFullYear() + ((1.0 / 12.0) * adate.getMonth()) - 1900))
  let nt1 = meanphase(adate.getTime(), k1)

  sdate = julian.fromDate(sdate)
  adate = nt1

  let k2
  let nt2
  while (1) {
    adate = adate + SYNODIC_MONTH
    k2 = k1 + 1
    nt2 = meanphase(adate, k2)
    if (nt1 <= sdate && sdate < nt2) {
      break
    }
    nt1 = nt2
    k1 = k2
  }

  return {
    new_date: truephase(k1, NEW),
    q1_date: truephase(k1, FIRST),
    full_date: truephase(k1, FULL),
    q3_date: truephase(k1, LAST),
    nextnew_date: truephase(k2, NEW)
  }
}

exports.phase = phase
exports.phase_hunt = phase_hunt
<commit_msg>Switches are more self-documenting here.<commit_after>/**
 * This library calculates the current phase of the moon
 * as well as finds the dates of the recent moon phases.
 *
 * Ported from python version found here:
 * https://bazaar.launchpad.net/~keturn/py-moon-phase/trunk/annotate/head:/moon.py
 *
 * Author: Ryan Seys (https://github.com/ryanseys)
 */

'use strict'

const julian = require('./julian')

// Phases of the moon & precision
const NEW = 0
const FIRST = 1
const FULL = 2
const LAST = 3

// Astronomical Constants
// JDN stands for Julian Day Number
// Angles here are in degrees
// 1980 January 0.0 in JDN
// XXX: DateTime(1980).jdn yields 2444239.5 -- which one is right?
// XXX: even though 2444239.5 is correct for the 1 Jan 1980, 2444238.5 gives
// better accuracy results... possibly somebody chose all of the below
// constants based on the wrong epoch?
const EPOCH = 2444238.5

// Ecliptic longitude of the Sun at epoch 1980.0
const ECLIPTIC_LONGITUDE_EPOCH = 278.833540

// Ecliptic longitude of the Sun at perigee
const ECLIPTIC_LONGITUDE_PERIGEE = 282.596403

// Eccentricity of Earth's orbit
const ECCENTRICITY = 0.016718

// Semi-major axis of Earth's orbit, in kilometers
const SUN_SMAXIS = 1.49585e8

// Sun's angular size, in degrees, at semi-major axis distance
const SUN_ANGULAR_SIZE_SMAXIS = 0.533128

// Elements of the Moon's orbit, epoch 1980.0
// Moon's mean longitude at the epoch
const MOON_MEAN_LONGITUDE_EPOCH = 64.975464

// Mean longitude of the perigee at the epoch
const MOON_MEAN_PERIGEE_EPOCH = 349.383063

// Eccentricity of the Moon's orbit
const MOON_ECCENTRICITY = 0.054900

// Moon's angular size at distance a from Earth
const MOON_ANGULAR_SIZE = 0.5181

// Semi-mojor axis of the Moon's orbit, in kilometers
const MOON_SMAXIS = 384401.0

// Synodic month (new Moon to new Moon), in days
const SYNODIC_MONTH = 29.53058868

function fixangle (a) {
  return a - 360.0 * Math.floor(a / 360.0)
}

/**
 * Convert degrees to radians
 * @param  {Number} d Angle in degrees
 * @return {Number}   Angle in radians
 */
function torad (d) {
  return (Math.PI / 180.0) * d
}

/**
 * Convert radians to degrees
 * @param  {Number} r Angle in radians
 * @return {Number}   Angle in degrees
 */
function todeg (r) {
  return (180.0 / Math.PI) * r
}

function dsin (d) {
  return Math.sin(torad(d))
}

function dcos (d) {
  return Math.cos(torad(d))
}

/**
 * Solve the equation of Kepler.
 */
function kepler (m, ecc) {
  const epsilon = 1e-6

  m = torad(m)
  let e = m
  while (1) {
    const delta = e - ecc * Math.sin(e) - m
    e -= delta / (1.0 - ecc * Math.cos(e))

    if (Math.abs(delta) <= epsilon) {
      break
    }
  }

  return e
}

/**
 * Finds the phase information for specific date.
 * @param  {Date} phase_date Date to get phase information of.
 * @return {Object}          Phase data
 */
function phase (phase_date) {
  if (!phase_date) {
    phase_date = new Date()
  }
  phase_date = julian.fromDate(phase_date)

  const day = phase_date - EPOCH

  // Mean anomaly of the Sun
  // XXX: capital vars should only be used for local constants
  const N = fixangle((360 / 365.2422) * day)

  // Convert from perigee coordinates to epoch 1980
  // XXX: capital vars should only be used for local constants
  const M = fixangle(N + ECLIPTIC_LONGITUDE_EPOCH - ECLIPTIC_LONGITUDE_PERIGEE)

  // Solve Kepler's equation
  // True anomaly
  // XXX: capital vars should only be used for local constants
  let Ec = kepler(M, ECCENTRICITY)
  Ec = Math.sqrt((1 + ECCENTRICITY) / (1 - ECCENTRICITY)) * Math.tan(Ec / 2)
  Ec = 2 * todeg(Math.atan(Ec))

  // Suns's geometric ecliptic longuitude
  const lambda_sun = fixangle(Ec + ECLIPTIC_LONGITUDE_PERIGEE)

  // Orbital distance factor
  // XXX: capital vars should only be used for local constants
  const F = ((1 + ECCENTRICITY * dcos(Ec)) / (1 - ECCENTRICITY * ECCENTRICITY))

  // Distance to Sun in km
  const sun_dist = SUN_SMAXIS / F
  const sun_angular_diameter = F * SUN_ANGULAR_SIZE_SMAXIS

  // Calculation of the Moon's position

  // Moon's mean longitude
  const moon_longitude = fixangle(13.1763966 * day + MOON_MEAN_LONGITUDE_EPOCH)

  // Moon's mean anomaly
  // XXX: capital vars should only be used for local constants
  const MM = fixangle(moon_longitude - 0.1114041 * day - MOON_MEAN_PERIGEE_EPOCH)

  const evection = 1.2739 * dsin(2 * (moon_longitude - lambda_sun) - MM)

  // Annual equation
  const annual_eq = 0.1858 * dsin(M)

  // Correction term
  // XXX: capital vars should only be used for local constants
  const A3 = 0.37 * dsin(M)

  // XXX: capital vars should only be used for local constants
  const MmP = MM + evection - annual_eq - A3

  // Correction for the equation of the centre
  const mEc = 6.2886 * dsin(MmP)

  // Another correction term
  // XXX: capital vars should only be used for local constants
  const A4 = 0.214 * dsin(2 * MmP)

  // Corrected longitude
  const lP = moon_longitude + evection + mEc - annual_eq + A4

  // Variation
  const variation = 0.6583 * dsin(2 * (lP - lambda_sun))

  // True longitude
  const lPP = lP + variation

  // Calculation of the phase of the Moon

  // Age of the Moon, in degrees
  const moon_age = lPP - lambda_sun

  // Phase of the Moon
  const moon_phase = (1 - dcos(moon_age)) / 2.0

  // Calculate distance of Moon from the centre of the Earth
  const moon_dist = (MOON_SMAXIS * (1 - MOON_ECCENTRICITY * MOON_ECCENTRICITY)) / (1 + MOON_ECCENTRICITY * dcos(MmP + mEc))

  // Calculate Moon's angular diameter
  const moon_diam_frac = moon_dist / MOON_SMAXIS
  const moon_angular_diameter = MOON_ANGULAR_SIZE / moon_diam_frac

  return {
    phase: fixangle(moon_age) / 360.0,
    illuminated: moon_phase,
    age: SYNODIC_MONTH * fixangle(moon_age) / 360.0,
    distance: moon_dist,
    angular_diameter: moon_angular_diameter,
    sun_distance: sun_dist,
    sun_angular_diameter: sun_angular_diameter
  }
}

/**
 * Calculates time of the mean new Moon for a given base date.
 * This argument K to this function is the precomputed synodic month
 * index, given by:
 *   K = (year - 1900) * 12.3685
 * where year is expressed as a year and fractional year.
 * @param  {Date} sdate   Start date
 * @param  {[type]} k     [description]
 * @return {[type]}       [description]
 */
function meanphase (sdate, k) {
  // Time in Julian centuries from 1900 January 12 noon UTC
  const delta_t = (sdate - -2208945600000.0) / 86400000.0
  const t = delta_t / 36525
  return 2415020.75933 +
    SYNODIC_MONTH * k +
    (0.0001178 - 0.000000155 * t) * t * t +
    0.00033 * dsin(166.56 + (132.87 - 0.009173 * t) * t)
}

/**
 * Given a K value used to determine the mean phase of the new
 * moon, and a phase selector (0.0, 0.25, 0.5, 0.75), obtain the
 * true, corrected phase time.
 * @param  {[type]} k      [description]
 * @param  {[type]} tphase [description]
 * @return {[type]}        [description]
 */
function truephase (k, tphase) {
  // add phase to new moon time
  k = k + 0.25 * tphase

  // Time in Julian centuries from 1900 January 0.5
  const t = k / 1236.85

  // Mean time of phase
  let pt = 2415020.75933 +
    SYNODIC_MONTH * k +
    (0.0001178 - 0.000000155 * t) * t * t +
    0.00033 * dsin(166.56 + (132.87 - 0.009173 * t) * t)

  // Sun's mean anomaly
  const m = 359.2242 + 29.10535608 * k - (0.0000333 - 0.00000347 * t) * t * t

  // Moon's mean anomaly
  const mprime = 306.0253 + 385.81691806 * k + (0.0107306 + 0.00001236 * t) * t * t

  // Moon's argument of latitude
  const f = 21.2964 + 390.67050646 * k - (0.0016528 - 0.00000239 * t) * t * t

  switch (tphase & 3) {
    case NEW:
    case FULL:
      pt += (0.1734 - 0.000393 * t) * dsin(m) +
        0.0021 * dsin(2 * m) -
        0.4068 * dsin(mprime) +
        0.0161 * dsin(2 * mprime) -
        0.0004 * dsin(3 * mprime) +
        0.0104 * dsin(2 * f) -
        0.0051 * dsin(m + mprime) -
        0.0074 * dsin(m - mprime) +
        0.0004 * dsin(2 * f + m) -
        0.0004 * dsin(2 * f - m) -
        0.0006 * dsin(2 * f + mprime) +
        0.0010 * dsin(2 * f - mprime) +
        0.0005 * dsin(m + 2 * mprime)
      break

    case FIRST:
    case LAST:
      pt += (0.1721 - 0.0004 * t) * dsin(m) +
        0.0021 * dsin(2 * m) -
        0.6280 * dsin(mprime) +
        0.0089 * dsin(2 * mprime) -
        0.0004 * dsin(3 * mprime) +
        0.0079 * dsin(2 * f) -
        0.0119 * dsin(m + mprime) -
        0.0047 * dsin(m - mprime) +
        0.0003 * dsin(2 * f + m) -
        0.0004 * dsin(2 * f - m) -
        0.0006 * dsin(2 * f + mprime) +
        0.0021 * dsin(2 * f - mprime) +
        0.0003 * dsin(m + 2 * mprime) +
        0.0004 * dsin(m - 2 * mprime) -
        0.0003 * dsin(2 * m + mprime)

      switch (tphase & 1) {
        case (FIRST & 1):
          pt += 0.0028 - 0.0004 * dcos(m) + 0.0003 * dcos(mprime)
          break

        case (LAST & 1):
          pt += -0.0028 + 0.0004 * dcos(m) - 0.0003 * dcos(mprime)
          break
      }
      break
  }

  return julian.toDate(pt)
}

/**
 * Find time of phases of the moon which surround the current date.
 * Five phases are found, starting and ending with the new moons
 * which bound the current lunation.
 * @param  {Date} sdate Date to start hunting from (defaults to current date)
 * @return {Object}     Object containing recent past and future phases
 */
function phase_hunt (sdate) {
  if (!sdate) {
    sdate = new Date()
  }

  let adate = new Date(sdate.getTime() - (45 * 86400000)) // 45 days prior
  let k1 = Math.floor(12.3685 * (adate.getFullYear() + ((1.0 / 12.0) * adate.getMonth()) - 1900))
  let nt1 = meanphase(adate.getTime(), k1)

  sdate = julian.fromDate(sdate)
  adate = nt1

  let k2
  let nt2
  while (1) {
    adate = adate + SYNODIC_MONTH
    k2 = k1 + 1
    nt2 = meanphase(adate, k2)
    if (nt1 <= sdate && sdate < nt2) {
      break
    }
    nt1 = nt2
    k1 = k2
  }

  return {
    new_date: truephase(k1, NEW),
    q1_date: truephase(k1, FIRST),
    full_date: truephase(k1, FULL),
    q3_date: truephase(k1, LAST),
    nextnew_date: truephase(k2, NEW)
  }
}

exports.phase = phase
exports.phase_hunt = phase_hunt
<|endoftext|>


<commit_before>jQuery(function($) {

  /* get cookie */
  var member = decodeURIComponent(getCookie('member'));
  var jso = JSON.parse(member);

  /* map of keys: key from cookies : name from form */
  var fields = {
    "firstname" : "first_name",
    "lastname" : "last_name",
    "email" : "email-5",
    "postcode" : "postal_code"
  };
  $.each(fields, function(k, f) {
    var el = $("input[name*="+f+"]");
    if (!el.val()) {
     el.val(jso[k]);
    }
  });
});

function getCookie(name) {
  var value = "; " + document.cookie;
  var parts = value.split("; " + name + "=");
  if (parts.length == 2) return parts.pop().split(";").shift();
}
<commit_msg>Prefill country on donation form based on cookie member<commit_after>jQuery(function($) {

  /* get cookie */
  var member = decodeURIComponent(getCookie('member'));
  var jso = JSON.parse(member);

  /* map of keys: key from cookies : name from form */
  var fields = {
    "firstname" : "first_name",
    "lastname" : "last_name",
    "email" : "email-5",
    "postcode" : "postal_code"
  };
  $.each(fields, function(k, f) {
    var el = $("input[name*="+f+"]");
    if (!el.val()) {
     el.val(jso[k]);
    }
  });

  /* set country */
  var countries = {
    "fr" : 1076,
    "de" : 1082,
    "gr" : 1085,
    "it" : 1107,
    "pl" : 1172,
    "pt" : 1173,
    "es" : 1198,
    "gb" : 1226,
    "uk" : 1226
  };

  if (jso.country && countries[jso.country]) {
    var ccc = {
      1 : "country-1",
      2 : "country_id-5"
    };
    $.each(ccc, function(k, f) {
      $("#" + f).val(countries[jso.country]).change(function(e){$("#select2-chosen-1").text($("#" + f + " option:selected").text());}).trigger("change");
    });
  }
});

function getCookie(name) {
  var value = "; " + document.cookie;
  var parts = value.split("; " + name + "=");
  if (parts.length == 2) return parts.pop().split(";").shift();
}
<|endoftext|>


<commit_before>var nm = require("nodemailer");
var t = nm.createTransport();

function sendAlert(stringerName, alertContent) {
  t.sendMail({
    from: "bot@data.string.er",
    to: config.userEmail,
    subject: "ALERT for " + stringerName,
    text: "On today's run, " + stringerName + "generated an alert, with the " +
        "following content:\n" + alertContent // TODO pretty print the object
  },
  function(err, info) {
    if(err) {
      console.log(err);
    }
  });
}

module.exports = {
  sendAler: sendAlert,
};
<commit_msg>Mailer: fix typo<commit_after>var nm = require("nodemailer");
var t = nm.createTransport();

function sendAlert(stringerName, alertContent) {
  t.sendMail({
    from: "bot@data.string.er",
    to: "basile@basilesimon.fr",
    subject: "ALERT for " + stringerName,
    text: "On today's run, " + stringerName + "generated an alert, with the " +
        "following content:\n" + alertContent // TODO pretty print the object
  },
  function(err, info) {
    if(err) {
      console.log(err);
    }
  });
}

module.exports = {
  sendAlert: sendAlert,
};
<|endoftext|>


<commit_before>#!/usr/bin/env node

/*
 * nodebox
 * https://github.com/sack.io/nodebox
 *
 * Copyright (c) 2015 Ben Sack
 * Licensed under the MIT license.
 */

var Path = require('path')
  , Optionall = require('optionall')
  , FSTK = require('fstk')
  , OS = require('os')
  , Async = require('async')
  , _ = require('underscore')
  , Belt = require('jsbelt')
  , Util = require('util')
  , Winston = require('winston')
  , Events = require('events')
  , Zlib = require('zlib')
  , Crypto = require('crypto')
  , AWS = require('aws-sdk')
  , Spinner = require('its-thinking')
;

module.exports = function(O){
  var Opts = O || new Optionall({
                                  '__dirname': Path.resolve(module.filename + '/../..')
                                , 'file_priority': ['package.json', 'environment.json', 'config.json']
                                });

  var S = new (Events.EventEmitter.bind({}))();
  S.settings = Belt.extend({
    'log_level': 'debug'
  , 'spin_pattern': 4
  , 'stat_concurrency': OS.cpus().length * OS.cpus().length
  , 'sync_concurrency': OS.cpus().length
  , 'upload_concurrency': 5
  }, Opts);

  var log = Opts.log || new Winston.Logger();
  if (!Opts.log) log.add(Winston.transports.Console, {'level': S.settings.log_level, 'colorize': true, 'timestamp': false});
  S.log = log;

  S['spinner'] = new Spinner(S.settings.spin_pattern);

  //////////////////////////////////////////////////////////////////////////////
  ////                           METHODS                                    ////
  //////////////////////////////////////////////////////////////////////////////

  S['start'] = function(options, callback){
    var a = Belt.argulint(arguments)
      , self = this;
    a.o = _.defaults(a.o, {
      'loop': false
    , 'wait_int': 500
    , 'priority': -Infinity
      //start_path
    });

    self.statQueue.push({'path': a.o.start_path}, a.o.priority);

    setTimeout(function(){
      Async.until(function(){ return !S.statQueue.length() && S.syncQueue.length(); }
      , function(next){ return setTimeout(next, 500); }
      , a.cb);
    }, 2000);

    return S;
  };

  S['sync'] = function(options, callback){
    options.part_size = 1000000;
    options.storage_class = 'REDUCED_REDUNDANCY';
    options.acl = 'private';
    options.algorithm = 'md5';
    options.bucket = S.settings.bucket;
    options.file_prefix = S.settings.file_prefix;
    options.checksum_prefix = S.settings.checksum_prefix;
    options.upload_concurrency = S.settings.upload_concurrency;

    var s3 = new AWS.S3(_.omit(S.settings.aws, ['bucket']))
      , gb = {}
      , ocb = _.once(function(){
          gb['ended'] = true;
          return callback.apply(this, arguments);
        });

    return Async.waterfall([
      function(cb){
        gb['fstream'] = FSTK._fs.createReadStream(options.file_path);

        //log.info('Opened [' + options.file_path + ']');

        gb.fstream.on('error', ocb);

        return cb();
      }
    , function(cb){
        return s3.getObject({
          'Bucket': options.bucket
        , 'Key': options.file_prefix + options.file_path.replace(/^\//, '') + '.checksums.gz'
        }, function(err, data){
          if (err) return cb(err.code === 'NoSuchKey' ? undefined : err);

          gb['s3_obj'] = data;

          return cb();
        });
      }
    , function(cb){
        if (!Belt.get(gb, 's3_obj.Body')) return cb();

        //log.info('Received object [' + options.file_prefix + options.file_path + '][' + options.bucket + ']');

        return Zlib.gunzip(gb.s3_obj.Body, Belt.cs(cb, gb, 's3_gunzip', 1, 0));
      }
    , function(cb){
        if (!gb.s3_gunzip) return cb();

        gb['s3_manifest'] = gb.s3_gunzip.toString().split('\n');

        //log.info('Unzipped object [' + options.file_prefix + options.file_path + '][' + options.bucket + ']');

        return cb();
      }
    , function(cb){
        gb['manifest'] = [];
        gb['manifest_object'] = {};

        gb.s3_manifest = gb.s3_manifest || [];

        var index = 0;

        gb.fstream.on('close', function(){
          //log.info('Close [' + options.file_path + ']');
          return gb['fstream_closed'] = true;
        });

        gb.upload_queue = Async.queue(function(task, next){
          var _gb = {};
          return Async.waterfall([
            function(cb){
              return s3.headObject({
                'Bucket': options.bucket
              , 'Key': options.checksum_prefix + task.sum
              }, function(err, obj){
                if (obj){
                  //log.warn('Part on S3 [' + task.sum + '][' + task.index + ']');
                  return next();
                }

                if (!err || err.code !== 'NotFound'){
                  //if (err) log.error(error);
                  return next(err);
                }

                return cb();
              });
            }
          , function(cb){
              return Zlib.gzip(task.part, Belt.cs(cb, _gb, 'gz', 1, 0));
            }
          ], function(err){
            if (err) return next(err);

            //log.info('Uploading part [' + task.sum + '][' + task.index + ']');

            return s3.putObject({
              'Bucket': options.bucket
            , 'Key': options.checksum_prefix + task.sum
            , 'Body': _gb.gzip
            , 'StorageClass': options.storage_class
            , 'ACL': options.acl
            }, Belt.cw(next, 0));
          });
        }, options.upload_concurrency);

        gb.fstream.on('readable', function(){
          var ind, part, sum;
          while (null !== (part = gb.fstream.read(options.part_size)) && !Belt.isNull(ind = index) && ++index){
            sum = Crypto.createHash(options.algorithm).update(part).digest('hex');
            gb.manifest[ind] = sum;

            //log.info('Read part [' + sum + '][' + ind + ']');

            if (sum === gb.s3_manifest[ind]){
              //log.info('Part matched manifest [' + sum + ']');
            } else {
              //log.error('Part did not match manifest [' + sum + ']');
              gb['changed'] = true;
            }

            if (gb.manifest_object[sum]){
              //log.warn('Part already uploaded [' + sum + ']');
              continue;
            }

            gb.manifest_object[sum] = true;

            gb.upload_queue.push({'sum': sum, 'part': part, 'index': ind});
          }
        });

        Async.until(function(){ return !gb.upload_queue.length() && gb.fstream_closed; }
        , function(next){ return setTimeout(next, 500); }
        , cb);
      }
    , function(cb){
        if (!gb.changed) return cb();

        return Zlib.gzip(gb.manifest.join('\n'), Belt.cs(cb, gb, 'gzip_manifest', 1, 0));
      }
    , function(cb){
        if (!gb.gzip_manifest) return cb();

        //log.info('Uploading part manifest');

        return s3.putObject({
          'Bucket': options.bucket
        , 'Key': options.file_prefix + options.file_path.replace(/^\//, '') + '.checksums.gz'
        , 'Body': gb.gzip_manifest
        }, cb);
      }
    ], function(err){
      return ocb(err, gb.changed);
    });
  };

  //////////////////////////////////////////////////////////////////////////////
  ////                           QUEUES                                     ////
  //////////////////////////////////////////////////////////////////////////////

  S['statQueue'] = Async.priorityQueue(function(task, next){
    return FSTK._fs.lstat(task.path, function(err, stat){
      if (err){
        return next();
      }

      if (stat.isSymbolicLink()){
        //TODO - put object to represent link
        return next();
      }

      if (stat.isDirectory()) {
        var mtime = -1 * stat.mtime.getTime();
        return FSTK._fs.readdir(task.path, function(err, paths){
          if (err || !_.any(paths)){
            return next();
          }

          _.each(paths, function(p){
            return S.statQueue.push({
              'path': task.path + '/' + p
            }, mtime);
          });

          return next();
        });
      }

      if (!stat.isFile()){
        //TODO - put object to represent non-file
        return next();
      }

      S.syncQueue.push(task, -1 * stat.mtime.getTime());

      return next();
    });
  }, S.settings.stat_concurrency);

  S['syncQueue'] = Async.priorityQueue(function(task, next){
    return S.sync({
      'file_path': task.path
    }, function(err, changed){
      log.info(arguments);
      log.info('SYNCED [' + task.path + ']');
      return next();
    });
  }, S.settings.sync_concurrency);

  return S;
};

if (require.main === module){
  var M = new module.exports()
    , method = _.find(_.keys(M.settings.argv), function(k){ return M[k]; });

  if (!method){
    M.log.error('Method not found');
    process.exit(1);
  } else {
    M[method](M.settings.argv, function(err, res){
      if (err) M.log.error(err);
      if (res) M.log.info(Belt.stringify(res));
      return process.exit(err ? 1 : 0);
    });
  }
}
<commit_msg>latest<commit_after>#!/usr/bin/env node

/*
 * nodebox
 * https://github.com/sack.io/nodebox
 *
 * Copyright (c) 2015 Ben Sack
 * Licensed under the MIT license.
 */

var Path = require('path')
  , Optionall = require('optionall')
  , FSTK = require('fstk')
  , OS = require('os')
  , Async = require('async')
  , _ = require('underscore')
  , Belt = require('jsbelt')
  , Util = require('util')
  , Winston = require('winston')
  , Events = require('events')
  , Zlib = require('zlib')
  , Crypto = require('crypto')
  , AWS = require('aws-sdk')
  , Spinner = require('its-thinking')
;

module.exports = function(O){
  var Opts = O || new Optionall({
                                  '__dirname': Path.resolve(module.filename + '/../..')
                                , 'file_priority': ['package.json', 'environment.json', 'config.json']
                                });

  var S = new (Events.EventEmitter.bind({}))();
  S.settings = Belt.extend({
    'log_level': 'debug'
  , 'spin_pattern': 4
  , 'stat_concurrency': 1 //OS.cpus().length * OS.cpus().length
  , 'sync_concurrency': 5 //OS.cpus().length
  , 'upload_concurrency': 5
  }, Opts);

  var log = Opts.log || new Winston.Logger();
  if (!Opts.log) log.add(Winston.transports.Console, {'level': S.settings.log_level, 'colorize': true, 'timestamp': false});
  S.log = log;

  S['spinner'] = new Spinner(S.settings.spin_pattern);

  //////////////////////////////////////////////////////////////////////////////
  ////                           METHODS                                    ////
  //////////////////////////////////////////////////////////////////////////////

  S['start'] = function(options, callback){
    var a = Belt.argulint(arguments)
      , self = this;
    a.o = _.defaults(a.o, {
      'loop': false
    , 'wait_int': 500
    , 'priority': -Infinity
      //start_path
    });

    self.syncQueue.pause();

    self.statQueue.push({'path': a.o.start_path}, a.o.priority);

    setTimeout(self.syncQueue.resume, 10000);

    setTimeout(function(){
      Async.until(function(){ return !S.statQueue.length() && !S.statQueue.running() && !S.syncQueue.length() && !S.syncQueue.running(); }
      , function(next){ return setTimeout(next, 500); }
      , a.cb);
    }, 2000);

    return S;
  };

  S['sync'] = function(options, callback){
    options.part_size = 1000000;
    options.storage_class = 'REDUCED_REDUNDANCY';
    options.acl = 'private';
    options.algorithm = 'md5';
    options.bucket = S.settings.bucket;
    options.file_prefix = S.settings.file_prefix;
    options.checksum_prefix = S.settings.checksum_prefix;
    options.upload_concurrency = S.settings.upload_concurrency;

    var s3 = new AWS.S3(_.omit(S.settings.aws, ['bucket']))
      , gb = {}
      , ocb = _.once(function(){
          gb['ended'] = true;
          return callback.apply(this, arguments);
        });

    return Async.waterfall([
      function(cb){
        gb['fstream'] = FSTK._fs.createReadStream(options.file_path);

        //log.info('Opened [' + options.file_path + ']');

        gb.fstream.on('error', ocb);

        return cb();
      }
    , function(cb){
        return s3.getObject({
          'Bucket': options.bucket
        , 'Key': options.file_prefix + options.file_path.replace(/^\//, '') + '.checksums.gz'
        }, function(err, data){
          if (err) return cb(err.code === 'NoSuchKey' ? undefined : err);

          gb['s3_obj'] = data;

          return cb();
        });
      }
    , function(cb){
        if (!Belt.get(gb, 's3_obj.Body')) return cb();

        //log.info('Received object [' + options.file_prefix + options.file_path + '][' + options.bucket + ']');

        return Zlib.gunzip(gb.s3_obj.Body, Belt.cs(cb, gb, 's3_gunzip', 1, 0));
      }
    , function(cb){
        if (!gb.s3_gunzip) return cb();

        gb['s3_manifest'] = gb.s3_gunzip.toString().split('\n');

        //log.info('Unzipped object [' + options.file_prefix + options.file_path + '][' + options.bucket + ']');

        return cb();
      }
    , function(cb){
        gb['manifest'] = [];
        gb['manifest_object'] = {};

        gb.s3_manifest = gb.s3_manifest || [];
        gb['s3_manifest_object'] = _.groupBy(gb.s3_manifest, function(m){ return m; });

        var index = 0;

        gb.fstream.on('close', function(){
          //log.info('Close [' + options.file_path + ']');
          return gb['fstream_closed'] = true;
        });

        gb.upload_queue = Async.queue(function(task, next){
          var _gb = {}
            , onext = _.once(function(){
              return next.apply(this, arguments);
            });

          setTimeout(function(){
            return onext(new Error('Timeout - upload queue'));
          }, 60000);

          return Async.waterfall([
            function(cb){
              return s3.headObject({
                'Bucket': options.bucket
              , 'Key': options.checksum_prefix + task.sum
              }, function(err, obj){
                if (obj){
                  //log.warn('Part on S3 [' + task.sum + '][' + task.index + ']');
                  return onext();
                }

                if (!err || err.code !== 'NotFound'){
                  //if (err) log.error(error);
                  return onext(err);
                }

                return cb();
              });
            }
          , function(cb){
              return Zlib.gzip(task.part, Belt.cs(cb, _gb, 'gz', 1, 0));
            }
          ], function(err){
            if (err) return onext(err);

            log.error('Uploading part [' + task.sum + '][' + task.index + ']');

            return s3.putObject({
              'Bucket': options.bucket
            , 'Key': options.checksum_prefix + task.sum
            , 'Body': _gb.gzip
            , 'StorageClass': options.storage_class
            , 'ACL': options.acl
            }, Belt.cw(onext, 0));
          });
        }, options.upload_concurrency);

        gb.fstream.on('readable', function(){
          var ind, part, sum;
          while (null !== (part = gb.fstream.read(options.part_size)) && !Belt.isNull(ind = index) && ++index){
            sum = Crypto.createHash(options.algorithm).update(part).digest('hex');
            gb.manifest[ind] = sum;

            //log.info('Read part [' + sum + '][' + ind + ']');

            if (sum === gb.s3_manifest[ind]){
              log.info('Part matched manifest [' + sum + ']');
              continue;
            } else {
              //log.error('Part did not match manifest [' + sum + ']');
              gb['changed'] = true;
            }

            if (gb.manifest_object[sum] || gb.s3_manifest_object[sum]){
              log.warn('Part already uploaded [' + sum + ']');
              continue;
            }

            gb.manifest_object[sum] = true;

            gb.upload_queue.push({'sum': sum, 'part': part, 'index': ind});
          }
        });

        Async.until(function(){ return !gb.upload_queue.length() && !gb.upload_queue.running() && gb.fstream_closed; }
        , function(next){ return setTimeout(next, 50); }
        , cb);
      }
    , function(cb){
        if (!gb.changed) return cb();

        return Zlib.gzip(gb.manifest.join('\n'), Belt.cs(cb, gb, 'gzip_manifest', 1, 0));
      }
    , function(cb){
        if (!gb.gzip_manifest) return cb();

        //log.info('Uploading part manifest');

        return s3.putObject({
          'Bucket': options.bucket
        , 'Key': options.file_prefix + options.file_path.replace(/^\//, '') + '.checksums.gz'
        , 'Body': gb.gzip_manifest
        }, cb);
      }
    ], function(err){
      return ocb(err, gb.changed, (gb.manifest || []).length);
    });
  };

  //////////////////////////////////////////////////////////////////////////////
  ////                           QUEUES                                     ////
  //////////////////////////////////////////////////////////////////////////////

  S['statQueue'] = Async.priorityQueue(function(task, next){
    //log.warn('STAT [' + task.path + ']');

    return FSTK._fs.lstat(task.path, function(err, stat){
      if (err){
        return next();
      }

      if (stat.isSymbolicLink()){
        //TODO - put object to represent link
        return next();
      }

      if (stat.isDirectory()) {
        var mtime = -1 * stat.ctime.getTime();
        return FSTK._fs.readdir(task.path, function(err, paths){
          if (err || !_.any(paths)){
            return next();
          }

          _.each(_.shuffle(paths), function(p){
            return S.statQueue.push({
              'path': task.path + '/' + p
            }, mtime);
          });

          return next();
        });
      }

      if (!stat.isFile() || stat.size === 0){
        //TODO - put object to represent non-file
        return next();
      }

      S.syncQueue.push(task, -1 * stat.ctime.getTime());

      return next();
    });
  }, S.settings.stat_concurrency);

  S['syncQueue'] = Async.priorityQueue(function(task, next){
    log.warn('START SYNC [' + task.path + ']');

    return S.sync({
      'file_path': task.path
    }, function(err, changed){
      log.info(arguments);
      log.info('SYNCED [' + task.path + ']');
      return next();
    });
  }, S.settings.sync_concurrency);

  return S;
};

if (require.main === module){
  var M = new module.exports()
    , method = _.find(_.keys(M.settings.argv), function(k){ return M[k]; });

  if (!method){
    M.log.error('Method not found');
    process.exit(1);
  } else {
    M[method](M.settings.argv, function(err, res){
      if (err) M.log.error(err);
      if (res) M.log.info(Belt.stringify(res));
      return process.exit(err ? 1 : 0);
    });
  }
}
<|endoftext|>


<commit_before>import { camelizeKeys, decamelizeKeys } from './utils'
import HttpError from './http-error'

const CSRF_METHODS = ['PATCH', 'POST', 'PUT']

const DEFAULT_CSRF_SELECTOR = 'csrf-token'

const DEFAULT_OPTIONS = {
  authenticated: false,
  tokenName: 'token',
  body: null,
  csrf: true,
  method: 'GET',
}

export default function (
  url,
  {
    authenticated = DEFAULT_OPTIONS.authenticated,
    body          = DEFAULT_OPTIONS.body,
    csrf          = DEFAULT_OPTIONS.csrf,
    method        = DEFAULT_OPTIONS.method,
    tokenName     = DEFAULT_OPTIONS.tokenName,
  }
) {

  const config = {
    headers: {
      'Accept': 'application/json',
      'X-Requested-With': 'XMLHttpRequest',
      'Content-Type': 'application/json',
    },
    method: method,
  }

  let token
  if (authenticated) {
    token = localStorage.getItem(tokenName)
    if (!token) {
      return Promise.reject(new HttpError(401, 'unauthorized', {}))
    }
  }

  if (token) {
    config.headers['Authorization'] = `Bearer ${token}`
  }

  if (CSRF_METHODS.includes(method)) {

    config.mode = 'same-origin'
    config.credentials = 'include'

    if (csrf) {

      const selector = (typeof csrf === 'string')
        ? csrf
        : DEFAULT_CSRF_SELECTOR

      config.headers['X-CSRF-Token'] = csrfToken(selector)
    }
  }

  if (body) {
    config.body = JSON.stringify(decamelizeKeys(body))
  }

  return fetch(url, config)
    .then(response => response.json()
      .then(json => {
        const camelized = camelizeKeys(json.data)
        if (response.ok) return camelized
        else throw new HttpError(response.status, response.statusText, camelized)
      })
    )
}

function csrfToken (selector) {
  if (typeof document === 'undefined') return null

  const token = document.querySelector(`meta[name="${selector}"]` )
  if (token && (token instanceof window.HTMLMetaElement)) {
    return token.content
  }
  return null
}
<commit_msg>handle data or no data<commit_after>import { camelizeKeys, decamelizeKeys } from './utils'
import HttpError from './http-error'

const CSRF_METHODS = ['PATCH', 'POST', 'PUT']

const DEFAULT_CSRF_SELECTOR = 'csrf-token'

const DEFAULT_OPTIONS = {
  authenticated: false,
  tokenName: 'token',
  body: null,
  csrf: true,
  method: 'GET',
}

export default function (
  url,
  {
    authenticated = DEFAULT_OPTIONS.authenticated,
    body          = DEFAULT_OPTIONS.body,
    csrf          = DEFAULT_OPTIONS.csrf,
    method        = DEFAULT_OPTIONS.method,
    tokenName     = DEFAULT_OPTIONS.tokenName,
  }
) {

  const config = {
    headers: {
      'Accept': 'application/json',
      'X-Requested-With': 'XMLHttpRequest',
      'Content-Type': 'application/json',
    },
    method: method,
  }

  let token
  if (authenticated) {
    token = localStorage.getItem(tokenName)
    if (!token) {
      return Promise.reject(new HttpError(401, 'unauthorized', {}))
    }
  }

  if (token) {
    config.headers['Authorization'] = `Bearer ${token}`
  }

  if (CSRF_METHODS.includes(method)) {

    config.mode = 'same-origin'
    config.credentials = 'include'

    if (csrf) {

      const selector = (typeof csrf === 'string')
        ? csrf
        : DEFAULT_CSRF_SELECTOR

      config.headers['X-CSRF-Token'] = csrfToken(selector)
    }
  }

  if (body) {
    config.body = JSON.stringify(decamelizeKeys(body))
  }

  return fetch(url, config)
    .then(response => response.json()
      .then(json => {
        const camelized = camelizeKeys(json.data || json)
        if (response.ok) return camelized
        else throw new HttpError(response.status, response.statusText, camelized)
      })
    )
}

function csrfToken (selector) {
  if (typeof document === 'undefined') return null

  const token = document.querySelector(`meta[name="${selector}"]` )
  if (token && (token instanceof window.HTMLMetaElement)) {
    return token.content
  }
  return null
}
<|endoftext|>