<commit_before>module.exports = {
    aspa: {
        type: Number
    },
    asi: {
        type: Number
    },
    acs: {
        type: Number,
        montantAnnuel: true
    },
    cmu_c: {
        type: Boolean
    },
    apl: {
        type: Number
    },
    als: {
        type: Number
    },
    alf: {
        type: Number
    },
    aide_logement: {
        type: Number
    },
    aide_logement_non_calculable: {
        type: String
    },
    af: {
        type: Number
    },
    rsa: {
        type: Number
    },
    rsa_majore: {
        type: Number
    },
    rsa_non_majore: {
        type: Number
    },
    rsa_non_calculable: {
        type: String
    },
    asf: {
        type: Number
    },
    cf: {
        type: Number
    },
    ass: {
        type: Number
    },
    paje_base: {
        type: Number
    },
    bourse_college: {
        type: Number,
        montantAnnuel: true
    },
    bourse_lycee: {
        type: Number,
        montantAnnuel: true
    },
    paris_logement_familles: {
        type: Number
    }
};
<commit_msg>Ajout adpa aux aides calculees<commit_after>module.exports = {
    aspa: {
        type: Number
    },
    asi: {
        type: Number
    },
    acs: {
        type: Number,
        montantAnnuel: true
    },
    cmu_c: {
        type: Boolean
    },
    apl: {
        type: Number
    },
    als: {
        type: Number
    },
    alf: {
        type: Number
    },
    aide_logement: {
        type: Number
    },
    aide_logement_non_calculable: {
        type: String
    },
    af: {
        type: Number
    },
    rsa: {
        type: Number
    },
    rsa_majore: {
        type: Number
    },
    rsa_non_majore: {
        type: Number
    },
    rsa_non_calculable: {
        type: String
    },
    asf: {
        type: Number
    },
    cf: {
        type: Number
    },
    ass: {
        type: Number
    },
    paje_base: {
        type: Number
    },
    bourse_college: {
        type: Number,
        montantAnnuel: true
    },
    bourse_lycee: {
        type: Number,
        montantAnnuel: true
    },
    paris_logement_familles: {
        type: Number
    },
    adpa: {
        type: Number
    }
};
<|endoftext|>


<commit_before>var createDefaultStream = require('./lib/default_stream');
var Render = require('./lib/render');
var Test = require('./lib/test');

var canEmitExit = typeof process !== 'undefined' && process
    && typeof process.on === 'function'
;
var canExit = typeof process !== 'undefined' && process
    && typeof process.exit === 'function'
;
var onexit = (function () {
    var stack = [];
    if (canEmitExit) process.on('exit', function (code) {
        for (var i = 0; i < stack.length; i++) stack[i](code);
    });
    return function (cb) { stack.push(cb) };
})();

exports = module.exports = createHarness();
exports.createHarness = createHarness;
exports.Test = Test;

var exitInterval;

function createHarness (conf_) {
    var pending = [];
    var running = false;
    var count = 0;

    var began = false;
    var only = false;
    var closed = false;
    var out = new Render();
    if (!conf_) conf_ = {};

    var tests = [];
    if (conf_.exit === false && exitInterval) clearInterval(exitInterval);

    exitInterval = !exitInterval && conf_.exit !== false && canEmitExit
    && typeof process._getActiveHandles === 'function'
    && setInterval(function () {
        if (process._getActiveHandles().length === 1) {
            tests.forEach(function (t) { t._exit() });
        }
    }, 200);

    var exitCode = 0;
    var exit = function (c) { exitCode = c };

    out.on('end', function () {
        clearInterval(exitInterval);
        if (conf_.exit !== false) process.exit(exitCode);
    });

    var test = function (name, conf, cb) {
        count++;
        var t = new Test(name, conf, cb);
        tests.push(t);
        if (!conf || typeof conf !== 'object') conf = conf_;

        if (conf.exit !== false) {
            onexit(function (code) {
                t._exit();
                if (!closed) {
                    closed = true
                    out.close();
                }
                if (!code && !t._ok && (!only || name === only)) {
                    exit(1);
                }
            });
        }

        process.nextTick(function () {
            if (!out.piped) out.pipe(createDefaultStream());
            if (!began) out.begin();
            began = true;

            var run = function () {
                running = true;
                out.push(t);
                t.run();
            };

            if (only && name !== only) {
                count--;
                return;
            }

            if (running || pending.length) {
                pending.push(run);
            }
            else run();
        });

        t.on('test', function sub (st) {
            count++;
            st.on('test', sub);
            st.on('end', onend);
        });
        t.on('result', function (r) { if (!r.ok) exitCode = 1 });

        t.on('end', onend);

        return t;

        function onend () {
            count--;
            if (this._progeny.length) {
                var unshifts = this._progeny.map(function (st) {
                    return function () {
                        running = true;
                        out.push(st);
                        st.run();
                    };
                });
                pending.unshift.apply(pending, unshifts);
            }

            process.nextTick(function () {
                running = false;
                if (pending.length) return pending.shift()();
                if (count === 0 && !closed) {
                    closed = true
                    out.close();
                }
                if (conf.exit !== false && canExit && !t._ok) {
                    exit(1);
                }
            });
        }
    };

    test.only = function (name) {
        if (only) {
            throw new Error("there can only be one only test");
        }

        only = name;

        return test.apply(null, arguments);
    };

    test.stream = out;
    return test;
}

// vim: set softtabstop=4 shiftwidth=4:
<commit_msg>guard process.exit() with a canExit for browsers<commit_after>var createDefaultStream = require('./lib/default_stream');
var Render = require('./lib/render');
var Test = require('./lib/test');

var canEmitExit = typeof process !== 'undefined' && process
    && typeof process.on === 'function'
;
var canExit = typeof process !== 'undefined' && process
    && typeof process.exit === 'function'
;
var onexit = (function () {
    var stack = [];
    if (canEmitExit) process.on('exit', function (code) {
        for (var i = 0; i < stack.length; i++) stack[i](code);
    });
    return function (cb) { stack.push(cb) };
})();

exports = module.exports = createHarness();
exports.createHarness = createHarness;
exports.Test = Test;

var exitInterval;

function createHarness (conf_) {
    var pending = [];
    var running = false;
    var count = 0;

    var began = false;
    var only = false;
    var closed = false;
    var out = new Render();
    if (!conf_) conf_ = {};

    var tests = [];
    if (conf_.exit === false && exitInterval) clearInterval(exitInterval);

    exitInterval = !exitInterval && conf_.exit !== false && canEmitExit
    && typeof process._getActiveHandles === 'function'
    && setInterval(function () {
        if (process._getActiveHandles().length === 1) {
            tests.forEach(function (t) { t._exit() });
        }
    }, 200);

    var exitCode = 0;
    var exit = function (c) { exitCode = c };

    out.on('end', function () {
        clearInterval(exitInterval);
        if (canExit && conf_.exit !== false) process.exit(exitCode);
    });

    var test = function (name, conf, cb) {
        count++;
        var t = new Test(name, conf, cb);
        tests.push(t);
        if (!conf || typeof conf !== 'object') conf = conf_;

        if (conf.exit !== false) {
            onexit(function (code) {
                t._exit();
                if (!closed) {
                    closed = true
                    out.close();
                }
                if (!code && !t._ok && (!only || name === only)) {
                    exit(1);
                }
            });
        }

        process.nextTick(function () {
            if (!out.piped) out.pipe(createDefaultStream());
            if (!began) out.begin();
            began = true;

            var run = function () {
                running = true;
                out.push(t);
                t.run();
            };

            if (only && name !== only) {
                count--;
                return;
            }

            if (running || pending.length) {
                pending.push(run);
            }
            else run();
        });

        t.on('test', function sub (st) {
            count++;
            st.on('test', sub);
            st.on('end', onend);
        });
        t.on('result', function (r) { if (!r.ok) exitCode = 1 });

        t.on('end', onend);

        return t;

        function onend () {
            count--;
            if (this._progeny.length) {
                var unshifts = this._progeny.map(function (st) {
                    return function () {
                        running = true;
                        out.push(st);
                        st.run();
                    };
                });
                pending.unshift.apply(pending, unshifts);
            }

            process.nextTick(function () {
                running = false;
                if (pending.length) return pending.shift()();
                if (count === 0 && !closed) {
                    closed = true
                    out.close();
                }
                if (conf.exit !== false && canExit && !t._ok) {
                    exit(1);
                }
            });
        }
    };

    test.only = function (name) {
        if (only) {
            throw new Error("there can only be one only test");
        }

        only = name;

        return test.apply(null, arguments);
    };

    test.stream = out;
    return test;
}

// vim: set softtabstop=4 shiftwidth=4:
<|endoftext|>


<commit_before>$(document).ready(function() {
  $(".button-collapse").sideNav();
  $('.parallax').parallax();
  $('ul.tabs').tabs('select_tab', 'tab_id');
  $(".dropdown-button").dropdown({
    belowOrigin: true, // displays dropdown below the button
    hover: true,
    inDuration: 300,
    outDuration: 225,
    gutter: 0 // spacing from edge
  });
  $('select').material_select();
});
<commit_msg>modified script file<commit_after>jQuery(document).ready(($) => {
  $('.button-collapse').sideNav();
  $('.parallax').parallax();
  $('ul.tabs').tabs('select_tab', 'tab_id');
  $('.dropdown-button').dropdown({
    belowOrigin: true, // displays dropdown below the button
    hover: true,
    inDuration: 300,
    outDuration: 225,
    gutter: 0 // spacing from edge
  });
  $('select').material_select();
});
<|endoftext|>


<commit_before>import React, {Component} from 'react'
import config from '../../../config/config'
import t from 't-component'
import bus from 'bus'

export default class UserBadge extends Component {
  constructor (props) {
    super(props)
    this.state = {
      menuUserBadge: false,
      canChangeTopics: false
    }
  }

  componentDidMount() {
    console.log('componentDidMount >>> setChangeTopicsPermission')
    bus.on('forum:change', this.setChangeTopicsPermission.bind(this))
  }

  componentWillUnmount() {
    console.log('componentWillUnmount >>> setChangeTopicsPermission')
    bus.off('forum:change', this.setChangeTopicsPermission.bind(this))
  }

  setChangeTopicsPermission (forum) {
    this.setState({canChangeTopics: (forum && forum.privileges.canChangeTopics)})
  }

  toggleMenu (e) {
    e.preventDefault()
    e.stopPropagation()
    this.setState({menuUserBadge: !this.state.menuUserBadge})
  }

  render () {
    var menuItemAdmin
    if (config.multiForum && this.props.user.privileges && this.props.user.privileges.canManage) {
      menuItemAdmin = (

          {t('header.forums')}

      )
    } else {
      menuItemAdmin = (

          {t('header.admin')}

      )
    }

    var classes = 'user-badge pull-right' +
      (this.state.menuUserBadge ? ' active' : '') +
      (this.state.canChangeTopics ? ' can-change-forum' : '')

    return (

              {this.props.user.firstName}

              {menuItemAdmin}

                {t('notifications.title')}

                {t('header.settings')}

              {config.frequentlyAskedQuestions &&
{t('help.faq.title')}
}
              {config.termsOfService &&
{t('help.tos.title')}
}
              {config.privacyPolicy &&
{t('help.pp.title')}
}
              {config.glossary &&
{t('help.glossary.title')}
}

                {t('header.logout')}

    )
  }
}
<commit_msg>close user menu on click out<commit_after>import React, {Component} from 'react'
import config from '../../../config/config'
import t from 't-component'
import bus from 'bus'

