<commit_before>/**
 * Activation component.
 *
 * This JavaScript loads on every admin page. Reserved for later.
 *
 * Site Kit by Google, Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * WordPress dependencies
 */
import domReady from '@wordpress/dom-ready';
import { render } from '@wordpress/element';
import { doAction } from '@wordpress/hooks';

/**
 * External dependencies
 */
import { loadTranslations } from 'GoogleUtil';
import 'GoogleComponents/notifications';

/**
 * Internal dependencies
 */
import { ActivationApp } from './components/activation/activation-app';

domReady( () => {
	const renderTarget = document.getElementById( 'js-googlesitekit-activation' );

	if ( renderTarget ) {
		loadTranslations();

		render( <ActivationApp />, renderTarget );

		/**
		 * Action triggered when the ActivationApp is loaded.
		 */
		doAction( 'googlesitekit.moduleLoaded', 'Activation' );
	}
} );
<commit_msg>Send plugin_activated event on activation.<commit_after>/**
 * Activation component.
 *
 * This JavaScript loads on every admin page. Reserved for later.
 *
 * Site Kit by Google, Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * WordPress dependencies
 */
import domReady from '@wordpress/dom-ready';
import { render } from '@wordpress/element';
import { doAction } from '@wordpress/hooks';

/**
 * External dependencies
 */
import { loadTranslations, sendAnalyticsTrackingEvent } from 'GoogleUtil';
import 'GoogleComponents/notifications';

/**
 * Internal dependencies
 */
import { ActivationApp } from './components/activation/activation-app';

domReady( () => {
	const renderTarget = document.getElementById( 'js-googlesitekit-activation' );

	if ( renderTarget ) {
		loadTranslations();
		sendAnalyticsTrackingEvent( 'plugin_setup', 'plugin_activated' );

		render( <ActivationApp />, renderTarget );

		/**
		 * Action triggered when the ActivationApp is loaded.
		 */
		doAction( 'googlesitekit.moduleLoaded', 'Activation' );
	}
} );
<|endoftext|>


<commit_before>/* Exports a function which returns an object that overrides the default &
 *   plugin file patterns (used widely through the app configuration)
 *
 * To see the default definitions for Lineman's file paths and globs, see:
 *
 *   - https://github.com/linemanjs/lineman/blob/master/config/files.coffee
 */
module.exports = function(lineman) {
  //Override file patterns here
  return {
    js: {
      vendor: [
        "vendor/bower/jquery/dist/jquery.js",
        "vendor/bower/growl/javascripts/jquery.growl.js",
        "vendor/bower/stacktrace/dist/stacktrace.js",
        "vendor/bower/angular/angular.js",
        "vendor/bower/angular-messages/angular-messages.js",
        "vendor/js/bootstrap.js",
        // angular-material
        "vendor/bower/angular-animate/angular-animate.js",
        "vendor/bower/angular-aria/angular-aria.js",
        "vendor/bower/hammerjs/hammer.js",
        "vendor/bower/angular-material/angular-material.js",

        "vendor/bower/angular-resource/angular-resource.js",
        // "vendor/bower/angular-ui-router/angular-ui-router.js",
        "vendor/js/angular-ui-router.js",
        "vendor/bower/angular-translate/angular-translate.js",
        "vendor/bower/angular-translate-loader-static-files/angular-translate-loader-static-files.js",

        "vendor/bower/angular-pageslide-directive/dist/angular-pageslide-directive.js",
        "vendor/bower/ng-idle/angular-idle.js",
        "vendor/bower/angular-bootstrap/ui-bootstrap.js",
        "vendor/bower/angular-bootstrap/ui-bootstrap-tpls.js",
        "vendor/bower/angular-ui-grid/ui-grid.js",
        "vendor/bower/angular-ui-utils/validate.js",
        "vendor/bower/angular-xeditable/dist/js/xeditable.js",
        "vendor/bower/moment/min/moment-with-locales.js",
        // "vendor/js/ui-bootstrap-tpls.js",
        //  "vendor/js/ui-grid.js",
        // "vendor/js/angular-idle.js",
        // "vendor/js/validate.js",
        // "vendor/js/xeditable.js",
        // "vendor/js/angular-translate.min.js",
        // "vendor/js/angular-translate-loader-static-files.min.js",
        "vendor/js/jsonpath.js",
        "vendor/js/highstock.src.js",

    // version conflicts to solve
    // "angular-pageslide-directive": "~0.1.8",
    // "ng-idle": "~0.3.5"

        // "vendor/js/jquery.js",
        // "vendor/js/jquery.growl.js",
        // // "vendor/js/ark.js",
        // "vendor/js/stacktrace.js",
        // "vendor/js/angular.js",
        // "vendor/js/angular-resource.js",
// "vendor/js/angular-idle.js",
        // "vendor/js/angular-ui-router.js",
        // "vendor/js/ui-bootstrap-tpls.js",
        // "vendor/js/ui-grid.js",
        // "vendor/js/angular-idle.js",
        // "vendor/js/validate.js",
        // "vendor/js/xeditable.js",
        // "vendor/js/angular-translate.min.js",
        // "vendor/js/angular-translate-loader-static-files.min.js",
        // "vendor/js/jsonpath.js",
        // "vendor/js/angular-pageslide-directive.js",
        // "vendor/js/highstock.src.js",
        // "vendor/js/moment-with-locales.js"
        "vendor/js/moment-with-locales.js",
        "vendor/js/bytebuffer.js"
      ],
      app: [
        "app/js/app.js",
        "app/js/**/*.js"
      ]
    },

//    less: {
//      compile: {
//        options: {
//          paths: ["vendor/css/normalize.css", "vendor/css/**/*.css", "app/css/**/*.less"]
//        }
//      }
//    },

    css: {
      vendor: [
        "vendor/bower/growl/stylesheets/jquery.growl.css",
        "vendor/bower/angular-material/angular-material.css",
        "vendor/bower/angular-ui-grid/ui-grid.css",
        "vendor/bower/angular-xeditable/dist/css/xeditable.css",
        "vendor/css/bootstrap.css",
        "vendor/css/font-awesome.css",
        "vendor/css/ark.css"

        // "vendor/css/jquery.growl.css",
        // "vendor/css/bootstrap.css",
        // "vendor/css/font-awesome.css",
        // "vendor/css/ark.css",
        // "vendor/css/xeditable.css",
        // "vendor/css/ui-grid.css"
      ],
      app: [
        "app/css/*.css",
        "app/css/main.scss"

        // "app/css/bootstrap_overrides.css",
        // "app/css/main.css",
        // "app/css/forms.css",
        // "app/css/layout.css",
        // "app/css/my-ng-grid.css",
        // "app/css/toolbar.css",
        // "app/css/footer.css",
        // "app/css/market.css",
        // "app/css/spinner.css",
        // "app/css/mail.css",
        // "app/css/help.css",
        // "app/css/splashpage.css",
        //
        // "app/main.scss"
      ]
      // vendor: [
      //   "vendor/css/jquery.growl.css",
      //   "vendor/css/bootstrap.css",
      //   "vendor/css/font-awesome.css",
      //   "vendor/css/ark.css",
      //   "vendor/css/xeditable.css",
      //   "vendor/css/ui-grid.css",
      //   "vendor/css/material.css",
      //   "vendor/css/material-wfont.css",
      //   "vendor/css/ripples.css",
      // ],
      // app: [
      //   "app/css/bootstrap_overrides.css",
      //   "app/css/main.css",
      //   "app/css/forms.css",
      //   "app/css/layout.css",
      //   "app/css/my-ng-grid.css",
      //   "app/css/toolbar.css",
      //   "app/css/footer.css",
      //   "app/css/market.css",
      //   "app/css/spinner.css",
      //   "app/css/help.css",
      //   "app/css/splashpage.scss"
      // ]
    }

  };
};

<commit_msg>house keeping<commit_after>/* Exports a function which returns an object that overrides the default &
 *   plugin file patterns (used widely through the app configuration)
 *
 * To see the default definitions for Lineman's file paths and globs, see:
 *
 *   - https://github.com/linemanjs/lineman/blob/master/config/files.coffee
 */
module.exports = function(lineman) {
  //Override file patterns here
  return {
    js: {
      vendor: [
        "vendor/bower/jquery/dist/jquery.js",
        "vendor/bower/growl/javascripts/jquery.growl.js",
        "vendor/bower/stacktrace/dist/stacktrace.js",
        "vendor/bower/angular/angular.js",
        "vendor/bower/angular-messages/angular-messages.js",
        "vendor/js/bootstrap.js",
        // angular-material
        "vendor/bower/angular-animate/angular-animate.js",
        "vendor/bower/angular-aria/angular-aria.js",
        "vendor/bower/hammerjs/hammer.js",
        "vendor/bower/angular-material/angular-material.js",

        "vendor/bower/angular-resource/angular-resource.js",
        "vendor/js/angular-ui-router.js",
        "vendor/bower/angular-translate/angular-translate.js",
        "vendor/bower/angular-translate-loader-static-files/angular-translate-loader-static-files.js",

        "vendor/bower/angular-pageslide-directive/dist/angular-pageslide-directive.js",
        "vendor/bower/ng-idle/angular-idle.js",
        "vendor/bower/angular-bootstrap/ui-bootstrap.js",
        "vendor/bower/angular-bootstrap/ui-bootstrap-tpls.js",
        "vendor/bower/angular-ui-grid/ui-grid.js",
        "vendor/bower/angular-ui-utils/validate.js",
        "vendor/bower/angular-xeditable/dist/js/xeditable.js",
        "vendor/bower/moment/min/moment-with-locales.js",
        "vendor/js/jsonpath.js",
        "vendor/js/highstock.src.js",
        "vendor/js/moment-with-locales.js",
        "vendor/js/bytebuffer.js"
      ],
      app: [
        "app/js/app.js",
        "app/js/**/*.js"
      ]
    },

//    less: {
//      compile: {
//        options: {
//          paths: ["vendor/css/normalize.css", "vendor/css/**/*.css", "app/css/**/*.less"]
//        }
//      }
//    },

    css: {
      vendor: [
        "vendor/bower/growl/stylesheets/jquery.growl.css",
        "vendor/bower/angular-material/angular-material.css",
        "vendor/bower/angular-ui-grid/ui-grid.css",
        "vendor/bower/angular-xeditable/dist/css/xeditable.css",
        "vendor/css/bootstrap.css",
        "vendor/css/font-awesome.css",
        "vendor/css/ark.css"
      ],
      app: [
        "app/css/*.css",
        "app/css/main.scss"
      ]
    }

  };
};

<|endoftext|>