export default class UserBadge extends Component {
  constructor (props) {
    super(props)
    this.state = {
      menuUserBadge: false,
      canChangeTopics: false
    }
  }

  componentDidMount() {
    document.body.addEventListener('click', this.closeMenuClickOut.bind(this))
    bus.on('forum:change', this.setChangeTopicsPermission.bind(this))
  }

  componentWillUnmount() {
    document.body.addEventListener('click', this.closeMenuClickOut.bind(this))
    bus.off('forum:change', this.setChangeTopicsPermission.bind(this))
  }

  setChangeTopicsPermission (forum) {
    this.setState({canChangeTopics: (forum && forum.privileges.canChangeTopics)})
  }

  toggleMenu (e) {
    e.preventDefault()
    e.stopPropagation()
    this.setState({menuUserBadge: !this.state.menuUserBadge})
  }

  closeMenuClickOut () {
    if (!this.state.menuUserBadge) return
    this.setState({menuUserBadge: false})
  }

  render () {
    var menuItemAdmin
    if (config.multiForum && this.props.user.privileges && this.props.user.privileges.canManage) {
      menuItemAdmin = (

          {t('header.forums')}

      )
    } else {
      menuItemAdmin = (

          {t('header.admin')}

      )
    }

    var classes = 'user-badge pull-right' +
      (this.state.menuUserBadge ? ' active' : '') +
      (this.state.canChangeTopics ? ' can-change-forum' : '')

    return (

              {this.props.user.firstName}

              {menuItemAdmin}

                {t('notifications.title')}

                {t('header.settings')}

              {config.frequentlyAskedQuestions &&
{t('help.faq.title')}
}
              {config.termsOfService &&
{t('help.tos.title')}
}
              {config.privacyPolicy &&
{t('help.pp.title')}
}
              {config.glossary &&
{t('help.glossary.title')}
}

                {t('header.logout')}

    )
  }
}
<|endoftext|>


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

"use strict";

const moment = require("moment");
const sugar = require("sugar");
const chalk = require("chalk");
const { exec } = require("child_process");

const examples = [
  "2010",
  "Tuesday May 25th, 2010",
  "the day after tomorrow",
  "now",
  "next friday",
  "12pm",
  "a second ago",
  "three days ago",
  "last year"
];

/**
 * Ensure that there is at least one argument.
 */
process.argv.splice(0, 2);
if (!process.argv.length) {
  exit();
}

/**
 * Check if the date can be parsed.
 */
const date = process.argv.join(" ");
const parsedDate = new sugar.Date.create(date);
if (/Invalid Date/.test(parsedDate))
  exit(`Could not parse "${date}" into a valid date`);

/**
 * Create and execute the command to rewrite git date history.
 */
const dateString = moment(parsedDate).format("ddd MMM DD HH:mm:ss YYYY ZZ");
const command = `GIT_COMMITTER_DATE="${dateString}" git commit --amend --date="${dateString}" --no-edit`;

exec(command, (err, stdout, stderr) => {
  if (err || stderr) exit("Could not modify the date of the previous commit");

  console.log(
    chalk`\nModified previous commit:\n    AUTHOR_DATE    {grey ${dateString}}\n    COMMITTER_DATE {grey ${dateString}}\n\nCommand executed:\n    {grey ${command}}\n`
  );
});

/**
 * Handle any exit or error for the application.
 */
function exit(err) {
  if (err) console.log(chalk`{red error: ${err}}`);

  console.log("usage: git date <date string>\n\nExamples of valid commands:");
  examples.forEach(example => console.log(`    git date ${example}`));
  console.log();

  process.exit(1);
}
<commit_msg>Use more readable colours<commit_after>#!/usr/bin/env node

"use strict";

const moment = require("moment");
const sugar = require("sugar");
const chalk = require("chalk");
const { exec } = require("child_process");

const examples = [
  "2010",
  "Tuesday May 25th, 2010",
  "the day after tomorrow",
  "now",
  "next friday",
  "12pm",
  "a second ago",
  "three days ago",
  "last year"
];

/**
 * Ensure that there is at least one argument.
 */
process.argv.splice(0, 2);
if (!process.argv.length) {
  exit();
}

/**
 * Check if the date can be parsed.
 */
const date = process.argv.join(" ");
const parsedDate = new sugar.Date.create(date);
if (/Invalid Date/.test(parsedDate))
  exit(`Could not parse "${date}" into a valid date`);

/**
 * Create and execute the command to rewrite git date history.
 */
const dateString = moment(parsedDate).format("ddd MMM DD HH:mm:ss YYYY ZZ");
const command = `GIT_COMMITTER_DATE="${dateString}" git commit --amend --date="${dateString}" --no-edit`;

exec(command, (err, stdout, stderr) => {
  if (err || stderr) exit("Could not modify the date of the previous commit");

  console.log(
    chalk`\nModified previous commit:\n    AUTHOR_DATE    {green ${dateString}}\n    COMMITTER_DATE {green ${dateString}}\n\nCommand executed:\n    {blue ${command}}\n`
  );
});

/**
 * Handle any exit or error for the application.
 */
function exit(err) {
  if (err) console.log(chalk`{red error: ${err}}`);

  console.log("usage: git date <date string>\n\nExamples of valid commands:");
  examples.forEach(example => console.log(`    git date ${example}`));
  console.log();

  process.exit(1);
}
<|endoftext|>


<commit_before>var absync;
(function( _absync, undefined ) {
	"use strict";

	var absyncModule;

	try {
		absyncModule = angular.module( "absync" );
	} catch( ignored ) {
		absyncModule = angular.module( "absync", [] );
	}

	absyncModule.provider( "absync", function() {
		var absyncProvider = this;
		var ioSocket;
		// If socket.io was not connected when a service was constructed, we put the registration request
		// into this array and register it as soon as socket.io is configured.
		var registerLater = [];

		function configure( configuration ) {
			var socket = configuration.socket || configuration;
			if( typeof socket == "function" ) {
				// Assume io
				ioSocket = socket();

			} else if( io && io.Socket && socket instanceof io.Socket ) {
				// Assume io.Socket
				ioSocket = socket;
			} else {
				throw new Error( "configure() expects input to be a function or a socket.io Socket instance." );
			}

			if( registerLater.length ) {
				angular.forEach( registerLater, function registerListener( listener ) {
					handleEntityEvent( listener.eventName, listener.callback, listener.rootScope );
				} );
			}
		}

		function handleEntityEvent( eventName, callback, rootScope ) {
			var wrapper = function() {
				var args = arguments;
				rootScope.$apply( function() {
					callback.apply( ioSocket, args );
				} );
			};
			ioSocket.on( eventName, wrapper );
			return function() {
				ioSocket.removeListener( eventName, wrapper );
			};
		}

		// Register on the provider itself to allow early configuration during setup phase.
		absyncProvider.configure = configure;

		absyncProvider.$get = function( $rootScope ) {
			return {
				configure : configure,
				on        : function( eventName, callback ) {
					if( !ioSocket ) {
						registerLater.push( { eventName : eventName, callback : callback, rootScope : $rootScope } );
						return;
					}

					handleEntityEvent( eventName, callback, $rootScope );
				},
				emit      : function( eventName, data, callback ) {
					if( !ioSocket ) {
						throw new Error( "socket.io is not initialized." );
					}

					ioSocket.emit( eventName, data, function() {
						var args = arguments;
						$rootScope.$apply( function() {
							if( callback ) {
								callback.apply( ioSocket, args );
							}
						} );
					} );
				}
			};
		};
		absyncProvider.$get.$inject = [ "$rootScope" ];
	} );

	/**
	 * Constructs a new caching module for a certain entity and the collection thereof.
	 * The result will be an Angular service which caches the collection and makes sure it stays in sync with the backend.
	 * The collection name and entity name must be used in the whole codebase when referring to these entities and the collection.
	 * For example, for the "person" record, the module would listen for "person" events broadcasted on the root scope. It will expect those messages
	 * to include a Person instance which should be put into the cache.
	 * @param {String} collectionName The name of the data collection. This will also be the name of the generated Angular service.
	 * When an API endpoint returns the connected collection, the returned JSON object is expected to contain the collection within a member of this name.
	 * @param {String} entityName The name of a single entity inside the collection.
	 * When an API endpoint returns a member of the collection, the returned JSON object is expected to contain the entity within a member of this name.
	 * @param {String} entityUri The URI from which a single entity of the collection can be retrieved.
	 * @param {String} collectionUri The URI from which the collection can be retrieved.
	 * @param {Function} [fromJson] A function that can convert a JSON instance of one member of the collection into a proper object.
	 */
	_absync.CacheServiceFactory = function cache( collectionName, entityName, collectionUri, entityUri, fromJson ) {

		var builder = {};

		if( !fromJson ) {
			fromJson = function( instance ) {
				return instance;
			}
		}

		builder.assemble = function( then, inModule ) {
			inModule = inModule || "absync";
			angular.module( inModule )
				.factory(
				collectionName,
				[ "$q", "$rootScope", "$http", "$log", "absync",
					function( $q, $rootScope, $http, $log, absync ) {
						var cacheService = this;

						cacheService.name = collectionName;

						cacheService.entityCache = [];
						cacheService.entityCacheRaw = null;

						cacheService.dataAvailableDeferred = cacheService.dataAvailableDeferred || $q.defer();
						cacheService.objectsAvailableDeferred = cacheService.objectsAvailableDeferred || $q.defer();
						cacheService.dataAvailable = cacheService.dataAvailableDeferred.promise;
						cacheService.objectsAvailable = cacheService.objectsAvailableDeferred.promise;

						cacheService.ensureLoaded = function() {
							if( null === cacheService.entityCacheRaw ) {
						cacheService.httpInterface = $http;
								cacheService.entityCacheRaw = [];

								$log.info( "Retrieving '" + collectionName + "' collection…" );
								cacheService.httpInterface.get( collectionUri )
									.then( function( peopleResult ) {
										cacheService.entityCacheRaw = peopleResult.data;
										cacheService.dataAvailableDeferred.resolve( peopleResult.data );
									},
									function( error ) {
										$rootScope.$emit( "authorizationError", error );
									} );
							}

							return $q.all( [ cacheService.dataAvailable,
								cacheService.objectsAvailable ] );
						};
						cacheService.ensureLoaded();

						cacheService.dataAvailable
							.then( function( rawData ) {
								cacheService.entityCache = cacheService.entityCache || [];
								rawData[ collectionName ].forEach( function( rawEntity ) {
									cacheService.entityCache.push( fromJson( rawEntity ) );
								} );
								cacheService.objectsAvailableDeferred.resolve( cacheService.entityCache );
								$rootScope.$broadcast( "collectionNew", {
									service : cacheService,
									cache   : cacheService.entityCache
								} );
							} );

						/**
						 * Read a single entity from the cache, or load it from the server if required.
						 * @param {String} id The ID of the entity to retrieve.
						 * @returns {adapter.deferred.promise|*|defer.promise|eventObject.promise|promise|Q.promise}
						 */
						cacheService.read = function( id ) {
							var deferred = $q.defer();

							cacheService.ensureLoaded()
								.then( function() {
									// Check if the entity is in the cache and return instantly if found.
									for( var entityIndex = 0, entity = cacheService.entityCache[ 0 ], cacheSize = cacheService.entityCache.length;
									     entityIndex < cacheSize;
									     ++entityIndex, entity = cacheService.entityCache[ entityIndex ] ) {
										if( entity.id == id ) {
											deferred.resolve( entity );
											return;
										}
									}

									// Grab the entity from the backend.
									cacheService.httpInterface.get( entityUri + "/" + id ).success(
										function( data ) {
											if( !data[ entityName ] ) {
												deferred.reject( new Error( "The requested entity could not be found in the database." ) );
												return;
											}

											var entity = fromJson( data[ entityName ] );
											updateCacheWithEntity( entity );
											deferred.resolve( entity );
										}
									);
								} );

							return deferred.promise;
						};

						/**
						 * Updates an entity and persists it to the backend and the cache.
						 * @param {Object} entity
						 */
						cacheService.update = function( entity ) {
							var promise;

							// Wrap entity in a new object, with a single property, named after the entity type.
							var wrapper = {};
							wrapper[ entityName ] = entity;

							if( "undefined" !== typeof( entity.id ) ) {
								promise = cacheService.httpInterface.put( entityUri + "/" + entity.id, wrapper );
								promise
									.then( function( result ) {
										// Writing an entity to the backend will usually invoke an update event to be
										// broadcast over websockets, where would also retrieve the updated record.
										// We still put the updated record we receive here into the cache to ensure early consistency.
										if( result.data[ entityName ] ) {
											var newEntity = fromJson( result.data[ entityName ] );
											updateCacheWithEntity( newEntity );
										}
									},
									function( error ) {
										$log.error( error );
									} );

							} else {
								// Create a new entity
								promise = cacheService.httpInterface.post( collectionUri, wrapper );
								promise
									.then( function( result ) {
										// Writing an entity to the backend will usually invoke an update event to be
										// broadcast over websockets, where would also retrieve the updated record.
										// We still put the updated record we receive here into the cache to ensure early consistency.
										if( result.data[ entityName ] ) {
											var newEntity = fromJson( result.data[ entityName ] );
											updateCacheWithEntity( newEntity );
										}
									},
									function( error ) {
										$log.error( error );
									} );
							}

							return promise;
						};

						/**
						 * Creates a new entity and persists it to the backend and the cache.
						 */
						cacheService.create = cacheService.update;

						/**
						 * Remove an entity from the cache and have it deleted on the backend.
						 * @param {Object} entity
						 */
						cacheService.delete = function( entity ) {
							var deferred = $q.defer();

							var entityId = entity.id;
							cacheService.httpInterface.delete( entityUri + "/" + entityId )
								.success( function( data, status, headers, config ) {
									removeEntityFromCache( entityId );
									deferred.resolve();
								} )
								.error( function( data, status, headers, config ) {
									$log.error( data );
									deferred.reject( new Error( "Unable to delete entity." ) );
								} );

							return deferred.promise;
						};

						/**
						 * Put an entity into the cache or update the existing record if the entity was already in the cache.
						 * @param {Object} entityToCache
						 */
						function updateCacheWithEntity( entityToCache ) {
							$log.info( "Updating entity in cache..." );
							var found = false;
							for( var entityIndex = 0, entity = cacheService.entityCache[ 0 ], cacheSize = cacheService.entityCache.length;
							     entityIndex < cacheSize;
							     ++entityIndex, entity = cacheService.entityCache[ entityIndex ] ) {
								if( entity.id == entityToCache.id ) {
									$rootScope.$broadcast( "beforeEntityUpdated",
										{
											service : cacheService,
											cache   : cacheService.entityCache,
											entity  : cacheService.entityCache[ entityIndex ],
											updated : entityToCache
										} );
									// Use the "copyFrom" method on the entity, if it exists, otherwise use naive approach.
									var targetEntity = cacheService.entityCache[ entityIndex ];
									if( targetEntity.copyFrom ) {
										targetEntity.copyFrom( entityToCache );
									} else {
										angular.extend( targetEntity, entityToCache );
									}

									found = true;
									$rootScope.$broadcast( "entityUpdated",
										{
											service : cacheService,
											cache   : cacheService.entityCache,
											entity  : cacheService.entityCache[ entityIndex ]
										} );
									break;
								}
							}

							// If the entity wasn't found in our records, it's a new entity.
							if( !found ) {
								cacheService.entityCache.push( entityToCache );
								$rootScope.$broadcast( "entityNew", {
									service : cacheService,
									cache   : cacheService.entityCache,
									entity  : entityToCache
								} );
							}
						}

						/**
						 * Removes an entity from the internal cache. The entity is not removed from the backend.
						 * @param {String} id The ID of the entity to remove from the cache.
						 */
						function removeEntityFromCache( id ) {
							for( var entityIndex = 0, entity = cacheService.entityCache[ 0 ], cacheSize = cacheService.entityCache.length;
							     entityIndex < cacheSize;
							     ++entityIndex, entity = cacheService.entityCache[ entityIndex ] ) {
								if( entity.id == id ) {
									$rootScope.$broadcast( "beforeEntityRemoved", {
										service : cacheService,
										cache   : cacheService.entityCache,
										entity  : entity
									} );
									cacheService.entityCache.splice( entityIndex, 1 );
									$rootScope.$broadcast( "entityRemoved", {
										service : cacheService,
										cache   : cacheService.entityCache,
										entity  : entity
									} );
									break;
								}
							}
						}

						/**
						 * Retrieve an associative array of all cached entities, which uses the ID of the entity records as the key in the array.
						 * @returns {Array}
						 */
						cacheService.lookupTableById = function() {
							//TODO: Keep a copy of the lookup table and only update it when the cached data updates
							var lookupTable = [];
							for( var entityIndex = 0, cacheSize = cacheService.entityCache.length; entityIndex < cacheSize; ++entityIndex ) {
								lookupTable[ cacheService.entityCache[ entityIndex ].id ] = cacheService.entityCache[ entityIndex ];
							}
							return lookupTable;
						};

						// Listen for entity broadcasts. These are sent when a record is received through a websocket.
						cacheService.ensureLoaded().then( function() {
							$rootScope.$on( entityName, function( event, args ) {

								var entityReceived = args;

								// Determine if the received record consists ONLY of an id property,
								// which would mean that this record was deleted from the backend.
								if( 1 == Object.keys( entityReceived ).length && entityReceived.hasOwnProperty( "id" ) ) {
									$log.info( "Entity was deleted from the server. Updating cache..." );
									removeEntityFromCache( entityReceived.id );
								} else {
									updateCacheWithEntity( fromJson( entityReceived ) );
								}
							} );
						} );

						absync.on( entityName, function( message ) {
							$rootScope.$broadcast( entityName, message[ entityName ] );
						} );

						if( then ) {
							// Use setTimeout to break possible dependency loops when "then" references the caching service that we just constructed.
							setTimeout( then );
						}

						return cacheService;
					}
				]
			);
		};

		return builder;
	};
}( absync || (absync = {}) ));
<commit_msg>[FEATURE] Allow ensureLoaded() to force reload<commit_after>var absync;
(function( _absync, undefined ) {
	"use strict";

	var absyncModule;

	try {
		absyncModule = angular.module( "absync" );
	} catch( ignored ) {
		absyncModule = angular.module( "absync", [] );
	}

	absyncModule.provider( "absync", function() {
		var absyncProvider = this;
		var ioSocket;
		// If socket.io was not connected when a service was constructed, we put the registration request
		// into this array and register it as soon as socket.io is configured.
		var registerLater = [];

		function configure( configuration ) {
			var socket = configuration.socket || configuration;
			if( typeof socket == "function" ) {
				// Assume io
				ioSocket = socket();

			} else if( io && io.Socket && socket instanceof io.Socket ) {
				// Assume io.Socket
				ioSocket = socket;
			} else {
				throw new Error( "configure() expects input to be a function or a socket.io Socket instance." );
			}

			if( registerLater.length ) {
				angular.forEach( registerLater, function registerListener( listener ) {
					handleEntityEvent( listener.eventName, listener.callback, listener.rootScope );
				} );
			}
		}

		function handleEntityEvent( eventName, callback, rootScope ) {
			var wrapper = function() {
				var args = arguments;
				rootScope.$apply( function() {
					callback.apply( ioSocket, args );
				} );
			};
			ioSocket.on( eventName, wrapper );
			return function() {
				ioSocket.removeListener( eventName, wrapper );
			};
		}

		// Register on the provider itself to allow early configuration during setup phase.
		absyncProvider.configure = configure;

		absyncProvider.$get = function( $rootScope ) {
			return {
				configure : configure,
				on        : function( eventName, callback ) {
					if( !ioSocket ) {
						registerLater.push( { eventName : eventName, callback : callback, rootScope : $rootScope } );
						return;
					}

					handleEntityEvent( eventName, callback, $rootScope );
				},
				emit      : function( eventName, data, callback ) {
					if( !ioSocket ) {
						throw new Error( "socket.io is not initialized." );
					}

					ioSocket.emit( eventName, data, function() {
						var args = arguments;
						$rootScope.$apply( function() {
							if( callback ) {
								callback.apply( ioSocket, args );
							}
						} );
					} );
				}
			};
		};
		absyncProvider.$get.$inject = [ "$rootScope" ];
	} );

	/**
	 * Constructs a new caching module for a certain entity and the collection thereof.
	 * The result will be an Angular service which caches the collection and makes sure it stays in sync with the backend.
	 * The collection name and entity name must be used in the whole codebase when referring to these entities and the collection.
	 * For example, for the "person" record, the module would listen for "person" events broadcasted on the root scope. It will expect those messages
	 * to include a Person instance which should be put into the cache.
	 * @param {String} collectionName The name of the data collection. This will also be the name of the generated Angular service.
	 * When an API endpoint returns the connected collection, the returned JSON object is expected to contain the collection within a member of this name.
	 * @param {String} entityName The name of a single entity inside the collection.
	 * When an API endpoint returns a member of the collection, the returned JSON object is expected to contain the entity within a member of this name.
	 * @param {String} entityUri The URI from which a single entity of the collection can be retrieved.
	 * @param {String} collectionUri The URI from which the collection can be retrieved.
	 * @param {Function} [fromJson] A function that can convert a JSON instance of one member of the collection into a proper object.
	 */
	_absync.CacheServiceFactory = function cache( collectionName, entityName, collectionUri, entityUri, fromJson ) {

		var builder = {};

		if( !fromJson ) {
			fromJson = function( instance ) {
				return instance;
			}
		}

		builder.assemble = function( then, inModule ) {
			inModule = inModule || "absync";
			angular.module( inModule )
				.factory(
				collectionName,
				[ "$q", "$rootScope", "$http", "$log", "absync",
					function( $q, $rootScope, $http, $log, absync ) {
						var cacheService = this;

						cacheService.name = collectionName;

						cacheService.entityCache = [];
						cacheService.entityCacheRaw = null;

						cacheService.dataAvailableDeferred = cacheService.dataAvailableDeferred || $q.defer();
						cacheService.objectsAvailableDeferred = cacheService.objectsAvailableDeferred || $q.defer();
						cacheService.dataAvailable = cacheService.dataAvailableDeferred.promise;
						cacheService.objectsAvailable = cacheService.objectsAvailableDeferred.promise;

						cacheService.httpInterface = $http;

						cacheService.ensureLoaded = function( forceReload ) {
							forceReload = (forceReload === true);
							if( null === cacheService.entityCacheRaw || forceReload ) {
								cacheService.entityCacheRaw = [];

								$log.info( "Retrieving '" + collectionName + "' collection…" );
								cacheService.httpInterface.get( collectionUri )
									.then( function( peopleResult ) {
										cacheService.entityCacheRaw = peopleResult.data;
										cacheService.dataAvailableDeferred.resolve( peopleResult.data );
									},
									function( error ) {
										cacheService.entityCacheRaw = null;
										$rootScope.$emit( "authorizationError", error );
									} );
							}

							return $q.all( [ cacheService.dataAvailable,
								cacheService.objectsAvailable ] );
						};
						cacheService.ensureLoaded();

						cacheService.dataAvailable
							.then( function( rawData ) {
								cacheService.entityCache = cacheService.entityCache || [];
								rawData[ collectionName ].forEach( function( rawEntity ) {
									cacheService.entityCache.push( fromJson( rawEntity ) );
								} );
								cacheService.objectsAvailableDeferred.resolve( cacheService.entityCache );
								$rootScope.$broadcast( "collectionNew", {
									service : cacheService,
									cache   : cacheService.entityCache
								} );
							} );

						/**
						 * Read a single entity from the cache, or load it from the server if required.
						 * @param {String} id The ID of the entity to retrieve.
						 * @returns {adapter.deferred.promise|*|defer.promise|eventObject.promise|promise|Q.promise}
						 */
						cacheService.read = function( id ) {
							var deferred = $q.defer();

							cacheService.ensureLoaded()
								.then( function() {
									// Check if the entity is in the cache and return instantly if found.
									for( var entityIndex = 0, entity = cacheService.entityCache[ 0 ], cacheSize = cacheService.entityCache.length;
									     entityIndex < cacheSize;
									     ++entityIndex, entity = cacheService.entityCache[ entityIndex ] ) {
										if( entity.id == id ) {
											deferred.resolve( entity );
											return;
										}
									}

									// Grab the entity from the backend.
									cacheService.httpInterface.get( entityUri + "/" + id ).success(
										function( data ) {
											if( !data[ entityName ] ) {
												deferred.reject( new Error( "The requested entity could not be found in the database." ) );
												return;
											}

											var entity = fromJson( data[ entityName ] );
											updateCacheWithEntity( entity );
											deferred.resolve( entity );
										}
									);
								} );

							return deferred.promise;
						};

						/**
						 * Updates an entity and persists it to the backend and the cache.
						 * @param {Object} entity
						 */
						cacheService.update = function( entity ) {
							var promise;

							// Wrap entity in a new object, with a single property, named after the entity type.
							var wrapper = {};
							wrapper[ entityName ] = entity;

							if( "undefined" !== typeof( entity.id ) ) {
								promise = cacheService.httpInterface.put( entityUri + "/" + entity.id, wrapper );
								promise
									.then( function( result ) {
										// Writing an entity to the backend will usually invoke an update event to be
										// broadcast over websockets, where would also retrieve the updated record.
										// We still put the updated record we receive here into the cache to ensure early consistency.
										if( result.data[ entityName ] ) {
											var newEntity = fromJson( result.data[ entityName ] );
											updateCacheWithEntity( newEntity );
										}
									},
									function( error ) {
										$log.error( error );
									} );

							} else {
								// Create a new entity
								promise = cacheService.httpInterface.post( collectionUri, wrapper );
								promise
									.then( function( result ) {
										// Writing an entity to the backend will usually invoke an update event to be
										// broadcast over websockets, where would also retrieve the updated record.
										// We still put the updated record we receive here into the cache to ensure early consistency.
										if( result.data[ entityName ] ) {
											var newEntity = fromJson( result.data[ entityName ] );
											updateCacheWithEntity( newEntity );
										}
									},
									function( error ) {
										$log.error( error );
									} );
							}

							return promise;
						};

						/**
						 * Creates a new entity and persists it to the backend and the cache.
						 */
						cacheService.create = cacheService.update;

						/**
						 * Remove an entity from the cache and have it deleted on the backend.
						 * @param {Object} entity
						 */
						cacheService.delete = function( entity ) {
							var deferred = $q.defer();

							var entityId = entity.id;
							cacheService.httpInterface.delete( entityUri + "/" + entityId )
								.success( function( data, status, headers, config ) {
									removeEntityFromCache( entityId );
									deferred.resolve();
								} )
								.error( function( data, status, headers, config ) {
									$log.error( data );
									deferred.reject( new Error( "Unable to delete entity." ) );
								} );

							return deferred.promise;
						};

						/**
						 * Put an entity into the cache or update the existing record if the entity was already in the cache.
						 * @param {Object} entityToCache
						 */
						function updateCacheWithEntity( entityToCache ) {
							$log.info( "Updating entity in cache..." );
							var found = false;
							for( var entityIndex = 0, entity = cacheService.entityCache[ 0 ], cacheSize = cacheService.entityCache.length;
							     entityIndex < cacheSize;
							     ++entityIndex, entity = cacheService.entityCache[ entityIndex ] ) {
								if( entity.id == entityToCache.id ) {
									$rootScope.$broadcast( "beforeEntityUpdated",
										{
											service : cacheService,
											cache   : cacheService.entityCache,
											entity  : cacheService.entityCache[ entityIndex ],
											updated : entityToCache
										} );
									// Use the "copyFrom" method on the entity, if it exists, otherwise use naive approach.
									var targetEntity = cacheService.entityCache[ entityIndex ];
									if( targetEntity.copyFrom ) {
										targetEntity.copyFrom( entityToCache );
									} else {
										angular.extend( targetEntity, entityToCache );
									}

									found = true;
									$rootScope.$broadcast( "entityUpdated",
										{
											service : cacheService,
											cache   : cacheService.entityCache,
											entity  : cacheService.entityCache[ entityIndex ]
										} );
									break;
								}
							}

							// If the entity wasn't found in our records, it's a new entity.
							if( !found ) {
								cacheService.entityCache.push( entityToCache );
								$rootScope.$broadcast( "entityNew", {
									service : cacheService,
									cache   : cacheService.entityCache,
									entity  : entityToCache
								} );
							}
						}

						/**
						 * Removes an entity from the internal cache. The entity is not removed from the backend.
						 * @param {String} id The ID of the entity to remove from the cache.
						 */
						function removeEntityFromCache( id ) {
							for( var entityIndex = 0, entity = cacheService.entityCache[ 0 ], cacheSize = cacheService.entityCache.length;
							     entityIndex < cacheSize;
							     ++entityIndex, entity = cacheService.entityCache[ entityIndex ] ) {
								if( entity.id == id ) {
									$rootScope.$broadcast( "beforeEntityRemoved", {
										service : cacheService,
										cache   : cacheService.entityCache,
										entity  : entity
									} );
									cacheService.entityCache.splice( entityIndex, 1 );
									$rootScope.$broadcast( "entityRemoved", {
										service : cacheService,
										cache   : cacheService.entityCache,
										entity  : entity
									} );
									break;
								}
							}
						}

						/**
						 * Retrieve an associative array of all cached entities, which uses the ID of the entity records as the key in the array.
						 * @returns {Array}
						 */
						cacheService.lookupTableById = function() {
							//TODO: Keep a copy of the lookup table and only update it when the cached data updates
							var lookupTable = [];
							for( var entityIndex = 0, cacheSize = cacheService.entityCache.length; entityIndex < cacheSize; ++entityIndex ) {
								lookupTable[ cacheService.entityCache[ entityIndex ].id ] = cacheService.entityCache[ entityIndex ];
							}
							return lookupTable;
						};

						// Listen for entity broadcasts. These are sent when a record is received through a websocket.
						cacheService.ensureLoaded().then( function() {
							$rootScope.$on( entityName, function( event, args ) {

								var entityReceived = args;

								// Determine if the received record consists ONLY of an id property,
								// which would mean that this record was deleted from the backend.
								if( 1 == Object.keys( entityReceived ).length && entityReceived.hasOwnProperty( "id" ) ) {
									$log.info( "Entity was deleted from the server. Updating cache..." );
									removeEntityFromCache( entityReceived.id );
								} else {
									updateCacheWithEntity( fromJson( entityReceived ) );
								}
							} );
						} );

						absync.on( entityName, function( message ) {
							$rootScope.$broadcast( entityName, message[ entityName ] );
						} );

						if( then ) {
							// Use setTimeout to break possible dependency loops when "then" references the caching service that we just constructed.
							setTimeout( then );
						}

						return cacheService;
					}
				]
			);
		};

		return builder;
	};
}( absync || (absync = {}) ));
<|endoftext|>