<commit_before>module.exports = {
  // order is important!
	libs: [
		'libs/datespy/datespy.js',
		'test/helpers/globals.js',
		'src/declarations.js',
		'src/addins/defaults.js',
		'src/addins/helpers.js',
		'src/addins/color.js',
		'src/addins/supplant.js',
		'src/addins/masking.js',
		'src/enhanceObj/*.js',
		'src/eLogger/logger.js',
		'src/eLogger/globals.js',
		'src/extras/*.js',
		'src/providerFunc/*.js'
	],
	exclusions: ['src/enhanceObj/globals.js'],
	reporters: ['dots', 'coverage'],
	tests: function (version) {
		var vspec = [];
		if (/[1-9]\.[2-9]|[1-9]\.[1-9]\.[2-9]|[1-9]\.[2-9]\.[1-9]/.test(version)) {
			vspec = [
				'test/vspec/*.js'
			];
		}
		return ['test/unit/*.js'].concat(vspec);
	},
	getAngularFiles: function (version) {
		if (version === undefined) {
			version = 'latest';
		} else {
			version += '.x';
		}
		return [
			'libs/angular/' + version + '/angular.js',
			'libs/angular/' + version + '/angular-mocks.js'
		];
	}
};
<commit_msg>vspec now runs on latests angular version<commit_after>module.exports = {
  // order is important!
	libs: [
		'libs/datespy/datespy.js',
		'test/helpers/globals.js',
		'src/declarations.js',
		'src/addins/defaults.js',
		'src/addins/helpers.js',
		'src/addins/color.js',
		'src/addins/supplant.js',
		'src/addins/masking.js',
		'src/enhanceObj/*.js',
		'src/eLogger/logger.js',
		'src/eLogger/globals.js',
		'src/extras/*.js',
		'src/providerFunc/*.js'
	],
	exclusions: ['src/enhanceObj/globals.js'],
	reporters: ['dots', 'coverage'],
	tests: function (version) {
		var vspec = [];
		if (/(?:[1-9]\.(?:[2-9](?:\.[1-9])?|[1-9]\.[2-9])|latest)/.test(version)) {
			vspec = [
				'test/vspec/*.js'
			];
		}
		return ['test/unit/*.js'].concat(vspec);
	},
	getAngularFiles: function (version) {
		if (version === undefined) {
			version = 'latest';
		} else {
			version += '.x';
		}
		return [
			'libs/angular/' + version + '/angular.js',
			'libs/angular/' + version + '/angular-mocks.js'
		];
	}
};
<|endoftext|>


<commit_before>// Load in dependencies
var numscale = require('numscale');
var Settings = require('shallow-settings');
var errorLoggers = require('./error-loggers');

// Define our settings
module.exports = new Settings({
  common: {
    addDevelopmentRoutes: true,
    addTestRoutes: true,
    articles: Settings.lazy(function () {
      return require('../articles');
    }),
    'app.locals': Settings.lazy(function () {
      // TODO: This is very bad technique but models/projects is worse
      var projects = require('../server/models/projects');
      if (this.updateProjectsImmediately) {
        process.nextTick(global.updateProjects);
      }
      return {
        config: {
          author: 'Todd Wolfson',
          title: 'Todd Wolfson - Javascript Developer',
          url: 'http://twolfson.com/'
        },
        env: this.ENV,
        numscale: numscale.scale,
        projects: projects
      };
    }),
    // TODO: Restore common logger
    // errorLogger: Settings.lazy(function () {
    //   return errorLoggers.common();
    // }),
    errorLogger: Settings.lazy(function () {
      return errorLoggers.production({
        environment: this.ENV,
        revision: this['package'].version
      });
    }),
    mail: Settings.lazy(function () {
      return require('./mail');
    }),
    'package': Settings.lazy(function () {
      return require('../package.json');
    }),
    'support-me': {
      bitcoin: '1LVT8UpsgyKhGzN3TZxSKqqqd466NtZ99p',
      dogecoin: 'DGJQbYtSH8jau967XKUR7cpZ7jJEe9SPSQ',
      flattr: 'twolfsn',
      gittip: 'twolfson',
      paypal: {
        name: 'Todd Wolfson',
        email: 'todd@twolfson.com'
      },
    },
    updateProjectsImmediately: false,
    url: {
      internal: {
        protocol: 'http',
        hostname: 'localhost',
        port: 8080
      },
      external: {
        protocol: 'http',
        hostname: 'localhost',
        port: 8080
      }
    }
  },
  development: {
    // Same as common
  },
  test: {
    addDevelopmentRoutes: false,
    addTestRoutes: true,
    mail: {
      host: 'localhost',
      port: 1338
    },
    url: {
      internal: {
        protocol: 'http',
        hostname: 'localhost',
        port: 1337
      },
      external: {
        protocol: 'http',
        hostname: 'twolfson.test',
        port: 1337
      }
    }
  },
  production: {
    addDevelopmentRoutes: false,
    addTestRoutes: false,
    errorLogger: Settings.lazy(function () {
      return errorLoggers.production({
        environment: this.ENV,
        revision: this['package'].version
      });
    }),
    updateProjectsImmediately: true,
    url: {
      internal: {
        protocol: 'http',
        hostname: 'localhost',
        port: 8080
      },
      external: {
        protocol: 'http',
        hostname: 'twolfson.com'
      }
    }
  }
});
<commit_msg>Fixing up dependency ordering<commit_after>// Load in dependencies
var numscale = require('numscale');
var Settings = require('shallow-settings');
var errorLoggers = require('./error-loggers');
var pkg = require('../package.json');

// Define our settings
module.exports = new Settings({
  common: {
    addDevelopmentRoutes: true,
    addTestRoutes: true,
    articles: Settings.lazy(function () {
      return require('../articles');
    }),
    'app.locals': Settings.lazy(function () {
      // TODO: This is very bad technique but models/projects is worse
      var projects = require('../server/models/projects');
      if (this.updateProjectsImmediately) {
        process.nextTick(global.updateProjects);
      }
      return {
        config: {
          author: 'Todd Wolfson',
          title: 'Todd Wolfson - Javascript Developer',
          url: 'http://twolfson.com/'
        },
        env: this.ENV,
        numscale: numscale.scale,
        projects: projects
      };
    }),
    // TODO: Restore common logger
    // errorLogger: Settings.lazy(function () {
    //   return errorLoggers.common();
    // }),
    errorLogger: Settings.lazy(function () {
      return errorLoggers.production({
        environment: this.ENV,
        revision: pkg.version
      });
    }),
    mail: Settings.lazy(function () {
      return require('./mail');
    }),
    'package': pkg,
    'support-me': {
      bitcoin: '1LVT8UpsgyKhGzN3TZxSKqqqd466NtZ99p',
      dogecoin: 'DGJQbYtSH8jau967XKUR7cpZ7jJEe9SPSQ',
      flattr: 'twolfsn',
      gittip: 'twolfson',
      paypal: {
        name: 'Todd Wolfson',
        email: 'todd@twolfson.com'
      },
    },
    updateProjectsImmediately: false,
    url: {
      internal: {
        protocol: 'http',
        hostname: 'localhost',
        port: 8080
      },
      external: {
        protocol: 'http',
        hostname: 'localhost',
        port: 8080
      }
    }
  },
  development: {
    // Same as common
  },
  test: {
    addDevelopmentRoutes: false,
    addTestRoutes: true,
    mail: {
      host: 'localhost',
      port: 1338
    },
    url: {
      internal: {
        protocol: 'http',
        hostname: 'localhost',
        port: 1337
      },
      external: {
        protocol: 'http',
        hostname: 'twolfson.test',
        port: 1337
      }
    }
  },
  production: {
    addDevelopmentRoutes: false,
    addTestRoutes: false,
    errorLogger: Settings.lazy(function () {
      return errorLoggers.production({
        environment: this.ENV,
        revision: pkg.version
      });
    }),
    updateProjectsImmediately: true,
    url: {
      internal: {
        protocol: 'http',
        hostname: 'localhost',
        port: 8080
      },
      external: {
        protocol: 'http',
        hostname: 'twolfson.com'
      }
    }
  }
});
<|endoftext|>


<commit_before>module.exports = {
    session: {
        secret: 'keyboard cat',
    },
}<commit_msg>added defaultChannel<commit_after>module.exports = {
    session: {
        secret: 'keyboard cat',
    },
    defaultChannel: 'general',
}<|endoftext|>


<commit_before>var https = require('https');
var zlib = require('zlib');
var fs = require('fs');
var google = require('googleapis');

var PROJECT_ID = 'PROJECT_ID';
var HOST = 'firebaseremoteconfig.googleapis.com';
var PATH = '/v1/projects/' + PROJECT_ID + '/remoteConfig';
var SCOPES = ['https://www.googleapis.com/auth/firebase.remoteconfig'];

/**
 * Get a valid access token.
 */
// [START retrieve_access_token]
function getAccessToken() {
  return new Promise(function(resolve, reject) {
    var key = require('./service-account.json');
    var jwtClient = new google.auth.JWT(
      key.client_email,
      null,
      key.private_key,
      SCOPES,
      null
    );
    jwtClient.authorize(function(err, tokens) {
      if (err) {
        reject(err);
        return;
      }
      resolve(tokens.access_token);
    });
  });
}
// [END retrieve_access_token]

/**
 * Retrieve the current Firebase Remote Config template from the server. Once
 * retrieved the template is stored locally in a file named `config.json`.
 */
function getTemplate() {
  getAccessToken().then(function(accessToken) {
    var options = {
      hostname: HOST,
      path: PATH,
      headers: {
        'Authorization': 'Bearer ' + accessToken,
        'Accept-Encoding': 'gzip',
      }
    };

    var buffer = [];
    var request = https.request(options, function(resp) {
      if (resp.statusCode == 200) {
        var gunzip = zlib.createGunzip();
        resp.pipe(gunzip);

        gunzip.on('data', function(data) {
          buffer.push(data.toString());
        }).on('end', function() {
          fs.writeFileSync('config.json', buffer.join(''));
          console.log('Retrieved template has been written to config.json');
          var etag = resp.headers['etag'];
          console.log('ETag from server: ' + etag);
        }).on('error', function(err) {
          console.error('Unable to decompress template.');
          console.error(err);
        });
      } else {
        console.log('Unable to get template.');
        console.log(resp.error);
      }
    });

    request.on('error', function(err) {
      console.log('Request for configuration template failed.');
      console.log(err);
    });

    request.end();
  });
}

/**
 * Print the last 5 available Firebase Remote Config template metadata from the server.
 */
function listVersions() {
  getAccessToken().then(function(accessToken) {
    const options = {
      hostname: HOST,
      path: PATH + ':listVersions?pageSize=5',
      method: 'GET',
      headers: {
        'Authorization': 'Bearer ' + accessToken,
      },
    };

    const request = https.request(options, function(resp) {
      if (resp.statusCode === 200) {
        console.log('Versions:');
        resp.on('data', function(data) {
          console.log(data.toString());
        });
      } else {
        resp.on('data', function(err) {
          console.log(err.toString());
        });
      }
    });

    request.on('error', function(err) {
      console.error('Request for template versions failed.');
      console.error(err.toString());
    });

    request.end();
  });
}

/**
 * Roll back to an available version of Firebase Remote Config template.
 *
 * @param version Version of the template to roll back to.
 */
function rollback(version) {
  getAccessToken().then(function(accessToken) {
    const options = {
      hostname: HOST,
      path: PATH + ':rollback',
      method: 'POST',
      headers: {
        'Authorization': 'Bearer ' + accessToken,
        'Content-Type': 'application/json; UTF-8',
        'Accept-Encoding': 'gzip',
      }
    };
    const request = https.request(options, function(resp) {
      const gunzip = zlib.createGunzip();
      resp.pipe(gunzip);

      if (resp.statusCode === 200) {
        gunzip.on('data', function(data) {
          console.log('Rolled back to: ' + version);
          console.log(data.toString());
          const newETag = resp.headers['etag'];
          console.log('ETag from server: ' + newETag);
        });
      } else {
        gunzip.on('data', function(data) {
          console.error(data.toString());
        });
      }
    });

    const rollbackVersion = {
      version_number: version
    };

    request.write(JSON.stringify(rollbackVersion));

    request.on('error', function(err) {
      console.error('Request to roll back to template: ' + version + ' failed.');
      console.error(err.toString());
    });

    request.end();
  });
}