<commit_before>require('./lib/util/patch');
var net = require('net');
var tls = require('tls');
var extend = require('extend');
var path = require('path');
var cluster = require('cluster');
var os = require('os');
var assert = require('assert');

var ver = process.version.substring(1).split('.');
var PROD_RE = /(^|\|)prod(uction)?($|\|)/;
var noop = function () {};
var state = {};
var INTERVAL = 1000;
var TIMEOUT = 10000;
var MASTER_TIMEOUT = 12000;

if (ver[0] >= 7 && ver[1] >= 7) {
  var connect = net.Socket.prototype.connect;
  if (typeof connect === 'function') {
    //fix: Node v7.7.0+引入的 `"listener" argument must be a function` 问题
    net.Socket.prototype.connect = function (options, cb) {
      if (options && typeof options === 'object' && typeof cb !== 'function') {
        return connect.call(this, options, null);
      }
      return connect.apply(this, arguments);
    };
  }
}

var env = process.env || '';
env.WHISTLE_ROOT = __dirname;
if (typeof tls.checkServerIdentity == 'function') {
  var checkServerIdentity = tls.checkServerIdentity;
  tls.checkServerIdentity = function () {
    try {
      return checkServerIdentity.apply(this, arguments);
    } catch (err) {
      return err;
    }
  };
}
if (env.WHISTLE_PLUGIN_EXEC_PATH) {
  env.PFORK_EXEC_PATH = env.WHISTLE_PLUGIN_EXEC_PATH;
}

function isPipeName(s) {
  return typeof s === 'string' && toNumber(s) === false;
}

function toNumber(x) {
  return (x = Number(x)) >= 0 ? x : false;
}

if (!net._normalizeConnectArgs) {
  //Returns an array [options] or [options, cb]
  //It is the same as the argument of Socket.prototype.connect().
  net._normalizeConnectArgs = function (args) {
    var options = {};

    if (args[0] !== null && typeof args[0] === 'object') {
      // connect(options, [cb])
      options = args[0];
    } else if (isPipeName(args[0])) {
      // connect(path, [cb]);
      options.path = args[0];
    } else {
      // connect(port, [host], [cb])
      options.port = args[0];
      if (typeof args[1] === 'string') {
        options.host = args[1];
      }
    }

    var cb = args[args.length - 1];
    return typeof cb === 'function' ? [options, cb] : [options];
  };
}

function loadConfig(options) {
  var config = options.config;
  if (config) {
    delete options.config;
    return require(path.resolve(config));
  }
}

function likePromise(p) {
  return p && typeof p.then === 'function' && typeof p.catch === 'function';
}

function killWorker(worker) {
  try {
    worker.removeAllListeners();
    worker.on('error', noop);
    worker.kill('SIGTERM');
  } catch (err) {}
}

function forkWorker(index) {
  var worker = cluster.fork({ workerIndex: index });
  var reforked;
  var refork = () => {
    if (!state[index]) {
      setTimeout(function () {
        process.exit(1);
      }, INTERVAL);
      return;
    }
    if (reforked) {
      return;
    }
    reforked = true;
    killWorker(worker);
    clearInterval(worker.timer);
    clearTimeout(worker.activeTimer);
    setTimeout(function () {
      forkWorker(index);
    }, 600);
  };
  worker.once('disconnect', refork);
  worker.once('exit', refork);
  worker.on('error', noop);
  worker.on('message', (msg) => {
    if (msg !== '1') {
      return;
    }
    state[index] = true;
    if (!worker.timer) {
      worker.timer = setInterval(() => {
        try {
          worker.send('1', noop);
        } catch (e) {
          clearInterval(worker.timer);
        }
      }, INTERVAL);
    } else {
      clearTimeout(worker.activeTimer);
    }
    worker.activeTimer = setTimeout(refork, MASTER_TIMEOUT);
  });
}

module.exports = function (options, callback) {
  if (typeof options === 'function') {
    callback = options;
    options = null;
  }
  var startWhistle = function (server) {
    var workerIndex = env.workerIndex;
    if (options && options.cluster && workerIndex >= 0) {
      options.storage =
        '.' +
        (options.storage || '') +
        '__cluster_worker.' +
        workerIndex +
        '_5b6af7b9884e1165__';
    }
    var conf = require('./lib/config').extend(options);
    if (!conf.cluster) {
      return require('./lib')(callback, server);
    }
    var timer;
    var activeTimeout = function () {
      clearTimeout(timer);
      timer = setTimeout(function () {
        process.exit(1);
      }, TIMEOUT);
    };
    process.once('SIGTERM', function () {
      process.exit(0);
    });

    require('./lib')(function () {
      activeTimeout();
      process.on('message', activeTimeout);
      process.send('1', noop);
      setInterval(() => {
        try {
          process.send('1', noop);
        } catch (e) {}
      }, INTERVAL);
    });
  };
  if (options) {
    if (/^\d+$/.test(options.cluster)) {
      options.cluster = Math.min(parseInt(options.cluster, 10), 999);
    } else if (options.cluster) {
      options.cluster = Math.min(os.cpus().length, 999);
    }
    if (options.cluster && cluster.isMaster) {
      assert(!options.server, 'cannot exist options.server in cluster mode');
      for (var i = 0; i < options.cluster; i++) {
        forkWorker(i);
      }
      return;
    }
    if (options.debugMode) {
      if (PROD_RE.test(options.mode)) {
        options.debugMode = false;
      } else {
        env.PFORK_MODE = 'bind';
      }
    }
    var config = loadConfig(options);
    if (typeof config === 'function') {
      var handleCallback = function (opts) {
        opts && extend(options, opts);
        return startWhistle(options.server);
      };
      if (config.length < 2) {
        config = config(options);
        if (likePromise(config)) {
          return config.then(handleCallback).catch(function (err) {
            process.nextTick(function () {
              throw err;
            });
          });
        }
      } else {
        config(options, handleCallback);
      }
    }
    config && extend(options, config);
  }
  return startWhistle(options.server);
};
<commit_msg>refactor: mandatory need to customize options.storage after setting options.server<commit_after>require('./lib/util/patch');
var net = require('net');
var tls = require('tls');
var extend = require('extend');
var path = require('path');
var cluster = require('cluster');
var os = require('os');
var assert = require('assert');

var ver = process.version.substring(1).split('.');
var PROD_RE = /(^|\|)prod(uction)?($|\|)/;
var noop = function () {};
var state = {};
var INTERVAL = 1000;
var TIMEOUT = 10000;
var MASTER_TIMEOUT = 12000;

if (ver[0] >= 7 && ver[1] >= 7) {
  var connect = net.Socket.prototype.connect;
  if (typeof connect === 'function') {
    //fix: Node v7.7.0+引入的 `"listener" argument must be a function` 问题
    net.Socket.prototype.connect = function (options, cb) {
      if (options && typeof options === 'object' && typeof cb !== 'function') {
        return connect.call(this, options, null);
      }
      return connect.apply(this, arguments);
    };
  }
}

var env = process.env || '';
env.WHISTLE_ROOT = __dirname;
if (typeof tls.checkServerIdentity == 'function') {
  var checkServerIdentity = tls.checkServerIdentity;
  tls.checkServerIdentity = function () {
    try {
      return checkServerIdentity.apply(this, arguments);
    } catch (err) {
      return err;
    }
  };
}
if (env.WHISTLE_PLUGIN_EXEC_PATH) {
  env.PFORK_EXEC_PATH = env.WHISTLE_PLUGIN_EXEC_PATH;
}

function isPipeName(s) {
  return typeof s === 'string' && toNumber(s) === false;
}

function toNumber(x) {
  return (x = Number(x)) >= 0 ? x : false;
}

if (!net._normalizeConnectArgs) {
  //Returns an array [options] or [options, cb]
  //It is the same as the argument of Socket.prototype.connect().
  net._normalizeConnectArgs = function (args) {
    var options = {};

    if (args[0] !== null && typeof args[0] === 'object') {
      // connect(options, [cb])
      options = args[0];
    } else if (isPipeName(args[0])) {
      // connect(path, [cb]);
      options.path = args[0];
    } else {
      // connect(port, [host], [cb])
      options.port = args[0];
      if (typeof args[1] === 'string') {
        options.host = args[1];
      }
    }

    var cb = args[args.length - 1];
    return typeof cb === 'function' ? [options, cb] : [options];
  };
}

function loadConfig(options) {
  var config = options.config;
  if (config) {
    delete options.config;
    return require(path.resolve(config));
  }
}

function likePromise(p) {
  return p && typeof p.then === 'function' && typeof p.catch === 'function';
}

function killWorker(worker) {
  try {
    worker.removeAllListeners();
    worker.on('error', noop);
    worker.kill('SIGTERM');
  } catch (err) {}
}

function forkWorker(index) {
  var worker = cluster.fork({ workerIndex: index });
  var reforked;
  var refork = () => {
    if (!state[index]) {
      setTimeout(function () {
        process.exit(1);
      }, INTERVAL);
      return;
    }
    if (reforked) {
      return;
    }
    reforked = true;
    killWorker(worker);
    clearInterval(worker.timer);
    clearTimeout(worker.activeTimer);
    setTimeout(function () {
      forkWorker(index);
    }, 600);
  };
  worker.once('disconnect', refork);
  worker.once('exit', refork);
  worker.on('error', noop);
  worker.on('message', (msg) => {
    if (msg !== '1') {
      return;
    }
    state[index] = true;
    if (!worker.timer) {
      worker.timer = setInterval(() => {
        try {
          worker.send('1', noop);
        } catch (e) {
          clearInterval(worker.timer);
        }
      }, INTERVAL);
    } else {
      clearTimeout(worker.activeTimer);
    }
    worker.activeTimer = setTimeout(refork, MASTER_TIMEOUT);
  });
}

module.exports = function (options, callback) {
  if (typeof options === 'function') {
    callback = options;
    options = null;
  }
  var startWhistle = function () {
    var server = options.server;
    assert(!server || options.storage, 'options.storage is required if options.server exists (you can use package.name as options.storage)');
    var workerIndex = env.workerIndex;
    if (options && options.cluster && workerIndex >= 0) {
      options.storage =
        '.' +
        (options.storage || '') +
        '__cluster_worker.' +
        workerIndex +
        '_5b6af7b9884e1165__';
    }
    var conf = require('./lib/config').extend(options);
    if (!conf.cluster) {
      return require('./lib')(callback, server);
    }
    var timer;
    var activeTimeout = function () {
      clearTimeout(timer);
      timer = setTimeout(function () {
        process.exit(1);
      }, TIMEOUT);
    };
    process.once('SIGTERM', function () {
      process.exit(0);
    });

    require('./lib')(function () {
      activeTimeout();
      process.on('message', activeTimeout);
      process.send('1', noop);
      setInterval(() => {
        try {
          process.send('1', noop);
        } catch (e) {}
      }, INTERVAL);
    });
  };
  if (options) {
    if (/^\d+$/.test(options.cluster)) {
      options.cluster = Math.min(parseInt(options.cluster, 10), 999);
    } else if (options.cluster) {
      options.cluster = Math.min(os.cpus().length, 999);
    }
    if (options.cluster && cluster.isMaster) {
      assert(!options.server, 'cannot exist options.server in cluster mode');
      for (var i = 0; i < options.cluster; i++) {
        forkWorker(i);
      }
      return;
    }
    if (options.debugMode) {
      if (PROD_RE.test(options.mode)) {
        options.debugMode = false;
      } else {
        env.PFORK_MODE = 'bind';
      }
    }
    var config = loadConfig(options);
    if (typeof config === 'function') {
      var handleCallback = function (opts) {
        opts && extend(options, opts);
        return startWhistle();
      };
      if (config.length < 2) {
        config = config(options);
        if (likePromise(config)) {
          return config.then(handleCallback).catch(function (err) {
            process.nextTick(function () {
              throw err;
            });
          });
        }
      } else {
        config(options, handleCallback);
      }
    }
    config && extend(options, config);
  }
  return startWhistle();
};
<|endoftext|>