/**
 * Publish the local template stored in `config.json` to the server.
 *
 * @param {String} etag ETag must be supplied when publishing a template. This is to
 *                      avoid race conditions when publishing.
 */
function publishTemplate(etag) {
  getAccessToken().then(function(accessToken) {
    var options = {
      hostname: HOST,
      path: PATH,
      method: 'PUT',
      headers: {
        'Authorization': 'Bearer ' + accessToken,
        'Content-Type': 'application/json; UTF-8',
        'Accept-Encoding': 'gzip',
        'If-Match': etag
      }
    };

    var request = https.request(options, function(resp) {
      if (resp.statusCode === 200) {
        var newETag = resp.headers['etag'];
        console.log('Template has been published');
        console.log('ETag from server: ' + newETag);
      } else {
        console.log('Unable to publish template.');
        console.log(resp.error);
      }
    });

    request.on('error', function(err) {
      console.log('Request to send configuration template failed.');
      console.log(err);
    });

    request.write(fs.readFileSync('config.json', 'UTF8'));
    request.end();
  });
}

const action = process.argv[2];
const etagOrVersion = process.argv[3];

if (action && action === 'get') {
  getTemplate();
} else if (action && action === 'publish' && etagOrVersion) {
  publishTemplate(etag);
} else if (action && action === 'versions') {
  listVersions();
} else if (action && action === 'rollback' && etagOrVersion) {
  rollback(etagOrVersion);
} else {
  console.log('Invalid command. Please use one of the following:\n'
      + 'node index.js get\n'
      + 'node index.js publish <LATEST_ETAG>\n'
      + 'node index.js versions\n'
      + 'node index.js rollback <TEMPLATE_VERSION_NUMBER>');
}
<commit_msg>change unassigned variable etag to etagOrVersion (#28)<commit_after>var https = require('https');
var zlib = require('zlib');
var fs = require('fs');
var google = require('googleapis');

var PROJECT_ID = 'PROJECT_ID';
var HOST = 'firebaseremoteconfig.googleapis.com';
var PATH = '/v1/projects/' + PROJECT_ID + '/remoteConfig';
var SCOPES = ['https://www.googleapis.com/auth/firebase.remoteconfig'];

/**
 * Get a valid access token.
 */
// [START retrieve_access_token]
function getAccessToken() {
  return new Promise(function(resolve, reject) {
    var key = require('./service-account.json');
    var jwtClient = new google.auth.JWT(
      key.client_email,
      null,
      key.private_key,
      SCOPES,
      null
    );
    jwtClient.authorize(function(err, tokens) {
      if (err) {
        reject(err);
        return;
      }
      resolve(tokens.access_token);
    });
  });
}
// [END retrieve_access_token]

/**
 * Retrieve the current Firebase Remote Config template from the server. Once
 * retrieved the template is stored locally in a file named `config.json`.
 */
function getTemplate() {
  getAccessToken().then(function(accessToken) {
    var options = {
      hostname: HOST,
      path: PATH,
      headers: {
        'Authorization': 'Bearer ' + accessToken,
        'Accept-Encoding': 'gzip',
      }
    };

    var buffer = [];
    var request = https.request(options, function(resp) {
      if (resp.statusCode == 200) {
        var gunzip = zlib.createGunzip();
        resp.pipe(gunzip);

        gunzip.on('data', function(data) {
          buffer.push(data.toString());
        }).on('end', function() {
          fs.writeFileSync('config.json', buffer.join(''));
          console.log('Retrieved template has been written to config.json');
          var etag = resp.headers['etag'];
          console.log('ETag from server: ' + etag);
        }).on('error', function(err) {
          console.error('Unable to decompress template.');
          console.error(err);
        });
      } else {
        console.log('Unable to get template.');
        console.log(resp.error);
      }
    });

    request.on('error', function(err) {
      console.log('Request for configuration template failed.');
      console.log(err);
    });

    request.end();
  });
}

/**
 * Print the last 5 available Firebase Remote Config template metadata from the server.
 */
function listVersions() {
  getAccessToken().then(function(accessToken) {
    const options = {
      hostname: HOST,
      path: PATH + ':listVersions?pageSize=5',
      method: 'GET',
      headers: {
        'Authorization': 'Bearer ' + accessToken,
      },
    };

    const request = https.request(options, function(resp) {
      if (resp.statusCode === 200) {
        console.log('Versions:');
        resp.on('data', function(data) {
          console.log(data.toString());
        });
      } else {
        resp.on('data', function(err) {
          console.log(err.toString());
        });
      }
    });

    request.on('error', function(err) {
      console.error('Request for template versions failed.');
      console.error(err.toString());
    });

    request.end();
  });
}

/**
 * Roll back to an available version of Firebase Remote Config template.
 *
 * @param version Version of the template to roll back to.
 */
function rollback(version) {
  getAccessToken().then(function(accessToken) {
    const options = {
      hostname: HOST,
      path: PATH + ':rollback',
      method: 'POST',
      headers: {
        'Authorization': 'Bearer ' + accessToken,
        'Content-Type': 'application/json; UTF-8',
        'Accept-Encoding': 'gzip',
      }
    };
    const request = https.request(options, function(resp) {
      const gunzip = zlib.createGunzip();
      resp.pipe(gunzip);

      if (resp.statusCode === 200) {
        gunzip.on('data', function(data) {
          console.log('Rolled back to: ' + version);
          console.log(data.toString());
          const newETag = resp.headers['etag'];
          console.log('ETag from server: ' + newETag);
        });
      } else {
        gunzip.on('data', function(data) {
          console.error(data.toString());
        });
      }
    });

    const rollbackVersion = {
      version_number: version
    };

    request.write(JSON.stringify(rollbackVersion));

    request.on('error', function(err) {
      console.error('Request to roll back to template: ' + version + ' failed.');
      console.error(err.toString());
    });

    request.end();
  });
}

/**
 * Publish the local template stored in `config.json` to the server.
 *
 * @param {String} etag ETag must be supplied when publishing a template. This is to
 *                      avoid race conditions when publishing.
 */
function publishTemplate(etag) {
  getAccessToken().then(function(accessToken) {
    var options = {
      hostname: HOST,
      path: PATH,
      method: 'PUT',
      headers: {
        'Authorization': 'Bearer ' + accessToken,
        'Content-Type': 'application/json; UTF-8',
        'Accept-Encoding': 'gzip',
        'If-Match': etag
      }
    };

    var request = https.request(options, function(resp) {
      if (resp.statusCode === 200) {
        var newETag = resp.headers['etag'];
        console.log('Template has been published');
        console.log('ETag from server: ' + newETag);
      } else {
        console.log('Unable to publish template.');
        console.log(resp.error);
      }
    });

    request.on('error', function(err) {
      console.log('Request to send configuration template failed.');
      console.log(err);
    });

    request.write(fs.readFileSync('config.json', 'UTF8'));
    request.end();
  });
}

const action = process.argv[2];
const etagOrVersion = process.argv[3];

if (action && action === 'get') {
  getTemplate();
} else if (action && action === 'publish' && etagOrVersion) {
  publishTemplate(etagOrVersion);
} else if (action && action === 'versions') {
  listVersions();
} else if (action && action === 'rollback' && etagOrVersion) {
  rollback(etagOrVersion);
} else {
  console.log('Invalid command. Please use one of the following:\n'
      + 'node index.js get\n'
      + 'node index.js publish <LATEST_ETAG>\n'
      + 'node index.js versions\n'
      + 'node index.js rollback <TEMPLATE_VERSION_NUMBER>');
}
<|endoftext|>


<commit_before>// Template version: 1.3.1
// see http://vuejs-templates.github.io/webpack for documentation.

const path = require("path");

module.exports = {
    dev: {

        // Paths
        assetsSubDirectory: "static",
        assetsPublicPath: "/",
        proxyTable: {},

        // Various Dev Server settings
        host: "localhost", // can be overwritten by process.env.HOST
        port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
        autoOpenBrowser: false,
        errorOverlay: true,
        notifyOnErrors: true,
        poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-

        // Use Eslint Loader?
        // If true, your code will be linted during bundling and
        // linting errors and warnings will be shown in the console.
        useEslint: true,
        // If true, eslint errors and warnings will also be shown in the error overlay
        // in the browser.
        showEslintErrorsInOverlay: false,

        /**
     * Source Maps
     */

        // https://webpack.js.org/configuration/devtool/#development
        devtool: "cheap-module-eval-source-map",

        // If you have problems debugging vue-files in devtools,
        // set this to false - it *may* help
        // https://vue-loader.vuejs.org/en/options.html#cachebusting
        cacheBusting: true,

        cssSourceMap: true
    },

    build: {
    // Template for index.html
        index: path.resolve(__dirname, "../dist/index.html"),

        // Paths
        assetsRoot: path.resolve(__dirname, "../dist"),
        assetsSubDirectory: "static",
        assetsPublicPath: "/",

        /**
     * Source Maps
     */

        productionSourceMap: true,
        // https://webpack.js.org/configuration/devtool/#production
        devtool: "#source-map",

        // Gzip off by default as many popular static hosts such as
        // Surge or Netlify already gzip all static assets for you.
        // Before setting to `true`, make sure to:
        // npm install --save-dev compression-webpack-plugin
        productionGzip: false,
        productionGzipExtensions: ["js", "css"],

        // Run the build command with an extra argument to
        // View the bundle analyzer report after build finishes:
        // `npm run build --report`
        // Set to `true` or `false` to always turn it on or off
        bundleAnalyzerReport: process.env.npm_config_report
    }
};
<commit_msg>🔌 Proxy API requests to Datasette DB on 8081<commit_after>// Template version: 1.3.1
// see http://vuejs-templates.github.io/webpack for documentation.

const path = require("path");

module.exports = {
    dev: {

        // Paths
        assetsSubDirectory: "static",
        assetsPublicPath: "/",
        proxyTable: {
            "/api": {
                target: "http://localhost:8081",
                changeOrigin: true,
                pathRewrite: {
                    "^/api": ""
                }
            }
        },

        // Various Dev Server settings
        host: "localhost", // can be overwritten by process.env.HOST
        port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
        autoOpenBrowser: false,
        errorOverlay: true,
        notifyOnErrors: true,
        poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-

        // Use Eslint Loader?
        // If true, your code will be linted during bundling and
        // linting errors and warnings will be shown in the console.
        useEslint: true,
        // If true, eslint errors and warnings will also be shown in the error overlay
        // in the browser.
        showEslintErrorsInOverlay: false,

        /**
     * Source Maps
     */

        // https://webpack.js.org/configuration/devtool/#development
        devtool: "cheap-module-eval-source-map",

        // If you have problems debugging vue-files in devtools,
        // set this to false - it *may* help
        // https://vue-loader.vuejs.org/en/options.html#cachebusting
        cacheBusting: true,

        cssSourceMap: true
    },

    build: {
    // Template for index.html
        index: path.resolve(__dirname, "../dist/index.html"),

        // Paths
        assetsRoot: path.resolve(__dirname, "../dist"),
        assetsSubDirectory: "static",
        assetsPublicPath: "/",

        /**
     * Source Maps
     */

        productionSourceMap: true,
        // https://webpack.js.org/configuration/devtool/#production
        devtool: "#source-map",

        // Gzip off by default as many popular static hosts such as
        // Surge or Netlify already gzip all static assets for you.
        // Before setting to `true`, make sure to:
        // npm install --save-dev compression-webpack-plugin
        productionGzip: false,
        productionGzipExtensions: ["js", "css"],

        // Run the build command with an extra argument to
        // View the bundle analyzer report after build finishes:
        // `npm run build --report`
        // Set to `true` or `false` to always turn it on or off
        bundleAnalyzerReport: process.env.npm_config_report
    }
};
<|endoftext|>


<commit_before>module.exports = {
  service: {
    name: 'melodies',
    synopsis: 'thoughts from soundtrack.io',
    icon: 'music'
  },
  database: {
    name: 'blog:soundtrack'
  }
};
<commit_msg>Change port number for production.<commit_after>module.exports = {
  service: {
    name: 'melodies',
    synopsis: 'thoughts from soundtrack.io',
    icon: 'music'
  },
  database: {
    name: 'blog:soundtrack'
  },
  services: {
    http: {
      port: 13005
    }
  }
};
<|endoftext|>


<commit_before> /*******************************************************************************************
  * Mafia Variables *************************************************************************
  ******************************************************************************************/

// Welcome to the code for mafia. This mainly functions on 2 general objects, mafia and user.mafia.

var mafia = exports.mafia = {
	// Initializing variables
	gameRunning : false,
	gameStarting : false,
	daytime : false,
	nighttime : false,
	votingphase : false,
	players : [],
	mafiaThemes : JSON.parse(fs.readFileSync('config/mafiathemes.json')),
	theme : {},
	timer : setTimeout(function(){},0),
	// Modify this pathway to change the mafia room.
	room : require('../rooms.js').rooms.mafia,

	// Major game functions
	// Function for shuffling player list. Got off of StackOverflow because lazy.
	shuffle : function(array) {
		var currentIndex = array.length,temporaryValue,randomIndex;

		// While there remain elements to shuffle...
		while (0 !== currentIndex) {

			// Pick a remaining element...
			randomIndex = Math.floor(Math.random() * currentIndex);
			currentIndex -= 1;

			// And swap it with the current element.
			temporaryValue = array[currentIndex];
			array[currentIndex] = array[randomIndex];
			array[randomIndex] = temporaryValue;
		}

		return array;
	},

	gameSignUp : function(user, theme) {
		mafia.theme = mafia.mafiaThemes[theme];
		room.add(user + ' has started a new mafia game with theme ' + mafa.theme.name);
		room.add('Type //mjoin to join the game.');
		// If the theme has a summary, it will be posted.
		if ('summary' in mafia.theme) {
			room.add(mafia.theme.summary);
		}
		// Comment this line out to prevent broadcasting to lobby.
		require('../rooms.js').rooms.lobby.add('A new mafia game is starting. Join tervari.psim.us/mafia and type /mjoin to join.');
		// Begin the countdown to gameStart.
		mafia.timer = setTimeout(function() {room.add('Hurry up! Only 30 seconds remaining to join.'); setTimeout(mafia.gameStart, 30000);}, 30000);
	}
};

	/*********************************************************
	 * Mafia commands
	 *********************************************************/

var commands = exports.commands = {

	mstart: function(target, room, user, connection) {
		// Make sure the user isn't doing something they aren't supposed to be doing.
		if (room !== mafia.room) { return; }
		if (!this.canTalk()) {
			return this.sendReply('You cannot start a mafia game because you are muted.');
		}
		if (mafia.gameRunning) {
			return this.sendReply('A game is currently being played. Use /mjoin to join the next game.');
		}
		if (mafia.gameStarting) {
			return this.sendReply('A game is currently in its sign-up phase. Use /mjoin to join.');
		}
		// Theme defaults to default (surprise).
		if (!target) {
			target = 'default';
		}
		if (!(target in mafia.mafiaThemes)) {
			return this.sendReply('The theme ' + target + ' does not exist.');
		}
		// And begin the sign-ups!
		mafia.gameStarting = true;
		mafia.gameSignUp(user, target);
	},

	mjoin: function(target, room, user, connection) {
		// Make sure the user isn't doing something they aren't supposed to be doing.

	}
};
<commit_msg>Finish mjoin<commit_after> /*******************************************************************************************
  * Mafia Variables *************************************************************************
  ******************************************************************************************/

// Welcome to the code for mafia. This mainly functions on 2 general objects, mafia and user.mafia.

var mafia = exports.mafia = {
	// Initializing variables
	gameRunning : false,
	gameStarting : false,
	daytime : false,
	nighttime : false,
	votingphase : false,
	players : [],
	mafiaThemes : JSON.parse(fs.readFileSync('config/mafiathemes.json')),
	theme : {},
	timer : setTimeout(function(){},0),
	maxPlayers : 0,
	// Modify this pathway to change the mafia room.
	room : require('../rooms.js').rooms.mafia,

	// Major game functions
	// Function for shuffling player list. Got off of StackOverflow because lazy.
	shuffle : function(array) {
		var currentIndex = array.length,temporaryValue,randomIndex;

		// While there remain elements to shuffle...
		while (0 !== currentIndex) {

			// Pick a remaining element...
			randomIndex = Math.floor(Math.random() * currentIndex);
			currentIndex -= 1;

			// And swap it with the current element.
			temporaryValue = array[currentIndex];
			array[currentIndex] = array[randomIndex];
			array[randomIndex] = temporaryValue;
		}

		return array;
	},

	gameSignUp : function(user, theme) {
		mafia.theme = mafia.mafiaThemes[theme];
		// Determine the maximum number of players for the theme.
		var rolesListNum = 1;
		while (('roles' + rolesListNum) in mafia.theme) {
			rolesListNum++;
		}
		mafia.maxPlayers = mafia.theme['roles' + (rolesListNum-1)];
		// Announce the game.
		room.add(user + ' has started a new mafia game with theme ' + mafa.theme.name);
		room.add('Type //mjoin to join the game.');
		// If the theme has a summary, it will be posted.
		if ('summary' in mafia.theme) {
			room.add(mafia.theme.summary);
		}
		// Comment this line out to prevent broadcasting to lobby.
		require('../rooms.js').rooms.lobby.add('A new mafia game is starting. Join tervari.psim.us/mafia and type /mjoin to join.');
		// Begin the countdown to gameStart.
		mafia.timer = setTimeout(function() {room.add('Hurry up! Only 30 seconds remaining to join.'); setTimeout(mafia.gameStart, 30000);}, 30000);
	}
};

	/*********************************************************
	 * Mafia commands
	 *********************************************************/

var commands = exports.commands = {

	mstart: function(target, room, user, connection) {
		// Make sure the user isn't doing something they aren't supposed to be doing.
		if (room !== mafia.room) { return; }
		if (!this.canTalk()) {
			return this.sendReply('You cannot start a mafia game because you are muted.');
		}
		if (mafia.gameRunning) {
			this.sendReply('A game is currently being played.');
			return this.sendReply('Wait until the game is over to start a new one.');
		}
		if (mafia.gameStarting) {
			this.sendReply('A game is currently in its sign-up phase.');
			return this.sendReply('Type /mjoin to join.');
		}
		// Theme defaults to default (surprise).
		if (!target) {
			target = 'default';
		}
		if (!(target in mafia.mafiaThemes)) {
			return this.sendReply('The theme ' + target + ' does not exist.');
		}
		// And begin the sign-ups!
		mafia.gameStarting = true;
		mafia.gameSignUp(user, target);
	},

	mjoin: function(target, room, user, connection) {
		// Make sure the user isn't doing something they aren't supposed to be doing.
		if (room !== mafia.room) { return; }
		if (!this.canTalk()) {
			return this.sendReply('You cannot join the mafia game because you are muted.');
		}
		if (mafia.gameRunning) {
			this.sendReply('A game is currently being played.');
			return this.sendReply('Use /mjoin to join the next game.');
		}
		if (!mafia.gameStarting) {
			this.sendReply('There is no mafia game in its Sign-Up phase right now.');
			return this.sendReply('Type /mstart to start a new game.');
		}
		if (mafia.players.indexOf(user) !== -1) {
			return this.sendReply('You have already joined the current game.');
		}
		mafia.players.push(user);
		this.sendReply('You have joined the mafia game.');
		if (mafia.players.length >== mafia.maxPlayers) {
			return room.add('Sign-Ups have closed.');
		}
		return;
	}
};
<|endoftext|>


<commit_before>/*
	ActionManager
*/
"use strict";

var KEY = require('../opts/keys.js'),
	PointerTracker = require('./pointerTracker.js'),
	Action = require('../bits/action.js'),
	utils = require('../utils/utils.js'),
	ActionManager = function () {},
	actionManager,
	allActions = [],
	activeTokens = [],
	deactivateQueue = [],
	baseActions = {};

ActionManager.prototype = {

	/*
		Create action

		@return [Action]
	*/
	create: function () {
		var action = new Action();

		this.register(action);

		return action;
	},

	/*
		Change action

		@param [Token]: Token for the action
		@param [object]: Value properties
		@param [object]: Action options
	*/
	change: function (token, changes, e) {
		var action = this.get(token);

        if (changes.link === KEY.LINK.POINTER) {
			changes.pointerOffset = PointerTracker.start(e);
        }

		action.set(changes);
	},

	/*
		Define a base action

		Can be called later with .play()

		@param [object]
	*/
	define: function (actions) {
		var key,
			chain,
			baseAction = {};

		for (key in actions) {
			if (actions.hasOwnProperty(key)) {
				if (baseActions[key] && !actions[key].forceOverride) {
					throw KEY.ERROR.ACTION_EXISTS;
				} else {
					chain = key.split('.');

					// If there's an inheritence chain, merge
					// TODO: multilayered inheritence?
					if (chain.length > 1) {
						if (baseActions[chain[0]]) {
							baseActions[key] = utils.merge(baseActions[chain[0]], actions[key]);
						// if we can't find action
						} else {
							throw KEY.ERROR.NO_ACTION;
						}
					// Else directly copy
					} else {
						baseActions[key] = actions[key];
					}
				}
			}
		}
	},

	/*
    	Create base action

    	@param [string || array || object]:
    	    String: Name or space-delimited playlist of actions
    	    Array: Playlist of actions
    	    Object: Raw action
        @param [object]: Action override
	*/
	createBase: function (defs, override) {
    	var baseAction = {},
    	    actionList = [];

        // If this is a straight action
        if (utils.isObj(defs)) {
            baseAction = defs;

        // These are previously defined actions
        } else {
            // Comma-delimited string or single action name
            if (utils.isString(defs)) {
                actionList = defs.split(" ");

            // Array of action names
            } else {
                actionList = defs;
            }

            baseAction = this.getDefined(actionList[0]);
            baseAction.playlist = actionList;
            baseAction.playCurrent = 0;
        }

        // Apply overrides if present
        if (utils.isObj(override)) {
            baseAction = utils.merge(baseAction, override);
        }

        return baseAction;
	},

	/*
    	Get defined action

    	@param [string]: The name of the predefined action
	*/
	getDefined: function (key) {
		return utils.copy(baseActions[key]);
	},

	/*
		Register action

		@param [Action]: Add action to storage array
	*/
	register: function (action) {
		allActions[action.token] = action;
	},

	/*
		Get the specified action

		@param [Token]: Token
		@return [Action || boolean]: Action with specified token, false if none found
	*/
	get: function (token) {
		return allActions[token] || false;
	},

	/*
    	Get tokens of all active actions

    	@return [array]: Array of active tokens
	*/
	getActiveTokens: function () {
    	return activeTokens;
	},

	/*
    	Activate specified action

    	Activates action and adds to activeTokens array

    	@param [Token]: Token
	*/
	activate: function (token) {
    	var action = this.get(token),
	        index = activeTokens.indexOf(token),
	        deactivateIndex = deactivateQueue.indexOf(token);

    	if (index === -1) {
            activeTokens.push(token);
        }

        // Remove from deactivate queue if it's been placed there
        if (deactivateIndex >= 0) {
            deactivateQueue.splice(deactivateIndex, 1);
        }

    	action.start();
	},

	/*
    	Deactivate specified action

    	Activates action and removes from activeTokens array

    	@param [Token]: Token
	*/
	deactivate: function (token) {
    	var action = this.get(token),
	        index = activeTokens.indexOf(token);

	    action.stop();

    	if (index > -1) {
    	    activeTokens.splice(index, 1);
    	}
	},

	/*
    	Purge deactivate queue

    	Loops through the deactivate queue and decides whether to deactivate
    	or swap action parameters with the next in the action's playList

    	We use a deactivate queue rather than deactivate as soon as we process it
    	because if we manipulate the list of activated Actions while it's being
    	looped through, well you can only imagine the fun that causes.
	*/
	purge: function () {
		var nextInPlaylist,
			queueLength = deactivateQueue.length;

		for (var i = 0; i < queueLength; ++i) {
			nextInPlaylist = this.getNextInPlaylist(deactivateQueue[i]);

			if (!nextInPlaylist) {
			    if (utils.isNum(deactivateQueue[i])) {
    			    this.deactivate(deactivateQueue[i]);
			    }
			} else {
    			this.change(deactivateQueue[i], nextInPlaylist);
    			this.activate(deactivateQueue[i]);
			}
		}

		deactivateQueue = [];
	},

	/*
    	Add token to the deactivate queue

    	Queue gets processed at the end of every frame

    	@param [Token]: Token of action
	*/
	queueDeactivate: function (token) {
		deactivateQueue.push(token);
	},

	/*
    	Get next item in playlist, or return false if none

    	@param [Token]: Token of action
	*/
	getNextInPlaylist: function (token) {
    	var nextInPlaylist = false,
    	    action = this.get(token),
    	    playlistLength = action.playlist ? action.playlist.length : 0;

    	if (playlistLength && action.link === KEY.LINK.TIME) {
        	if (action.playCurrent < playlistLength - 1) {
            	action.playCurrent++;
            	nextInPlaylist = this.getDefined(action.playlist[action.playCurrent]);
        	}
    	}

    	return nextInPlaylist;
	},

	getData: function (token, key) {
	    var action = this.get(token);

    	return action.data ? action.data[key] : undefined;
	},

	setData: function (token, data) {
    	var action = this.get(token);

    	for (var key in data) {
        	if (data.hasOwnProperty(key)) {
            	action.data[key] = data[key];

            	if (key === KEY.JQUERY_ELEMENT) {
                	action.data = data[key];
            	}
        	}
    	}
	}
};

actionManager = new ActionManager();

module.exports = actionManager;<commit_msg>adding loop and play stubs<commit_after>/*
	ActionManager
*/
"use strict";

var KEY = require('../opts/keys.js'),
	PointerTracker = require('./pointerTracker.js'),
	Action = require('../bits/action.js'),
	utils = require('../utils/utils.js'),
	ActionManager = function () {},
	actionManager,
	allActions = [],
	activeTokens = [],
	deactivateQueue = [],
	baseActions = {};

ActionManager.prototype = {

	/*
		Create action

		@return [Action]
	*/
	create: function () {
		var action = new Action();

		this.register(action);

		return action;
	},

	/*
		Change action

		@param [Token]: Token for the action
		@param [object]: Value properties
		@param [object]: Action options
	*/
	change: function (token, changes, e) {
		var action = this.get(token);

        if (changes.link === KEY.LINK.POINTER) {
			changes.pointerOffset = PointerTracker.start(e);
        }

		action.set(changes);
	},

	/*
		Define a base action

		Can be called later with .play()

		@param [object]
	*/
	define: function (actions) {
		var key,
			chain,
			baseAction = {};

		for (key in actions) {
			if (actions.hasOwnProperty(key)) {
				if (baseActions[key] && !actions[key].forceOverride) {
					throw KEY.ERROR.ACTION_EXISTS;
				} else {
					chain = key.split('.');

					// If there's an inheritence chain, merge
					// TODO: multilayered inheritence?
					if (chain.length > 1) {
						if (baseActions[chain[0]]) {
							baseActions[key] = utils.merge(baseActions[chain[0]], actions[key]);
						// if we can't find action
						} else {
							throw KEY.ERROR.NO_ACTION;
						}
					// Else directly copy
					} else {
						baseActions[key] = actions[key];
					}
				}
			}
		}
	},

	/*
    	Create base action

    	@param [string || array || object]:
    	    String: Name or space-delimited playlist of actions
    	    Array: Playlist of actions
    	    Object: Raw action
        @param [object]: Action override
	*/
	createBase: function (defs, override) {
    	var baseAction = {},
    	    actionList = [];

        // If this is a straight action
        if (utils.isObj(defs)) {
            baseAction = defs;

        // These are previously defined actions
        } else {
            // Comma-delimited string or single action name
            if (utils.isString(defs)) {
                actionList = defs.split(" ");

            // Array of action names
            } else {
                actionList = defs;
            }

            baseAction = this.getDefined(actionList[0]);
            baseAction.playlist = actionList;
            baseAction.playCurrent = 0;
        }

        // Apply overrides if present
        if (utils.isObj(override)) {
            baseAction = utils.merge(baseAction, override);
        }

        return baseAction;
	},

	/*
    	Get defined action

    	@param [string]: The name of the predefined action
	*/
	getDefined: function (key) {
		return utils.copy(baseActions[key]);
	},

	/*
		Register action

		@param [Action]: Add action to storage array
	*/
	register: function (action) {
		allActions[action.token] = action;
	},

	/*
		Get the specified action

		@param [Token]: Token
		@return [Action || boolean]: Action with specified token, false if none found
	*/
	get: function (token) {
		return allActions[token] || false;
	},

	/*
    	Get tokens of all active actions

    	@return [array]: Array of active tokens
	*/
	getActiveTokens: function () {
    	return activeTokens;
	},

	/*
    	Activate specified action

    	Activates action and adds to activeTokens array

    	@param [Token]: Token
	*/
	activate: function (token) {
    	var action = this.get(token),
	        index = activeTokens.indexOf(token),
	        deactivateIndex = deactivateQueue.indexOf(token);

    	if (index === -1) {
            activeTokens.push(token);
        }

        // Remove from deactivate queue if it's been placed there
        if (deactivateIndex >= 0) {
            deactivateQueue.splice(deactivateIndex, 1);
        }

    	action.start();
	},

	/*
    	Deactivate specified action

    	Activates action and removes from activeTokens array

    	@param [Token]: Token
	*/
	deactivate: function (token) {
    	var action = this.get(token),
	        index = activeTokens.indexOf(token);

	    action.stop();

    	if (index > -1) {
    	    activeTokens.splice(index, 1);
    	}
	},

	/*
    	Purge deactivate queue

    	Loops through the deactivate queue and decides whether to deactivate
    	or swap action parameters with the next in the action's playList

    	We use a deactivate queue rather than deactivate as soon as we process it
    	because if we manipulate the list of activated Actions while it's being
    	looped through, well you can only imagine the fun that causes.
	*/
	purge: function () {
	    var queueLength = deactivateQueue.length;

	    // Run through all queued actions and decide what to do next
	    for (var i = 0; i < queueLength; ++i) {
	        if (utils.isNum(deactivateQueue[i])) {
    	        this.decideNext(deactivateQueue[i]);
	        }
	    }

        // Clear deactivateQueue
		deactivateQueue = [];
	},

	/*
    	Decide what to do with an action

    	Takes an action and decides, based on its playlist and loop properties,
    	what to do with it next.

    	@param [Token]: Action token
	*/
	decideNext: function (token) {
    	if (!this.loop(token) && !this.playNext(token)) {
        	this.deactivate(token);
    	}
	},

	/*
    	Play next in playlist, if exists

    	@param [Token]: Action token
    	@return [boolean]: Success
	*/
	playNext: function (token) {
    	var hasPlayedNext = false;

    	return hasPlayedNext;
	},

	/*
    	Loop current action, if we're that way inclined

    	@param [Token]: Action token
    	@return [boolean]: Success
	*/
	loop: function (token) {
    	var hasLooped = false;

    	return hasLooped;
	},

	/*
		/*
			nextInPlaylist = this.getNextInPlaylist(deactivateQueue[i]);

            // If there's nothing in the play list
			if (!nextInPlaylist) {
			    if (utils.isNum(deactivateQueue[i])) {
    			    this.deactivate(deactivateQueue[i]);
			    }
			} else {
    			this.change(deactivateQueue[i], nextInPlaylist);
    			this.activate(deactivateQueue[i]);
			}
		*/

	/*
    	Add token to the deactivate queue

    	Queue gets processed at the end of every frame

    	@param [Token]: Token of action
	*/
	queueDeactivate: function (token) {
		deactivateQueue.push(token);
	},

	/*
    	Get next item in playlist, or return false if none

    	@param [Token]: Token of action
	*/
	getNextInPlaylist: function (token) {
    	var nextInPlaylist = false,
    	    action = this.get(token),
    	    playlistLength = action.playlist ? action.playlist.length : 0;

    	if (playlistLength && action.link === KEY.LINK.TIME) {
        	if (action.playCurrent < playlistLength - 1) {
            	action.playCurrent++;
            	nextInPlaylist = this.getDefined(action.playlist[action.playCurrent]);
        	}
    	}

    	return nextInPlaylist;
	},

	/*
    	Get data from our action's data object

    	@param [Token]: Action token
    	@param [string]: Key of data point
	*/
	getData: function (token, key) {
	    var action = this.get(token);

    	return action.data ? action.data[key] : undefined;
	},

	/*
    	Set data point to action's data object

    	@param [Token]: Action token
    	@param [object]: Data to save to action
	*/
	setData: function (token, data) {
    	var action = this.get(token);

    	for (var key in data) {
        	if (data.hasOwnProperty(key)) {
            	action.data[key] = data[key];

            	if (key === KEY.JQUERY_ELEMENT) {
                	action.data = data[key];
            	}
        	}
    	}
	}
};

actionManager = new ActionManager();

module.exports = actionManager;<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @flow
 */

import * as cache from './cache.js';
export {cache};

import * as ls from './ls.js';
export {ls};

import * as why from './why.js';
export {why};

import * as access from './access.js';
export {access};

import * as add from './add.js';
export {add};

import * as clean from './clean.js';
export {clean};

import * as config from './config.js';
export {config};

import * as team from './team.js';
export {team};

import * as link from './link.js';
export {link};

import * as outdated from './outdated.js';
export {outdated};

import * as pack from './pack.js';
export {pack};

import * as owner from './owner.js';
export {owner};

import * as distTag from './dist-tag.js';
export {distTag};

import * as publish from './publish.js';
export {publish};

import * as login from './login.js';
export {login};

import * as logout from './logout.js';
export {logout};

import * as licenses from './licenses.js';
export {licenses};

import * as selfUpdate from './self-update.js';
export {selfUpdate};

import * as uninstall from './uninstall.js';
export {uninstall};

import * as install from './install.js';
export {install};

import * as upgrade from './upgrade.js';
export {upgrade};

import * as check from './check.js';
export {check};

import buildUseless from './_useless.js';

export let version = buildUseless(
  'Use `kpm --version` instead of `kpm version`',
);

export let runScript = buildUseless(
  'Use `kpm <script-name>` instead of `kpm run-script <script-name>`',
);

export let lockfile = buildUseless(
  "The lockfile command isn't necessary. `kpm install` will produce a lockfile.",
);

export let dedupe = buildUseless(
  "The dedupe command isn't necessary. `kpm install` will already dedupe.",
);

export let prune = buildUseless(
  "The prune command isn't necessary. `kpm install` will prune extraneous packages.",
);
<commit_msg>Add version command (#294)<commit_after>/**
 * Copyright (c) 2016-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @flow
 */

import * as cache from './cache.js';
export {cache};

import * as ls from './ls.js';
export {ls};

import * as why from './why.js';
export {why};

import * as access from './access.js';
export {access};

import * as add from './add.js';
export {add};

import * as clean from './clean.js';
export {clean};

import * as config from './config.js';
export {config};

import * as team from './team.js';
export {team};

import * as link from './link.js';
export {link};

import * as outdated from './outdated.js';
export {outdated};

import * as pack from './pack.js';
export {pack};

import * as owner from './owner.js';
export {owner};

import * as distTag from './dist-tag.js';
export {distTag};

import * as publish from './publish.js';
export {publish};

import * as login from './login.js';
export {login};

import * as logout from './logout.js';
export {logout};

import * as licenses from './licenses.js';
export {licenses};

import * as selfUpdate from './self-update.js';
export {selfUpdate};

import * as uninstall from './uninstall.js';
export {uninstall};

import * as install from './install.js';
export {install};

import * as upgrade from './upgrade.js';
export {upgrade};

import * as check from './check.js';
export {check};

import * as version from './version.js';
export {version};

import buildUseless from './_useless.js';

export let runScript = buildUseless(
  'Use `kpm <script-name>` instead of `kpm run-script <script-name>`',
);

export let lockfile = buildUseless(
  "The lockfile command isn't necessary. `kpm install` will produce a lockfile.",
);

export let dedupe = buildUseless(
  "The dedupe command isn't necessary. `kpm install` will already dedupe.",
);

export let prune = buildUseless(
  "The prune command isn't necessary. `kpm install` will prune extraneous packages.",
);
<|endoftext|>


<commit_before>import Activity from './Activity';
import serviceManager from './serviceManager';
import viewManager from './viewManager';
import socket from './socket';
// import defaultViewContent from '../config/defaultViewContent';
// import defaultViewTemplates from '../config/defaultViewTemplates';
import viewport from '../views/viewport';

/**
 * Client side entry point for a `soundworks` application.
 *
 * This object hosts general informations about the user, as well as methods
 * to initialize and start the application.
 *
 * @memberof module:soundworks/client
 * @namespace
 *
 * @example
 * import * as soundworks from 'soundworks/client';
 * import MyExperience from './MyExperience';
 *
 * soundworks.client.init('player');
 * const myExperience = new MyExperience();
 * soundworks.client.start();
 */
const client = {
  /**
   * Unique id of the client, generated and retrieved by the server.
   *
   * @type {Number}
   */
  uuid: null,

  /**
   * The type of the client, this can generally be considered as the role of the
   * client in the application. This value is defined in the
   * [`client.init`]{@link module:soundworks/server.server~serverConfig} object
   * and defaults to `'player'`.
   *
   * @type {String}
   */
  type: null,

  /**
   * Configuration informations from the server configuration if any.
   *
   * @type {Object}
   * @see {@link module:soundworks/client.client~init}
   * @see {@link module:soundworks/client.SharedConfig}
   */
  config: {},

  /**
   * Array of optionnal parameters passed through the url
   *
   * @type {Array}
   */
   urlParams: null,

  /**
   * Information about the client platform. The properties are set by the
   * [`platform`]{@link module:soundworks/client.Platform} service.
   *
   * @type {Object}
   * @property {String} os - Operating system.
   * @property {Boolean} isMobile - Indicates whether the client is running on a
   *  mobile platform or not.
   * @property {String} audioFileExt - Audio file extension to use, depending on
   *  the platform.
   * @property {String} interaction - Type of interaction allowed by the
   *  viewport, `touch` or `mouse`
   *
   * @see {@link module:soundworks/client.Platform}
   */
  platform: {
    os: null,
    isMobile: null,
    audioFileExt: '',
    interaction: null,
  },

  /**
   * Defines whether the user's device is compatible with the application
   * requirements.
   *
   * @type {Boolean}
   * @see {@link module:soundworks/client.Platform}
   */
  compatible: null,

  /**
   * Index (if any) given by a [`placer`]{@link module:soundworks/client.Placer}
   * or [`checkin`]{@link module:soundworks/client.Checkin} service.
   *
   * @type {Number}
   * @see {@link module:soundworks/client.Checkin}
   * @see {@link module:soundworks/client.Placer}
   */
  index: null,

  /**
   * Ticket label (if any) given by a [`placer`]{@link module:soundworks/client.Placer}
   * or [`checkin`]{@link module:soundworks/client.Checkin} service.
   *
   * @type {String}
   * @see {@link module:soundworks/client.Checkin}
   * @see {@link module:soundworks/client.Placer}
   */
  label: null,

  /**
   * Client coordinates (if any) given by a
   * [`locator`]{@link module:soundworks/client.Locator},
   * [`placer`]{@link module:soundworks/client.Placer} or
   * [`checkin`]{@link module:soundworks/client.Checkin} service.
   * (Format: `[x:Number, y:Number]`.)
   *
   * @type {Array<Number>}
   * @see {@link module:soundworks/client.Checkin}
   * @see {@link module:soundworks/client.Locator}
   * @see {@link module:soundworks/client.Placer}
   * @see {@link module:soundworks/client.Geolocation}
   */
  coordinates: null,

  /**
   * Full `geoposition` object as returned by `navigator.geolocation`, when
   * using the `geolocation` service.
   *
   * @type {Object}
   * @see {@link module:soundworks/client.Geolocation}
   */
  geoposition: null,

  /**
   * Socket object that handle communications with the server, if any.
   * This object is automatically created if the experience requires any service
   * having a server-side counterpart.
   *
   * @type {module:soundworks/client.socket}
   * @private
   */
  socket: socket,

  /**
   * Initialize the application.
   *
   * @param {String} [clientType='player'] - The type of the client, defines the
   *  socket connection namespace. Should match a client type defined server side.
   * @param {Object} [config={}]
   * @param {Object} [config.appContainer='#container'] - A css selector
   *  matching a DOM element where the views should be inserted.
   * @param {Object} [config.websockets.url=''] - The url where the socket should
   *  connect _(unstable)_.
   * @param {Object} [config.websockets.transports=['websocket']] - The transport
   *  used to create the url (overrides default socket.io mecanism) _(unstable)_.
   */
  init(clientType = 'player', config = {}) {
    this.type = clientType;

    this._parseUrlParams();
    // if socket config given, mix it with defaults
    const websockets = Object.assign({
      url: '',
      transports: ['websocket'],
      path: '',
    }, config.websockets);

    // mix all other config and override with defined socket config
    Object.assign(this.config, config, { websockets });

    serviceManager.init();
    viewport.init();

    const el = config.appContainer;
    const $container = el instanceof Element ? el : document.querySelector(el);
    viewManager.setAppContainer($container);

    return Promise.resolve();
  },

  /**
   * Register a function to be executed when a service is instanciated.
   *
   * @param {serviceManager~serviceInstanciationHook} func - Function to
   *  register has a hook to be execute when a service is created.
   */
  /**
   * @callback serviceManager~serviceInstanciationHook
   * @param {String} id - id of the instanciated service.
   * @param {Service} instance - instance of the service.
   */
  setServiceInstanciationHook(func) {
    serviceManager.setServiceInstanciationHook(func);
  },

  /**
   * Start the application.
   */
  start() {
    if (socket.required)
      this._initSocket();
    else
      serviceManager.start();
  },

  /**
   * Returns a service configured with the given options.
   * @param {String} id - Identifier of the service.
   * @param {Object} options - Options to configure the service.
   */
  require(id, options) {
    return serviceManager.require(id, options);
  },

  /**
   * Retrieve an array of optionnal parameters from the url excluding the client type
   * and store it in `this.urlParams`.
   * Parameters can be defined in two ways :
   * - as a regular route (ex: `/player/param1/param2`)
   * - as a hash (ex: `/player#param1-param2`)
   * The parameters are send along with the socket connection
   *
   * @see {@link module:soundworks/client.socket}
   * @private
   * @todo - When handshake implemented, define if these informations should be part of it
   */
  _parseUrlParams() {
    let pathParams = null;
    let hashParams = null;
    // handle path name first
    let pathname = window.location.pathname;
    // sanitize
    pathname = pathname
      .replace(/^\//, '')                               // leading slash
      .replace(new RegExp('^' + this.type + '/?'), '')  // remove clientType
      .replace(/\/$/, '');                              // trailing slash

    if (pathname.length > 0)
      pathParams = pathname.split('/');

    // handle hash
    let hash = window.location.hash;
    hash = hash.replace(/^#/, '');

    if (hash.length > 0)
      hashParams = hash.split('-');

    if (pathParams || hashParams) {
      this.urlParams = [];

      if (pathParams)
        pathParams.forEach((param) => this.urlParams.push(param));

      if (hashParams)
        hashParams.forEach((param) => this.urlParams.push(param));
    }

    console.log('soundworks', this.urlParams);
  },

  /**
   * Initialize socket connection and perform handshake with the server.
   * @todo - refactor handshake.
   * @private
   */
  _initSocket() {
    socket.init(this.type, this.config.websockets);

    // see: http://socket.io/docs/client-api/#socket
    this.socket.addStateListener((eventName) => {
      switch (eventName) {
        case 'connect':
          const payload = { urlParams: this.urlParams };

          if (this.config.env !== 'production') {
            Object.assign(payload, {
              requiredServices: serviceManager.getRequiredServices()
            });
          }

          this.socket.send('handshake', payload);
          // wait for handshake response to mark client as `ready`
          this.socket.receive('client:start', (uuid) => {
            this.uuid = uuid;
            serviceManager.start();
          });

          this.socket.receive('client:error', (err) => {
            switch (err.type) {
              case 'services':
                // can only append if env !== 'production'
                const msg = `"${err.data.join(', ')}" required client-side but not server-side`;
                throw new Error(msg);
                break;
            }
          });
          break;
          // case 'reconnect':
          //   // serviceManager.start();
          //   break;
          // case 'disconnect':
          //   // can relaunch serviceManager on reconnection
          //   // serviceManager.reset();
          //   break;
          // case 'connect_error':
          // case 'reconnect_attempt':
          // case 'reconnecting':
          // case 'reconnect_error':
          // case 'reconnect_failed':
          //   break;
      }
    });
  },
};

export default client;
<commit_msg>improved readability of start lifecycle<commit_after>import Activity from './Activity';
import serviceManager from './serviceManager';
import viewManager from './viewManager';
import socket from './socket';
// import defaultViewContent from '../config/defaultViewContent';
// import defaultViewTemplates from '../config/defaultViewTemplates';
import viewport from '../views/viewport';

/**
 * Client side entry point for a `soundworks` application.
 *
 * This object hosts general informations about the user, as well as methods
 * to initialize and start the application.
 *
 * @memberof module:soundworks/client
 * @namespace
 *
 * @example
 * import * as soundworks from 'soundworks/client';
 * import MyExperience from './MyExperience';
 *
 * soundworks.client.init('player');
 * const myExperience = new MyExperience();
 * soundworks.client.start();
 */
const client = {
  /**
   * Unique id of the client, generated and retrieved by the server.
   *
   * @type {Number}
   */
  uuid: null,

  /**
   * The type of the client, this can generally be considered as the role of the
   * client in the application. This value is defined in the
   * [`client.init`]{@link module:soundworks/server.server~serverConfig} object
   * and defaults to `'player'`.
   *
   * @type {String}
   */
  type: null,

  /**
   * Configuration informations from the server configuration if any.
   *
   * @type {Object}
   * @see {@link module:soundworks/client.client~init}
   * @see {@link module:soundworks/client.SharedConfig}
   */
  config: {},

  /**
   * Array of optionnal parameters passed through the url
   *
   * @type {Array}
   */
   urlParams: null,

  /**
   * Information about the client platform. The properties are set by the
   * [`platform`]{@link module:soundworks/client.Platform} service.
   *
   * @type {Object}
   * @property {String} os - Operating system.
   * @property {Boolean} isMobile - Indicates whether the client is running on a
   *  mobile platform or not.
   * @property {String} audioFileExt - Audio file extension to use, depending on
   *  the platform.
   * @property {String} interaction - Type of interaction allowed by the
   *  viewport, `touch` or `mouse`
   *
   * @see {@link module:soundworks/client.Platform}
   */
  platform: {
    os: null,
    isMobile: null,
    audioFileExt: '',
    interaction: null,
  },

  /**
   * Defines whether the user's device is compatible with the application
   * requirements.
   *
   * @type {Boolean}
   * @see {@link module:soundworks/client.Platform}
   */
  compatible: null,

  /**
   * Index (if any) given by a [`placer`]{@link module:soundworks/client.Placer}
   * or [`checkin`]{@link module:soundworks/client.Checkin} service.
   *
   * @type {Number}
   * @see {@link module:soundworks/client.Checkin}
   * @see {@link module:soundworks/client.Placer}
   */
  index: null,

  /**
   * Ticket label (if any) given by a [`placer`]{@link module:soundworks/client.Placer}
   * or [`checkin`]{@link module:soundworks/client.Checkin} service.
   *
   * @type {String}
   * @see {@link module:soundworks/client.Checkin}
   * @see {@link module:soundworks/client.Placer}
   */
  label: null,

  /**
   * Client coordinates (if any) given by a
   * [`locator`]{@link module:soundworks/client.Locator},
   * [`placer`]{@link module:soundworks/client.Placer} or
   * [`checkin`]{@link module:soundworks/client.Checkin} service.
   * (Format: `[x:Number, y:Number]`.)
   *
   * @type {Array<Number>}
   * @see {@link module:soundworks/client.Checkin}
   * @see {@link module:soundworks/client.Locator}
   * @see {@link module:soundworks/client.Placer}
   * @see {@link module:soundworks/client.Geolocation}
   */
  coordinates: null,

  /**
   * Full `geoposition` object as returned by `navigator.geolocation`, when
   * using the `geolocation` service.
   *
   * @type {Object}
   * @see {@link module:soundworks/client.Geolocation}
   */
  geoposition: null,

  /**
   * Socket object that handle communications with the server, if any.
   * This object is automatically created if the experience requires any service
   * having a server-side counterpart.
   *
   * @type {module:soundworks/client.socket}
   * @private
   */
  socket: socket,

  /**
   * Initialize the application.
   *
   * @param {String} [clientType='player'] - The type of the client, defines the
   *  socket connection namespace. Should match a client type defined server side.
   * @param {Object} [config={}]
   * @param {Object} [config.appContainer='#container'] - A css selector
   *  matching a DOM element where the views should be inserted.
   * @param {Object} [config.websockets.url=''] - The url where the socket should
   *  connect _(unstable)_.
   * @param {Object} [config.websockets.transports=['websocket']] - The transport
   *  used to create the url (overrides default socket.io mecanism) _(unstable)_.
   */
  init(clientType = 'player', config = {}) {
    this.type = clientType;

    this._parseUrlParams();
    // if socket config given, mix it with defaults
    const websockets = Object.assign({
      url: '',
      transports: ['websocket'],
      path: '',
    }, config.websockets);

    // mix all other config and override with defined socket config
    Object.assign(this.config, config, { websockets });

    serviceManager.init();
    viewport.init();

    const el = config.appContainer;
    const $container = el instanceof Element ? el : document.querySelector(el);
    viewManager.setAppContainer($container);

    return Promise.resolve();
  },

  /**
   * Register a function to be executed when a service is instanciated.
   *
   * @param {serviceManager~serviceInstanciationHook} func - Function to
   *  register has a hook to be execute when a service is created.
   */
  /**
   * @callback serviceManager~serviceInstanciationHook
   * @param {String} id - id of the instanciated service.
   * @param {Service} instance - instance of the service.
   */
  setServiceInstanciationHook(func) {
    serviceManager.setServiceInstanciationHook(func);
  },

  /**
   * Start the application.
   */
  start() {
    if (socket.required)
      this._initSocket(() => serviceManager.start());
    else
      serviceManager.start();
  },

  /**
   * Returns a service configured with the given options.
   * @param {String} id - Identifier of the service.
   * @param {Object} options - Options to configure the service.
   */
  require(id, options) {
    return serviceManager.require(id, options);
  },

  /**
   * Retrieve an array of optionnal parameters from the url excluding the client type
   * and store it in `this.urlParams`.
   * Parameters can be defined in two ways :
   * - as a regular route (ex: `/player/param1/param2`)
   * - as a hash (ex: `/player#param1-param2`)
   * The parameters are send along with the socket connection
   *
   * @see {@link module:soundworks/client.socket}
   * @private
   * @todo - When handshake implemented, define if these informations should be part of it
   */
  _parseUrlParams() {
    let pathParams = null;
    let hashParams = null;
    // handle path name first
    let pathname = window.location.pathname;
    // sanitize
    pathname = pathname
      .replace(/^\//, '')                               // leading slash
      .replace(new RegExp('^' + this.type + '/?'), '')  // remove clientType
      .replace(/\/$/, '');                              // trailing slash

    if (pathname.length > 0)
      pathParams = pathname.split('/');

    // handle hash
    let hash = window.location.hash;
    hash = hash.replace(/^#/, '');

    if (hash.length > 0)
      hashParams = hash.split('-');

    if (pathParams || hashParams) {
      this.urlParams = [];

      if (pathParams)
        pathParams.forEach((param) => this.urlParams.push(param));

      if (hashParams)
        hashParams.forEach((param) => this.urlParams.push(param));
    }

    console.log('soundworks', this.urlParams);
  },

  /**
   * Initialize socket connection and perform handshake with the server.
   * @todo - refactor handshake.
   * @private
   */
  _initSocket(callback) {
    socket.init(this.type, this.config.websockets);

    // see: http://socket.io/docs/client-api/#socket
    this.socket.addStateListener((eventName) => {
      switch (eventName) {
        case 'connect':
          const payload = { urlParams: this.urlParams };

          if (this.config.env !== 'production') {
            Object.assign(payload, {
              requiredServices: serviceManager.getRequiredServices()
            });
          }

          this.socket.send('handshake', payload);
          // wait for handshake response to mark client as `ready`
          this.socket.receive('client:start', (uuid) => {
            this.uuid = uuid;
            callback();
          });

          this.socket.receive('client:error', (err) => {
            switch (err.type) {
              case 'services':
                // can only append if env !== 'production'
                const msg = `"${err.data.join(', ')}" required client-side but not server-side`;
                throw new Error(msg);
                break;
            }
          });
          break;
          // case 'reconnect':
          //   // serviceManager.start();
          //   break;
          // case 'disconnect':
          //   // can relaunch serviceManager on reconnection
          //   // serviceManager.reset();
          //   break;
          // case 'connect_error':
          // case 'reconnect_attempt':
          // case 'reconnecting':
          // case 'reconnect_error':
          // case 'reconnect_failed':
          //   break;
      }
    });
  },
};

export default client;
<|endoftext|>


<commit_before>'use strict';
const $ = require('jquery');

$(document).ready(function () {

  var $counter = $('#boLBCounter');
  var $description = $('#boLbCounterDescription');

  function updateCounter() {
    var counter = {
      current: new Date(),
      start: $counter.data('start'),
      end: $counter.data('end'),
      time: {}
    };

    if (counter.current < counter.start) {
      //Before event
      counter.state = window.states.pre;
      counter.value = counter.start - counter.current;

    } else if (counter.current <= counter.end) {
      //During event
      counter.state = window.states.during;
      counter.value = counter.end - counter.current;
    } else {
      //Post event
      counter.state = window.states.post;
      counter.value = counter.current - counter.end;
    }

    counter.time.days = Math.floor(counter.value / (24 * 60 * 60 * 1000));
    counter.time.hours = Math.floor((counter.value - (counter.time.days * 24 * 60 * 60 * 1000)) / (60 * 60 * 1000));
    counter.time.minutes = Math.floor(
      (counter.value
      - (counter.time.days * 24 * 60 * 60 * 1000)
      - (counter.time.hours * 60 * 60 * 1000)) / (60 * 1000));
    counter.time.seconds = Math.floor(
      (counter.value
      - (counter.time.days * 24 * 60 * 60 * 1000)
      - (counter.time.hours * 60 * 60 * 1000)
      - (counter.time.minutes * 60 * 1000)) / 1000);

    if (counter.time.days > 1) {
      $counter.html(leftPad(counter.time.days) + ' ' + window.days + ' ' + leftPad(counter.time.hours) + ':' + leftPad(counter.time.minutes) + ':' + leftPad(counter.time.seconds));
    } else {
      $counter.html(leftPad(counter.time.hours + (counter.time.days * 24)) + ':' + leftPad(counter.time.minutes) + ':' + leftPad(counter.time.seconds));
    }

    $description.html(counter.state);

  }

  function leftPad(time) {
    var string = '00' + time;
    return string.substring(string.length - 2);
  }

  updateCounter();
  setInterval(updateCounter, 1000);

  //SCROLLING

  var $marker = $('#boTeamPostScroll');
  var $teamPosts = $('#teamPosts');
  var loading = false;
  var finished = false;
  var current = 0;
  $(window).on('load', function () {
    $(window).scroll(function () {

      if ($marker.offset().top - 100 < window.scrollY + $(window).height()) {
        if (!loading && !finished) {
          loading = true;
          $.post('/liveblog/posting/', {
            activeEvents: window.activeEvents,
            page: current + 1
          }).success(function (postingsHTML) {
            var $postings = $(postingsHTML);
            if ($postings.length === 0) {
              finished = true;
              $marker.html('
Keine weiteren Posts verfügbar!
');
            } else {
              current++;
              $teamPosts.append($postings);
              window.msnry.appended($postings);
              //LOLOL DIRTY HACK FOR SLOW BROWSERS
              setTimeout(function () {
                window.msnry.layout();
              }, 200);
              setTimeout(function () {
                window.msnry.layout();
              }, 500);
              setTimeout(function () {
                window.msnry.layout();
              }, 2000);
              setTimeout(function () {
                window.msnry.layout();
              }, 5000);
              setTimeout(function () {
                window.msnry.layout();
              }, 15000);
              loading = false;
            }
          }).error(function () {
            $marker.html('
Konnte keine weiteren Posts laden.
');
            loading = false;
          });
        }
      }
    });
  });

  $.fn.countTo = function (options) {
    // merge the default plugin settings with the custom options
    options = $.extend({}, $.fn.countTo.defaults, options || {});

    // how many times to update the value, and how much to increment the value on each update
    var loops = Math.ceil(options.speed / options.refreshInterval),
      increment = (options.to - options.from) / loops;

    return $(this).each(function () {
      var _this = this,
        loopCount = 0,
        value = options.from,
        interval = setInterval(updateTimer, options.refreshInterval);

      function updateTimer() {
        value += increment;
        loopCount++;
        $(_this).html(value.toFixed(0).toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.'));

        if (typeof(options.onUpdate) == 'function') {
          options.onUpdate.call(_this, value);
        }

        if (loopCount >= loops) {
          clearInterval(interval);
          value = options.to;

          if (typeof(options.onComplete) == 'function') {
            options.onComplete.call(_this, value);
          }
        }
      }
    });
  };

  $.fn.countTo.defaults = {
    from: 0,  // the number the element should start at
    to: 100,  // the number the element should end at
    speed: 30000,  // how long it should take to count between the target numbers
    refreshInterval: 100,  // how often the element should be updated
    decimals: 0,  // the number of decimal places to show
    onUpdate: null,  // callback method for every time the element is updated,
    onComplete: null  // callback method for when the element finishes updating
  };

  function loadData() {
    var currentDonations = {};
    window.activeEvents.forEach(function(id) {
      $.get(
        window.boClientConfig.baseUrl + '/event/' + id + '/donatesum/',
        function (data) {
          currentDonations[id] = data.fullSum;
          if(Object.keys(currentDonations).length === window.activeEvents.length) {
            count('bo-donate-sum', currentDonations);
          }
        }
      );
    });

    var currentDistance = {};
    window.activeEvents.forEach(function(id) {
      $.get(
        window.boClientConfig.baseUrl + '/event/' + id + '/distance/',
        function (data) {
          currentDistance[id] = data.distance;
          if(Object.keys(currentDistance).length === window.activeEvents.length) {
            count('bo-distance-sum', currentDistance);
          }
        }
      );
    });
  }

  function count(target, currentData) {
    var old = window.oldData[target];

    var oldTotal = 0;
    var newTotal = 0;

    if(old) {
      window.activeEvents.forEach(function(id) {
        $(`.${target}[data-id='${id}']`).countTo({from: Math.round(old[id]), to: Math.round(currentData[id])});
        oldTotal += Math.round(old[id]);
        newTotal += Math.round(currentData[id]);
      });
      $('#' + target).countTo({from: oldTotal, to: newTotal});
    }

    window.oldData[target] = currentData;
  }

  window.oldData = {};
  setInterval(loadData, 30000);

});
<commit_msg>no longer left padding days<commit_after>'use strict';
const $ = require('jquery');

$(document).ready(function () {

  var $counter = $('#boLBCounter');
  var $description = $('#boLbCounterDescription');

  function updateCounter() {
    var counter = {
      current: new Date(),
      start: $counter.data('start'),
      end: $counter.data('end'),
      time: {}
    };

    if (counter.current < counter.start) {
      //Before event
      counter.state = window.states.pre;
      counter.value = counter.start - counter.current;

    } else if (counter.current <= counter.end) {
      //During event
      counter.state = window.states.during;
      counter.value = counter.end - counter.current;
    } else {
      //Post event
      counter.state = window.states.post;
      counter.value = counter.current - counter.end;
    }

    counter.time.days = Math.floor(counter.value / (24 * 60 * 60 * 1000));
    counter.time.hours = Math.floor((counter.value - (counter.time.days * 24 * 60 * 60 * 1000)) / (60 * 60 * 1000));
    counter.time.minutes = Math.floor(
      (counter.value
      - (counter.time.days * 24 * 60 * 60 * 1000)
      - (counter.time.hours * 60 * 60 * 1000)) / (60 * 1000));
    counter.time.seconds = Math.floor(
      (counter.value
      - (counter.time.days * 24 * 60 * 60 * 1000)
      - (counter.time.hours * 60 * 60 * 1000)
      - (counter.time.minutes * 60 * 1000)) / 1000);

    if (counter.time.days > 1) {
      $counter.html(counter.time.days + ' ' + window.days + ' ' + leftPad(counter.time.hours) + ':' + leftPad(counter.time.minutes) + ':' + leftPad(counter.time.seconds));
    } else {
      $counter.html(leftPad(counter.time.hours + (counter.time.days * 24)) + ':' + leftPad(counter.time.minutes) + ':' + leftPad(counter.time.seconds));
    }

    $description.html(counter.state);

  }

  function leftPad(time) {
    var string = '00' + time;
    return string.substring(string.length - 2);
  }

  updateCounter();
  setInterval(updateCounter, 1000);

  //SCROLLING

  var $marker = $('#boTeamPostScroll');
  var $teamPosts = $('#teamPosts');
  var loading = false;
  var finished = false;
  var current = 0;
  $(window).on('load', function () {
    $(window).scroll(function () {

      if ($marker.offset().top - 100 < window.scrollY + $(window).height()) {
        if (!loading && !finished) {
          loading = true;
          $.post('/liveblog/posting/', {
            activeEvents: window.activeEvents,
            page: current + 1
          }).success(function (postingsHTML) {
            var $postings = $(postingsHTML);
            if ($postings.length === 0) {
              finished = true;
              $marker.html('
Keine weiteren Posts verfügbar!
');
            } else {
              current++;
              $teamPosts.append($postings);
              window.msnry.appended($postings);
              //LOLOL DIRTY HACK FOR SLOW BROWSERS
              setTimeout(function () {
                window.msnry.layout();
              }, 200);
              setTimeout(function () {
                window.msnry.layout();
              }, 500);
              setTimeout(function () {
                window.msnry.layout();
              }, 2000);
              setTimeout(function () {
                window.msnry.layout();
              }, 5000);
              setTimeout(function () {
                window.msnry.layout();
              }, 15000);
              loading = false;
            }
          }).error(function () {
            $marker.html('
Konnte keine weiteren Posts laden.
');
            loading = false;
          });
        }
      }
    });
  });

  $.fn.countTo = function (options) {
    // merge the default plugin settings with the custom options
    options = $.extend({}, $.fn.countTo.defaults, options || {});

    // how many times to update the value, and how much to increment the value on each update
    var loops = Math.ceil(options.speed / options.refreshInterval),
      increment = (options.to - options.from) / loops;

    return $(this).each(function () {
      var _this = this,
        loopCount = 0,
        value = options.from,
        interval = setInterval(updateTimer, options.refreshInterval);

      function updateTimer() {
        value += increment;
        loopCount++;
        $(_this).html(value.toFixed(0).toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.'));

        if (typeof(options.onUpdate) == 'function') {
          options.onUpdate.call(_this, value);
        }

        if (loopCount >= loops) {
          clearInterval(interval);
          value = options.to;

          if (typeof(options.onComplete) == 'function') {
            options.onComplete.call(_this, value);
          }
        }
      }
    });
  };

  $.fn.countTo.defaults = {
    from: 0,  // the number the element should start at
    to: 100,  // the number the element should end at
    speed: 30000,  // how long it should take to count between the target numbers
    refreshInterval: 100,  // how often the element should be updated
    decimals: 0,  // the number of decimal places to show
    onUpdate: null,  // callback method for every time the element is updated,
    onComplete: null  // callback method for when the element finishes updating
  };

  function loadData() {
    var currentDonations = {};
    window.activeEvents.forEach(function(id) {
      $.get(
        window.boClientConfig.baseUrl + '/event/' + id + '/donatesum/',
        function (data) {
          currentDonations[id] = data.fullSum;
          if(Object.keys(currentDonations).length === window.activeEvents.length) {
            count('bo-donate-sum', currentDonations);
          }
        }
      );
    });

    var currentDistance = {};
    window.activeEvents.forEach(function(id) {
      $.get(
        window.boClientConfig.baseUrl + '/event/' + id + '/distance/',
        function (data) {
          currentDistance[id] = data.distance;
          if(Object.keys(currentDistance).length === window.activeEvents.length) {
            count('bo-distance-sum', currentDistance);
          }
        }
      );
    });
  }

  function count(target, currentData) {
    var old = window.oldData[target];

    var oldTotal = 0;
    var newTotal = 0;

    if(old) {
      window.activeEvents.forEach(function(id) {
        $(`.${target}[data-id='${id}']`).countTo({from: Math.round(old[id]), to: Math.round(currentData[id])});
        oldTotal += Math.round(old[id]);
        newTotal += Math.round(currentData[id]);
      });
      $('#' + target).countTo({from: oldTotal, to: newTotal});
    }

    window.oldData[target] = currentData;
  }

  window.oldData = {};
  setInterval(loadData, 30000);

});
<|endoftext|>


<commit_before>define(['underscore', 'util'],
function(_,            util)
{

var nodetypes,
    type_attributes = {
        'internship': ['status', 'startdate', 'enddate', 'description', 'url'],
        'skill': ['description', 'url'],
        'interest': ['description', 'url'],
        'person': ['description', 'url'],
    },
    all_attributes;

nodetypes = _.keys(type_attributes);

type_attributes['_defaults'] = ['description', 'url'];

_.values(type_attributes).map(function (attributes) {
        attributes.push('name');
        attributes.push('type');
        attributes.sort();
    });

all_attributes = _.union(_.flatten(_.map(type_attributes, _.values))).sort();

return (
    {
        nodetypes: nodetypes,
        type_attributes: function (type) {
            util.assert(type[0] !== '_', 'invalid type name');
            return type_attributes[type_attributes.hasOwnProperty(type) ? type : '_defaults'];
        },
        all_attributes: all_attributes,
    });
}
)
<commit_msg>client/model/types: store titles for types and attributes<commit_after>define(['underscore', 'util'],
function(_,            util)
{

var nodetypes,
    type_attributes = {
        'internship': {
            'title': 'Internship',
            'attributes':
                ['status', 'startdate', 'enddate', 'description', 'url',
                 'internship-type',
                 'facility',
                 'facility-affiliation',
                 'cnrs-inserm-unit-code',
                 'street-address',
                 'city',
                 'country',
                ],
            },
        'skill': {
            'title': 'Skill',
            'attributes': ['description', 'url'],
            },
        'interest': {
            'title': 'Interesst',
            'attributes': ['description', 'url'],
            },
        'person': {
            'title': 'Person',
            'attributes': ['description', 'url'],
            }
    },
    all_attributes,
    attribute_titles = {
        'name': 'Name',
        'type': 'Type',
        'description': 'Description',
        'url': 'URL',
        'status': 'Status',
        'startdate': 'Start Date',
        'enddate': 'End Date',
        'internship-type': 'Internship Type',
        'facility': 'Lab/Company',
        'facility-affiliation': 'Lab affiliation',
        'cnrs-inserm-unit-code': 'CNRS / INSERM unit code',
        'street-address': 'Street address',
        'city': 'City',
        'country': 'Country',
    };

nodetypes = _.keys(type_attributes);

type_attributes['_defaults'] = {
    'title': 'default',
    'attributes':['description', 'url']
    };

_.pluck(_.values(type_attributes), 'attributes').map(function (attributes) {
        attributes.push('name');
        attributes.push('type');
        attributes.sort();
    });

all_attributes = _.union(_.flatten(_.pluck(_.values(type_attributes), 'attributes'))).sort();

util.assert(_.isEqual(all_attributes, _.keys(attribute_titles).sort()));

return (
    {
        nodetypes: nodetypes,
        type_attributes: function (type) {
            util.assert(type[0] !== '_', 'invalid type name');
            return type_attributes[type_attributes.hasOwnProperty(type) ? type : '_defaults'].attributes;
        },
        all_attributes: all_attributes,
        attribute_titles: attribute_titles,
    });
}
)
<|endoftext|>