<commit_before>var absync;
(function( _absync ) {
	"use strict";

	/**
	 * Constructs a new caching module for a certain entity and the collection thereof.
	 * The result will be an Angular service which caches the collection and makes sure it stays in sync with the backend.
	 * The collection name and entity name must be used in the whole codebase when referring to these entities and the collection.
	 * For example, for the "person" record, the module would listen for "person" events broadcasted on the root scope. It will expect those messages
	 * to include a Person instance which should be put into the cache.
	 * @param {String} collectionName The name of the data collection. This will also be the name of the generated Angular service.
	 * When an API endpoint returns the connected collection, the returned JSON object is expected to contain the collection within a member of this name.
	 * @param {String} entityName The name of a single entity inside the collection.
	 * When an API endpoint returns a member of the collection, the returned JSON object is expected to contain the entity within a member of this name.
	 * @param {String} entityUri The URI from which a single entity of the collection can be retrieved.
	 * @param {String} collectionUri The URI from which the collection can be retrieved.
	 * @param {Function} fromJson A function that can convert a JSON instance of one member of the collection into a proper object.
	 */
	_absync.CacheServiceFactory = function cache( collectionName, entityName, collectionUri, entityUri, fromJson ) {

		var builder = {};

		builder.assemble = function( then ) {
			angular.module( "fmServices" )
				.factory(
				collectionName,
				[ "$q", "$rootScope", "$http",
					function( $q, $rootScope, $http ) {
						var cacheService = this;

						cacheService.name = collectionName;

						cacheService.entityCache = null;
						cacheService.entityCacheRaw = null;

						cacheService.dataAvailableDeferred = cacheService.dataAvailableDeferred || $q.defer();
						cacheService.objectsAvailableDeferred = cacheService.objectsAvailableDeferred || $q.defer();
						cacheService.dataAvailable = cacheService.dataAvailableDeferred.promise;
						cacheService.objectsAvailable = cacheService.objectsAvailableDeferred.promise;

						cacheService.ensureLoaded = function() {
							if( null === cacheService.entityCacheRaw ) {
								cacheService.entityCacheRaw = [];

								console.log( "Retrieving '" + collectionName + "' collection…" );
								$http.get( collectionUri )
									.then( function( peopleResult ) {
										cacheService.entityCacheRaw = peopleResult.data;
										cacheService.dataAvailableDeferred.resolve( peopleResult.data );
									},
									function( error ) {
										$rootScope.$emit( "authorizationError", error );
									} );
							}

							return $q.all( [ cacheService.dataAvailable,
								cacheService.objectsAvailable ] );
						};
						cacheService.ensureLoaded();

						cacheService.dataAvailable
							.then( function( rawData ) {
								cacheService.entityCache = [];
								rawData[ collectionName ].forEach( function( rawEntity ) {
									cacheService.entityCache.push( fromJson( rawEntity ) );
								} );
								cacheService.objectsAvailableDeferred.resolve( cacheService.entityCache );
								$rootScope.$broadcast( "collectionNew", {
									service : cacheService,
									cache   : cacheService.entityCache
								} );
							} );

						/**
						 * Read a single entity from the cache, or load it from the server if required.
						 * @param {String} id The ID of the entity to retrieve.
						 * @returns {adapter.deferred.promise|*|defer.promise|eventObject.promise|promise|Q.promise}
						 */
						cacheService.read = function( id ) {
							var deferred = $q.defer();

							cacheService.ensureLoaded()
								.then( function() {
									// Check if the entity is in the cache and return instantly if found.
									for( var entityIndex = 0, entity = cacheService.entityCache[ 0 ], cacheSize = cacheService.entityCache.length;
									     entityIndex < cacheSize;
									     ++entityIndex, entity = cacheService.entityCache[ entityIndex ] ) {
										if( entity.id == id ) {
											deferred.resolve( entity );
											return;
										}
									}

									// Grab the entity from the backend.
									$http.get( entityUri + "/" + id ).success(
										function( data ) {
											if( !data[ entityName ] ) {
												deferred.reject( new Error( "The requested person could not be found in the database." ) );
												return;
											}

											var entity = fromJson( data[ entityName ] );
											updateCacheWithEntity( entity );
											deferred.resolve( entity );
										}
									);
								} );

							return deferred.promise;
						};

						/**
						 * Updates an entity and persists it to the backend and the cache.
						 * @param {Object} entity
						 */
						cacheService.update = function( entity ) {
							var promise;

							// Wrap entity in a new object, with a single property, named after the entity type.
							var wrapper = {};
							wrapper[ entityName ] = entity;

							if( "undefined" !== typeof( entity.id ) ) {
								promise = $http.put( entityUri + "/" + entity.id, wrapper );
								promise
									.then( function( result ) {
										// Writing a person to the backend will usually invoke an update event to be
										// broadcast over websockets, where would also retrieve the updated record.
										// We still put the updated record we receive here into the cache to ensure early consistency.
										if( result.data[ entityName ] ) {
											var newEntity = fromJson( result.data[ entityName ] );
											updateCacheWithEntity( newEntity );
										}
									},
									function( error ) {
										console.error( error );
									} );

							} else {
								// Create a new person
								promise = $http.post( collectionUri, wrapper );
								promise
									.then( function( result ) {
										// Writing a person to the backend will usually invoke an update event to be
										// broadcast over websockets, where would also retrieve the updated record.
										// We still put the updated record we receive here into the cache to ensure early consistency.
										if( result.data[ entityName ] ) {
											var newEntity = fromJson( result.data[ entityName ] );
											updateCacheWithEntity( newEntity );
										}
									},
									function( error ) {
										console.error( error );
									} );
							}

							return promise;
						};

						/**
						 * Creates a new entity and persists it to the backend and the cache.
						 */
						cacheService.create = cacheService.update;

						/**
						 * Remove an entity from the cache and have it deleted on the backend.
						 * @param {Object} entity
						 */
						cacheService.delete = function( entity ) {
							var deferred = $q.defer();

							var entityId = entity.id;
							$http.delete( entityUri + "/" + entityId )
								.success( function( data, status, headers, config ) {
									removeEntityFromCache( entityId );
									deferred.resolve();
								} )
								.error( function( data, status, headers, config ) {
									console.error( data );
									deferred.reject( new Error( "Unable to delete entity." ) );
								} );

							return deferred.promise;
						};

						/**
						 * Put an entity into the cache or update the existing record if the entity was already in the cache.
						 * @param {Object} entityToCache
						 */
						function updateCacheWithEntity( entityToCache ) {
							console.log( "Updating entity in cache..." );
							var found = false;
							for( var entityIndex = 0, entity = cacheService.entityCache[ 0 ], cacheSize = cacheService.entityCache.length;
							     entityIndex < cacheSize;
							     ++entityIndex, entity = cacheService.entityCache[ entityIndex ] ) {
								if( entity.id == entityToCache.id ) {
									$rootScope.$broadcast( "beforeEntityUpdated",
										{
											service : cacheService,
											cache   : cacheService.entityCache,
											entity  : cacheService.entityCache[ entityIndex ]
										} );
									cacheService.entityCache[ entityIndex ].copyFrom( entityToCache );
									found = true;
									$rootScope.$broadcast( "entityUpdated",
										{
											service : cacheService,
											cache   : cacheService.entityCache,
											entity  : cacheService.entityCache[ entityIndex ]
										} );
									break;
								}
							}

							// If the entity wasn't found in our records, it's a new entity.
							if( !found ) {
								cacheService.entityCache.push( entityToCache );
								$rootScope.$broadcast( "entityNew", {
									service : cacheService,
									cache   : cacheService.entityCache,
									entity  : entityToCache
								} );
							}
						}

						/**
						 * Removes an entity from the internal cache. The entity is not removed from the backend.
						 * @param {String} id The ID of the entity to remove from the cache.
						 */
						function removeEntityFromCache( id ) {
							for( var entityIndex = 0, entity = cacheService.entityCache[ 0 ], cacheSize = cacheService.entityCache.length;
							     entityIndex < cacheSize;
							     ++entityIndex, entity = cacheService.entityCache[ entityIndex ] ) {
								if( entity.id == id ) {
									$rootScope.$broadcast( "beforeEntityRemoved", {
										service : cacheService,
										cache   : cacheService.entityCache,
										entity  : entity
									} );
									cacheService.entityCache.splice( entityIndex, 1 );
									$rootScope.$broadcast( "entityRemoved", {
										service : cacheService,
										cache   : cacheService.entityCache,
										entity  : entity
									} );
									break;
								}
							}
						}

						/**
						 * Retrieve an associative array of all cached entities, which uses the ID of the entity records as the key in the array.
						 * @returns {Array}
						 */
						cacheService.lookupTableById = function() {
							//TODO: Keep a copy of the lookup table and only update it when the cached data updates
							var lookupTable = [];
							for( var entityIndex = 0, cacheSize = cacheService.entityCache.length; entityIndex < cacheSize; ++entityIndex ) {
								lookupTable[ cacheService.entityCache[ entityIndex ].id ] = cacheService.entityCache[ entityIndex ];
							}
							return lookupTable;
						};

						// Listen for person broadcasts. These are sent when a person record is received through a websocket.
						cacheService.ensureLoaded().then( function() {
							$rootScope.$on( entityName, function( event, args ) {

								var entityReceived = args;

								// Determine if the received record consists ONLY of an id property,
								// which would mean that this record was deleted from the backend.
								if( 1 == Object.keys( entityReceived ).length && entityReceived.hasOwnProperty( "id" ) ) {
									console.log( "Entity was deleted from the server. Updating cache..." );
									removeEntityFromCache( entityReceived.id );
								} else {
									updateCacheWithEntity( fromJson( entityReceived ) );
								}
							} );
						} );

						if( then ) {
							// Use setTimeout to break possible dependency loops when "then" references the caching service that we just constructed.
							setTimeout( then );
						}

						return cacheService;
					}
				]
			);
		};

		return builder;
	};
}( absync || (absync = {}) ));
<commit_msg>[TASK] Renamed module<commit_after>var absync;
(function( _absync ) {
	"use strict";

	/**
	 * Constructs a new caching module for a certain entity and the collection thereof.
	 * The result will be an Angular service which caches the collection and makes sure it stays in sync with the backend.
	 * The collection name and entity name must be used in the whole codebase when referring to these entities and the collection.
	 * For example, for the "person" record, the module would listen for "person" events broadcasted on the root scope. It will expect those messages
	 * to include a Person instance which should be put into the cache.
	 * @param {String} collectionName The name of the data collection. This will also be the name of the generated Angular service.
	 * When an API endpoint returns the connected collection, the returned JSON object is expected to contain the collection within a member of this name.
	 * @param {String} entityName The name of a single entity inside the collection.
	 * When an API endpoint returns a member of the collection, the returned JSON object is expected to contain the entity within a member of this name.
	 * @param {String} entityUri The URI from which a single entity of the collection can be retrieved.
	 * @param {String} collectionUri The URI from which the collection can be retrieved.
	 * @param {Function} fromJson A function that can convert a JSON instance of one member of the collection into a proper object.
	 */
	_absync.CacheServiceFactory = function cache( collectionName, entityName, collectionUri, entityUri, fromJson ) {

		var builder = {};

		builder.assemble = function( then ) {
			angular.module( "absync" )
				.factory(
				collectionName,
				[ "$q", "$rootScope", "$http",
					function( $q, $rootScope, $http ) {
						var cacheService = this;

						cacheService.name = collectionName;

						cacheService.entityCache = null;
						cacheService.entityCacheRaw = null;

						cacheService.dataAvailableDeferred = cacheService.dataAvailableDeferred || $q.defer();
						cacheService.objectsAvailableDeferred = cacheService.objectsAvailableDeferred || $q.defer();
						cacheService.dataAvailable = cacheService.dataAvailableDeferred.promise;
						cacheService.objectsAvailable = cacheService.objectsAvailableDeferred.promise;

						cacheService.ensureLoaded = function() {
							if( null === cacheService.entityCacheRaw ) {
								cacheService.entityCacheRaw = [];

								console.log( "Retrieving '" + collectionName + "' collection…" );
								$http.get( collectionUri )
									.then( function( peopleResult ) {
										cacheService.entityCacheRaw = peopleResult.data;
										cacheService.dataAvailableDeferred.resolve( peopleResult.data );
									},
									function( error ) {
										$rootScope.$emit( "authorizationError", error );
									} );
							}

							return $q.all( [ cacheService.dataAvailable,
								cacheService.objectsAvailable ] );
						};
						cacheService.ensureLoaded();

						cacheService.dataAvailable
							.then( function( rawData ) {
								cacheService.entityCache = [];
								rawData[ collectionName ].forEach( function( rawEntity ) {
									cacheService.entityCache.push( fromJson( rawEntity ) );
								} );
								cacheService.objectsAvailableDeferred.resolve( cacheService.entityCache );
								$rootScope.$broadcast( "collectionNew", {
									service : cacheService,
									cache   : cacheService.entityCache
								} );
							} );

						/**
						 * Read a single entity from the cache, or load it from the server if required.
						 * @param {String} id The ID of the entity to retrieve.
						 * @returns {adapter.deferred.promise|*|defer.promise|eventObject.promise|promise|Q.promise}
						 */
						cacheService.read = function( id ) {
							var deferred = $q.defer();

							cacheService.ensureLoaded()
								.then( function() {
									// Check if the entity is in the cache and return instantly if found.
									for( var entityIndex = 0, entity = cacheService.entityCache[ 0 ], cacheSize = cacheService.entityCache.length;
									     entityIndex < cacheSize;
									     ++entityIndex, entity = cacheService.entityCache[ entityIndex ] ) {
										if( entity.id == id ) {
											deferred.resolve( entity );
											return;
										}
									}

									// Grab the entity from the backend.
									$http.get( entityUri + "/" + id ).success(
										function( data ) {
											if( !data[ entityName ] ) {
												deferred.reject( new Error( "The requested person could not be found in the database." ) );
												return;
											}

											var entity = fromJson( data[ entityName ] );
											updateCacheWithEntity( entity );
											deferred.resolve( entity );
										}
									);
								} );

							return deferred.promise;
						};

						/**
						 * Updates an entity and persists it to the backend and the cache.
						 * @param {Object} entity
						 */
						cacheService.update = function( entity ) {
							var promise;

							// Wrap entity in a new object, with a single property, named after the entity type.
							var wrapper = {};
							wrapper[ entityName ] = entity;

							if( "undefined" !== typeof( entity.id ) ) {
								promise = $http.put( entityUri + "/" + entity.id, wrapper );
								promise
									.then( function( result ) {
										// Writing a person to the backend will usually invoke an update event to be
										// broadcast over websockets, where would also retrieve the updated record.
										// We still put the updated record we receive here into the cache to ensure early consistency.
										if( result.data[ entityName ] ) {
											var newEntity = fromJson( result.data[ entityName ] );
											updateCacheWithEntity( newEntity );
										}
									},
									function( error ) {
										console.error( error );
									} );

							} else {
								// Create a new person
								promise = $http.post( collectionUri, wrapper );
								promise
									.then( function( result ) {
										// Writing a person to the backend will usually invoke an update event to be
										// broadcast over websockets, where would also retrieve the updated record.
										// We still put the updated record we receive here into the cache to ensure early consistency.
										if( result.data[ entityName ] ) {
											var newEntity = fromJson( result.data[ entityName ] );
											updateCacheWithEntity( newEntity );
										}
									},
									function( error ) {
										console.error( error );
									} );
							}

							return promise;
						};

						/**
						 * Creates a new entity and persists it to the backend and the cache.
						 */
						cacheService.create = cacheService.update;

						/**
						 * Remove an entity from the cache and have it deleted on the backend.
						 * @param {Object} entity
						 */
						cacheService.delete = function( entity ) {
							var deferred = $q.defer();

							var entityId = entity.id;
							$http.delete( entityUri + "/" + entityId )
								.success( function( data, status, headers, config ) {
									removeEntityFromCache( entityId );
									deferred.resolve();
								} )
								.error( function( data, status, headers, config ) {
									console.error( data );
									deferred.reject( new Error( "Unable to delete entity." ) );
								} );

							return deferred.promise;
						};

						/**
						 * Put an entity into the cache or update the existing record if the entity was already in the cache.
						 * @param {Object} entityToCache
						 */
						function updateCacheWithEntity( entityToCache ) {
							console.log( "Updating entity in cache..." );
							var found = false;
							for( var entityIndex = 0, entity = cacheService.entityCache[ 0 ], cacheSize = cacheService.entityCache.length;
							     entityIndex < cacheSize;
							     ++entityIndex, entity = cacheService.entityCache[ entityIndex ] ) {
								if( entity.id == entityToCache.id ) {
									$rootScope.$broadcast( "beforeEntityUpdated",
										{
											service : cacheService,
											cache   : cacheService.entityCache,
											entity  : cacheService.entityCache[ entityIndex ]
										} );
									cacheService.entityCache[ entityIndex ].copyFrom( entityToCache );
									found = true;
									$rootScope.$broadcast( "entityUpdated",
										{
											service : cacheService,
											cache   : cacheService.entityCache,
											entity  : cacheService.entityCache[ entityIndex ]
										} );
									break;
								}
							}

							// If the entity wasn't found in our records, it's a new entity.
							if( !found ) {
								cacheService.entityCache.push( entityToCache );
								$rootScope.$broadcast( "entityNew", {
									service : cacheService,
									cache   : cacheService.entityCache,
									entity  : entityToCache
								} );
							}
						}

						/**
						 * Removes an entity from the internal cache. The entity is not removed from the backend.
						 * @param {String} id The ID of the entity to remove from the cache.
						 */
						function removeEntityFromCache( id ) {
							for( var entityIndex = 0, entity = cacheService.entityCache[ 0 ], cacheSize = cacheService.entityCache.length;
							     entityIndex < cacheSize;
							     ++entityIndex, entity = cacheService.entityCache[ entityIndex ] ) {
								if( entity.id == id ) {
									$rootScope.$broadcast( "beforeEntityRemoved", {
										service : cacheService,
										cache   : cacheService.entityCache,
										entity  : entity
									} );
									cacheService.entityCache.splice( entityIndex, 1 );
									$rootScope.$broadcast( "entityRemoved", {
										service : cacheService,
										cache   : cacheService.entityCache,
										entity  : entity
									} );
									break;
								}
							}
						}

						/**
						 * Retrieve an associative array of all cached entities, which uses the ID of the entity records as the key in the array.
						 * @returns {Array}
						 */
						cacheService.lookupTableById = function() {
							//TODO: Keep a copy of the lookup table and only update it when the cached data updates
							var lookupTable = [];
							for( var entityIndex = 0, cacheSize = cacheService.entityCache.length; entityIndex < cacheSize; ++entityIndex ) {
								lookupTable[ cacheService.entityCache[ entityIndex ].id ] = cacheService.entityCache[ entityIndex ];
							}
							return lookupTable;
						};

						// Listen for person broadcasts. These are sent when a person record is received through a websocket.
						cacheService.ensureLoaded().then( function() {
							$rootScope.$on( entityName, function( event, args ) {

								var entityReceived = args;

								// Determine if the received record consists ONLY of an id property,
								// which would mean that this record was deleted from the backend.
								if( 1 == Object.keys( entityReceived ).length && entityReceived.hasOwnProperty( "id" ) ) {
									console.log( "Entity was deleted from the server. Updating cache..." );
									removeEntityFromCache( entityReceived.id );
								} else {
									updateCacheWithEntity( fromJson( entityReceived ) );
								}
							} );
						} );

						if( then ) {
							// Use setTimeout to break possible dependency loops when "then" references the caching service that we just constructed.
							setTimeout( then );
						}

						return cacheService;
					}
				]
			);
		};

		return builder;
	};
}( absync || (absync = {}) ));
<|endoftext|>


<commit_before>"use strict";function _createForOfIteratorHelper(o,allowArrayLike){var it;if(typeof Symbol==="undefined"||o[Symbol.iterator]==null){if(Array.isArray(o)||(it=_unsupportedIterableToArray(o))||allowArrayLike&&o&&typeof o.length==="number"){if(it)o=it;var i=0;var F=function F(){};return{s:F,n:function n(){if(i>=o.length)return{done:true};return{done:false,value:o[i++]}},e:function e(_e2){throw _e2},f:F}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var normalCompletion=true,didErr=false,err;return{s:function s(){it=o[Symbol.iterator]()},n:function n(){var step=it.next();normalCompletion=step.done;return step},e:function e(_e3){didErr=true;err=_e3},f:function f(){try{if(!normalCompletion&&it["return"]!=null)it["return"]()}finally{if(didErr)throw err}}}}function _defineProperty(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true})}else{obj[key]=value}return obj}function _slicedToArray(arr,i){return _arrayWithHoles(arr)||_iterableToArrayLimit(arr,i)||_unsupportedIterableToArray(arr,i)||_nonIterableRest()}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _unsupportedIterableToArray(o,minLen){if(!o)return;if(typeof o==="string")return _arrayLikeToArray(o,minLen);var n=Object.prototype.toString.call(o).slice(8,-1);if(n==="Object"&&o.constructor)n=o.constructor.name;if(n==="Map"||n==="Set")return Array.from(o);if(n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return _arrayLikeToArray(o,minLen)}function _arrayLikeToArray(arr,len){if(len==null||len>arr.length)len=arr.length;for(var i=0,arr2=new Array(len);i<len;i++){arr2[i]=arr[i]}return arr2}function _iterableToArrayLimit(arr,i){if(typeof Symbol==="undefined"||!(Symbol.iterator in Object(arr)))return;var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break}}catch(err){_d=true;_e=err}finally{try{if(!_n&&_i["return"]!=null)_i["return"]()}finally{if(_d)throw _e}}return _arr}function _arrayWithHoles(arr){if(Array.isArray(arr))return arr}module.exports=function(input){if(!input)return[];if(typeof input!=="string"||input.match(/^\s+$/))return[];var lines=input.split("\n");if(lines.length===0)return[];var files=[];var currentFile=null;var currentChunk=null;var deletedLineCounter=0;var addedLineCounter=0;var normal=function normal(line){var _currentChunk;(_currentChunk=currentChunk)===null||_currentChunk===void 0?void 0:_currentChunk.changes.push({type:"normal",normal:true,ln1:deletedLineCounter++,ln2:addedLineCounter++,content:line})};var start=function start(line){var _parseFiles;var _ref=(_parseFiles=parseFiles(line))!==null&&_parseFiles!==void 0?_parseFiles:[],_ref2=_slicedToArray(_ref,2),fromFileName=_ref2[0],toFileName=_ref2[1];currentFile={chunks:[],deletions:0,additions:0,from:fromFileName,to:toFileName};files.push(currentFile)};var restart=function restart(){if(!currentFile||currentFile.chunks.length)start()};var newFile=function newFile(){restart();currentFile["new"]=true;currentFile.from="/dev/null"};var deletedFile=function deletedFile(){restart();currentFile.deleted=true;currentFile.to="/dev/null"};var index=function index(line){restart();currentFile.index=line.split(" ").slice(1)};var fromFile=function fromFile(line){restart();currentFile.from=parseOldOrNewFile(line)};var toFile=function toFile(line){restart();currentFile.to=parseOldOrNewFile(line)};var chunk=function chunk(line,match){if(!currentFile)return;var _match$slice=match.slice(1),_match$slice2=_slicedToArray(_match$slice,4),oldStart=_match$slice2[0],oldNumLines=_match$slice2[1],newStart=_match$slice2[2],newNumLines=_match$slice2[3];deletedLineCounter=+oldStart;addedLineCounter=+newStart;currentChunk={content:line,changes:[],oldStart:+oldStart,oldLines:+(oldNumLines||1),newStart:+newStart,newLines:+(newNumLines||1)};currentFile.chunks.push(currentChunk)};var del=function del(line){if(!currentChunk)return;currentChunk.changes.push({type:"del",del:true,ln:deletedLineCounter++,content:line});currentFile.deletions++};var add=function add(line){if(!currentChunk)return;currentChunk.changes.push({type:"add",add:true,ln:addedLineCounter++,content:line});currentFile.additions++};var eof=function eof(line){var _currentChunk$changes3;if(!currentChunk)return;var _currentChunk$changes=currentChunk.changes.slice(-1),_currentChunk$changes2=_slicedToArray(_currentChunk$changes,1),mostRecentChange=_currentChunk$changes2[0];currentChunk.changes.push((_currentChunk$changes3={type:mostRecentChange.type},_defineProperty(_currentChunk$changes3,mostRecentChange.type,true),_defineProperty(_currentChunk$changes3,"ln1",mostRecentChange.ln1),_defineProperty(_currentChunk$changes3,"ln2",mostRecentChange.ln2),_defineProperty(_currentChunk$changes3,"ln",mostRecentChange.ln),_defineProperty(_currentChunk$changes3,"content",line),_currentChunk$changes3))};var schema=[// TODO: better regexp to avoid detect normal line starting with diff
[/^\s+/,normal],[/^diff\s/,start],[/^new file mode \d+$/,newFile],[/^deleted file mode \d+$/,deletedFile],[/^index\s[\da-zA-Z]+\.\.[\da-zA-Z]+(\s(\d+))?$/,index],[/^---\s/,fromFile],[/^\+\+\+\s/,toFile],[/^@@\s+-(\d+),?(\d+)?\s+\+(\d+),?(\d+)?\s@@/,chunk],[/^-/,del],[/^\+/,add],[/^\\ No newline at end of file$/,eof]];var parseLine=function parseLine(line){var _iterator=_createForOfIteratorHelper(schema),_step;try{for(_iterator.s();!(_step=_iterator.n()).done;){var _step$value=_slicedToArray(_step.value,2),pattern=_step$value[0],handler=_step$value[1];var match=line.match(pattern);if(match){handler(line,match);return true}}}catch(err){_iterator.e(err)}finally{_iterator.f()}return false};var _iterator2=_createForOfIteratorHelper(lines),_step2;try{for(_iterator2.s();!(_step2=_iterator2.n()).done;){var line=_step2.value;parseLine(line)}}catch(err){_iterator2.e(err)}finally{_iterator2.f()}return files};var fileNameDiffRegex=/a\/.*(?=["']? ["']?b\/)|b\/.*$/g;var gitFileHeaderRegex=/^(a|b)\//;var parseFiles=function parseFiles(line){var fileNames=line===null||line===void 0?void 0:line.match(fileNameDiffRegex);return fileNames===null||fileNames===void 0?void 0:fileNames.map(function(fileName){return fileName.replace(gitFileHeaderRegex,"").replace(/("|')$/,"")})};var qoutedFileNameRegex=/^\\?['"]|\\?['"]$/g;var parseOldOrNewFile=function parseOldOrNewFile(line){var fileName=leftTrimChars(line,"-+").trim();fileName=removeTimeStamp(fileName);return fileName.replace(qoutedFileNameRegex,"").replace(gitFileHeaderRegex,"")};var leftTrimChars=function leftTrimChars(string,trimmingChars){string=makeString(string);if(!trimmingChars&&String.prototype.trimLeft)return string.trimLeft();var trimmingString=formTrimmingString(trimmingChars);return string.replace(new RegExp("^".concat(trimmingString,"+")),"")};var timeStampRegex=/\t.*|\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d(.\d+)?\s(\+|-)\d\d\d\d/;var removeTimeStamp=function removeTimeStamp(string){var timeStamp=timeStampRegex.exec(string);if(timeStamp){string=string.substring(0,timeStamp.index).trim()}return string};var formTrimmingString=function formTrimmingString(trimmingChars){if(trimmingChars===null||trimmingChars===undefined)return"\\s";else if(trimmingChars instanceof RegExp)return trimmingChars.source;return"[".concat(makeString(trimmingChars).replace(/([.*+?^=!:${}()|[\]/\\])/g,"\\$1"),"]")};var makeString=function makeString(itemToConvert){return(itemToConvert!==null&&itemToConvert!==void 0?itemToConvert:"")+""};
<commit_msg>Push minified file too<commit_after>"use strict";function _createForOfIteratorHelper(o,allowArrayLike){var it;if(typeof Symbol==="undefined"||o[Symbol.iterator]==null){if(Array.isArray(o)||(it=_unsupportedIterableToArray(o))||allowArrayLike&&o&&typeof o.length==="number"){if(it)o=it;var i=0;var F=function F(){};return{s:F,n:function n(){if(i>=o.length)return{done:true};return{done:false,value:o[i++]}},e:function e(_e2){throw _e2},f:F}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var normalCompletion=true,didErr=false,err;return{s:function s(){it=o[Symbol.iterator]()},n:function n(){var step=it.next();normalCompletion=step.done;return step},e:function e(_e3){didErr=true;err=_e3},f:function f(){try{if(!normalCompletion&&it["return"]!=null)it["return"]()}finally{if(didErr)throw err}}}}function _defineProperty(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true})}else{obj[key]=value}return obj}function _slicedToArray(arr,i){return _arrayWithHoles(arr)||_iterableToArrayLimit(arr,i)||_unsupportedIterableToArray(arr,i)||_nonIterableRest()}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _unsupportedIterableToArray(o,minLen){if(!o)return;if(typeof o==="string")return _arrayLikeToArray(o,minLen);var n=Object.prototype.toString.call(o).slice(8,-1);if(n==="Object"&&o.constructor)n=o.constructor.name;if(n==="Map"||n==="Set")return Array.from(o);if(n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return _arrayLikeToArray(o,minLen)}function _arrayLikeToArray(arr,len){if(len==null||len>arr.length)len=arr.length;for(var i=0,arr2=new Array(len);i<len;i++){arr2[i]=arr[i]}return arr2}function _iterableToArrayLimit(arr,i){if(typeof Symbol==="undefined"||!(Symbol.iterator in Object(arr)))return;var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break}}catch(err){_d=true;_e=err}finally{try{if(!_n&&_i["return"]!=null)_i["return"]()}finally{if(_d)throw _e}}return _arr}function _arrayWithHoles(arr){if(Array.isArray(arr))return arr}module.exports=function(input){if(!input)return[];if(typeof input!=="string"||input.match(/^\s+$/))return[];var lines=input.split("\n");if(lines.length===0)return[];var files=[];var currentFile=null;var currentChunk=null;var deletedLineCounter=0;var addedLineCounter=0;var currentFileChanges=null;var normal=function normal(line){var _currentChunk;(_currentChunk=currentChunk)===null||_currentChunk===void 0?void 0:_currentChunk.changes.push({type:"normal",normal:true,ln1:deletedLineCounter++,ln2:addedLineCounter++,content:line});currentFileChanges.oldLines--;currentFileChanges.newLines--};var start=function start(line){var _parseFiles;var _ref=(_parseFiles=parseFiles(line))!==null&&_parseFiles!==void 0?_parseFiles:[],_ref2=_slicedToArray(_ref,2),fromFileName=_ref2[0],toFileName=_ref2[1];currentFile={chunks:[],deletions:0,additions:0,from:fromFileName,to:toFileName};files.push(currentFile)};var restart=function restart(){if(!currentFile||currentFile.chunks.length)start()};var newFile=function newFile(){restart();currentFile["new"]=true;currentFile.from="/dev/null"};var deletedFile=function deletedFile(){restart();currentFile.deleted=true;currentFile.to="/dev/null"};var index=function index(line){restart();currentFile.index=line.split(" ").slice(1)};var fromFile=function fromFile(line){restart();currentFile.from=parseOldOrNewFile(line)};var toFile=function toFile(line){restart();currentFile.to=parseOldOrNewFile(line)};var toNumOfLines=function toNumOfLines(number){return+(number||1)};var chunk=function chunk(line,match){if(!currentFile)return;var _match$slice=match.slice(1),_match$slice2=_slicedToArray(_match$slice,4),oldStart=_match$slice2[0],oldNumLines=_match$slice2[1],newStart=_match$slice2[2],newNumLines=_match$slice2[3];deletedLineCounter=+oldStart;addedLineCounter=+newStart;currentChunk={content:line,changes:[],oldStart:+oldStart,oldLines:toNumOfLines(oldNumLines),newStart:+newStart,newLines:toNumOfLines(newNumLines)};currentFileChanges={oldLines:toNumOfLines(oldNumLines),newLines:toNumOfLines(newNumLines)};currentFile.chunks.push(currentChunk)};var del=function del(line){if(!currentChunk)return;currentChunk.changes.push({type:"del",del:true,ln:deletedLineCounter++,content:line});currentFile.deletions++;currentFileChanges.oldLines--};var add=function add(line){if(!currentChunk)return;currentChunk.changes.push({type:"add",add:true,ln:addedLineCounter++,content:line});currentFile.additions++;currentFileChanges.newLines--};var eof=function eof(line){var _currentChunk$changes3;if(!currentChunk)return;var _currentChunk$changes=currentChunk.changes.slice(-1),_currentChunk$changes2=_slicedToArray(_currentChunk$changes,1),mostRecentChange=_currentChunk$changes2[0];currentChunk.changes.push((_currentChunk$changes3={type:mostRecentChange.type},_defineProperty(_currentChunk$changes3,mostRecentChange.type,true),_defineProperty(_currentChunk$changes3,"ln1",mostRecentChange.ln1),_defineProperty(_currentChunk$changes3,"ln2",mostRecentChange.ln2),_defineProperty(_currentChunk$changes3,"ln",mostRecentChange.ln),_defineProperty(_currentChunk$changes3,"content",line),_currentChunk$changes3))};var schemaHeaders=[[/^diff\s/,start],[/^new file mode \d+$/,newFile],[/^deleted file mode \d+$/,deletedFile],[/^index\s[\da-zA-Z]+\.\.[\da-zA-Z]+(\s(\d+))?$/,index],[/^---\s/,fromFile],[/^\+\+\+\s/,toFile],[/^@@\s+-(\d+),?(\d+)?\s+\+(\d+),?(\d+)?\s@@/,chunk],[/^\\ No newline at end of file$/,eof]];var schemaContent=[[/^-/,del],[/^\+/,add],[/^\s+/,normal]];var parseContentLine=function parseContentLine(line){var _iterator=_createForOfIteratorHelper(schemaContent),_step;try{for(_iterator.s();!(_step=_iterator.n()).done;){var _step$value=_slicedToArray(_step.value,2),pattern=_step$value[0],handler=_step$value[1];var match=line.match(pattern);if(match){handler(line,match);break}}}catch(err){_iterator.e(err)}finally{_iterator.f()}if(currentFileChanges.oldLines===0&&currentFileChanges.newLines===0){currentFileChanges=null}};var parseHeaderLine=function parseHeaderLine(line){var _iterator2=_createForOfIteratorHelper(schemaHeaders),_step2;try{for(_iterator2.s();!(_step2=_iterator2.n()).done;){var _step2$value=_slicedToArray(_step2.value,2),pattern=_step2$value[0],handler=_step2$value[1];var match=line.match(pattern);if(match){handler(line,match);break}}}catch(err){_iterator2.e(err)}finally{_iterator2.f()}};var parseLine=function parseLine(line){if(currentFileChanges){parseContentLine(line)}else{parseHeaderLine(line)}return};var _iterator3=_createForOfIteratorHelper(lines),_step3;try{for(_iterator3.s();!(_step3=_iterator3.n()).done;){var line=_step3.value;parseLine(line)}}catch(err){_iterator3.e(err)}finally{_iterator3.f()}return files};var fileNameDiffRegex=/a\/.*(?=["']? ["']?b\/)|b\/.*$/g;var gitFileHeaderRegex=/^(a|b)\//;var parseFiles=function parseFiles(line){var fileNames=line===null||line===void 0?void 0:line.match(fileNameDiffRegex);return fileNames===null||fileNames===void 0?void 0:fileNames.map(function(fileName){return fileName.replace(gitFileHeaderRegex,"").replace(/("|')$/,"")})};var qoutedFileNameRegex=/^\\?['"]|\\?['"]$/g;var parseOldOrNewFile=function parseOldOrNewFile(line){var fileName=leftTrimChars(line,"-+").trim();fileName=removeTimeStamp(fileName);return fileName.replace(qoutedFileNameRegex,"").replace(gitFileHeaderRegex,"")};var leftTrimChars=function leftTrimChars(string,trimmingChars){string=makeString(string);if(!trimmingChars&&String.prototype.trimLeft)return string.trimLeft();var trimmingString=formTrimmingString(trimmingChars);return string.replace(new RegExp("^".concat(trimmingString,"+")),"")};var timeStampRegex=/\t.*|\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d(.\d+)?\s(\+|-)\d\d\d\d/;var removeTimeStamp=function removeTimeStamp(string){var timeStamp=timeStampRegex.exec(string);if(timeStamp){string=string.substring(0,timeStamp.index).trim()}return string};var formTrimmingString=function formTrimmingString(trimmingChars){if(trimmingChars===null||trimmingChars===undefined)return"\\s";else if(trimmingChars instanceof RegExp)return trimmingChars.source;return"[".concat(makeString(trimmingChars).replace(/([.*+?^=!:${}()|[\]/\\])/g,"\\$1"),"]")};var makeString=function makeString(itemToConvert){return(itemToConvert!==null&&itemToConvert!==void 0?itemToConvert:"")+""};
<|endoftext|>