<commit_before>/* eslint no-console:off */

(function setupSW() {
  'use strict'

  if ('serviceWorker' in navigator) {
    window.addEventListener('load', function () {
      navigator.serviceWorker.register('/sw.js').then(function (registration) { // eslint-disable-line compat/compat
        console.log('ServiceWorker registration successful with scope: ', registration.scope)
        registration.onupdatefound = function () {
          var installingWorker = registration.installing
          installingWorker.onstatechange = function () {
            switch (installingWorker.state) {
              case 'installed':
                if (navigator.serviceWorker.controller) { // eslint-disable-line compat/compat
                  console.log('new update available')
                  location.reload(true)
                }
                break

              default:
            }
          }
        }
      }).catch(function (err) {
        console.log('ServiceWorker registration failed: ', err)
      })
    })
  }
}())
<commit_msg>Remove page reload in pwa.js. (#24923)<commit_after>/* eslint no-console:off */

(function setupSW() {
  'use strict'

  if ('serviceWorker' in navigator) {
    window.addEventListener('load', function () {
      navigator.serviceWorker.register('/sw.js').then(function (registration) { // eslint-disable-line compat/compat
        console.log('ServiceWorker registration successful with scope: ', registration.scope)
      }).catch(function (err) {
        console.log('ServiceWorker registration failed: ', err)
      })
    })
  } else {
    console.log('Service workers are not supported.')
  }
}())
<|endoftext|>


<commit_before>// ==UserScript==
// @author      Robert Slifka (github @rslifka)
// @connect     docs.google.com
// @connect     rslifka.github.io
// @copyright   2017-2018, Robert Slifka (https://github.com/rslifka/fate_of_all_fools)
// @description Enhancements to the Destiny Item Manager
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getValue
// @grant       GM_log
// @grant       GM_setValue
// @grant       GM_xmlhttpRequest
// @homepage    https://github.com/rslifka/fate_of_all_fools
// @license     MIT; https://raw.githubusercontent.com/rslifka/fate_of_all_fools/master/LICENSE.txt
// @match       https://*.destinyitemmanager.com/*
// @name        Fate of All Fools
// @require     https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.js
// @resource    fateOfAllFoolsCSS https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.css
// @run-at      document-start
// @supportURL  https://github.com/rslifka/fate_of_all_fools/issues
// @version     387
// ==/UserScript==
<commit_msg>AUTO-CREATED Release Artifact v388 c/o Travis<commit_after>// ==UserScript==
// @author      Robert Slifka (github @rslifka)
// @connect     docs.google.com
// @connect     rslifka.github.io
// @copyright   2017-2018, Robert Slifka (https://github.com/rslifka/fate_of_all_fools)
// @description Enhancements to the Destiny Item Manager
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getValue
// @grant       GM_log
// @grant       GM_setValue
// @grant       GM_xmlhttpRequest
// @homepage    https://github.com/rslifka/fate_of_all_fools
// @license     MIT; https://raw.githubusercontent.com/rslifka/fate_of_all_fools/master/LICENSE.txt
// @match       https://*.destinyitemmanager.com/*
// @name        Fate of All Fools
// @require     https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.js
// @resource    fateOfAllFoolsCSS https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.css
// @run-at      document-start
// @supportURL  https://github.com/rslifka/fate_of_all_fools/issues
// @version     388
// ==/UserScript==
<|endoftext|>


<commit_before>module.exports = {
    init: init
};

var util = require("util");
var FrameInputStream = require("./frame_input_stream");

function AppUtil(argv){
    this.argv = argv;
}

function init(argv){
    return new AppUtil(argv);
}

AppUtil.prototype.log = function(message){
    if(this.argv.verbose){
        util.print(message + "\n");
    }
};

AppUtil.prototype.fatalError = function(message){
    process.stderr.write(message + "\n");
    process.exit(1);
};

AppUtil.prototype.fatalErrorEvent = function(format){
    var self = this;
    return function(error){
        self.fatalError(util.format(format, error.message));
    };
};

AppUtil.prototype.parseHeaderLines = function(){

    var headers = {};

    var headerPattern = /([^:]+):(.*)/;

    for(var i = 0; i < arguments.length; i++){

        var arg = arguments[i];

        if(!(arg instanceof Array)){
            arg = [arg];
        }

        for(var j = 0; j < arg.length; j++){

            var lines = ("" + arg[j]).split("\n");

            for(var k = 0; k < lines.length; k++){

                var line = lines[k];

                var match = line.match(headerPattern);

                if(match){
                    headers[match[1]] = FrameInputStream.prototype.decodeHeaderValue(match[2]);
                }
            }
        }
    }

    return headers;
};
<commit_msg>The format parameter for AppUtil.fatalErrorEvent function is optional<commit_after>module.exports = {
    init: init
};

var util = require("util");
var FrameInputStream = require("./frame_input_stream");

function AppUtil(argv){
    this.argv = argv;
}

function init(argv){
    return new AppUtil(argv);
}

AppUtil.prototype.log = function(message){
    if(this.argv.verbose){
        util.print(message + "\n");
    }
};

AppUtil.prototype.fatalError = function(message){
    process.stderr.write(message + "\n");
    process.exit(1);
};

AppUtil.prototype.fatalErrorEvent = function(format){

    var self = this;

    return function(error){

        var message;

        if(format){
            message = util.format(format, error.message);
        }
        else{

            message = error.message;

            if(error.longMessage){
                message += "\n\t" + error.longMessage;
            }
        }

        self.fatalError(message);
    };
};

AppUtil.prototype.parseHeaderLines = function(){

    var headers = {};

    var headerPattern = /([^:]+):(.*)/;

    for(var i = 0; i < arguments.length; i++){

        var arg = arguments[i];

        if(!(arg instanceof Array)){
            arg = [arg];
        }

        for(var j = 0; j < arg.length; j++){

            var lines = ("" + arg[j]).split("\n");

            for(var k = 0; k < lines.length; k++){

                var line = lines[k];

                var match = line.match(headerPattern);

                if(match){
                    headers[match[1]] = FrameInputStream.prototype.decodeHeaderValue(match[2]);
                }
            }
        }
    }

    return headers;
};
<|endoftext|>


<commit_before>/*
   Copyright 2016 The Trustees of University of Arizona

   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

       http://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.
*/

var util = require('util');
var utils = require('./utils.js');
var syndicate = require('syndicate-drive');
var nodeCache = require('node-cache');

function safe_close_fh(ug, fh) {
    if(ug) {
        utils.log_debug("SAFECLOSE: calling syndicate.close");
        syndicate.close(ug, fh);
    }
}

function safe_close_gateway(ug) {
    if(ug) {
        // shutdown UG
        utils.log_debug("SHUTDOWN: calling syndicate.shutdown");
        syndicate.shutdown(ug);
    }
}

/**
 * Expose root class
 */
module.exports = {
    // create a new gateway state
    create: function(user, volume, gateway, config_path) {
        utils.log_debug("INIT: calling syndicate.create_opts");
        var conf_file = util.format("%s/syndicate.conf", config_path);
        var opts = syndicate.create_opts(user, volume, gateway, 0, conf_file);

        // init UG
        utils.log_debug("INIT: calling syndicate.init");
        var ug = syndicate.init(opts);

        // setup state
        var fd_map = new nodeCache({
            stdTTL: 3600,
            checkperiod: 600,
            useClones: false
        });

        fd_map.on("expired", function(key, fh) {
            utils.log_debug(util.format("closing an expired file handle - %s", key));
            safe_close_fh(ug, fh);
        });

        var gateway_state = {
            user: user,
            volume: volume,
            gateway: gateway,
            config_path: conf_file,
            opts: opts,
            ug: ug,
            fd_map: fd_map,
            last_fd: 0,
            io_statistics: {},
        };

        return gateway_state;
    },
    // destroy a gateway state
    destroy: function(gateway_state) {
        // destroy
        // close all files opened
        var key;
        for(key in gateway_state.fd_map) {
            utils.log_debug(util.format("closing a missing file handle - %s", key));
            var stat = gateway_state.fd_map.get(key);
            if(stat !== null) {
                safe_close_fh(gateway_state.ug, stat.fh);
                utils.log_debug(util.format("file handle closed - fh(%d), path(%s), flag(%s)", stat.fh, stat.path, stat.flag));
            }

            gateway_state.fd_map.del(key);
        }

        // close ug
        safe_close_gateway(gateway_state.ug);
    },
    /*
    statistics_keys: {
        RESPONSE: "response",
        RESPONSE_DATA: "response_data",
        RESPONSE_ERROR: "response_error",
        REQUEST: "request",
        REQUEST_GET: "request_get",
        REQUEST_POST: "request_post",
        REQUEST_DELETE: "request_delete",
        FILE_OPENED: "file_opened",
        FILE_READ: "file_read",
        FILE_WRITE: "file_write",
    },
    // statistics
    get_statistics: function(gateway_state, key) {
        var val = null;
        if(key in gateway_state.io_statistics) {
            val = gateway_state.io_statistics[key];
        } else {
            val = 0;
        }
        return val;
    },
    inc_statistics: function(gateway_state, key) {
        var val = null;
        if(key in gateway_state.io_statistics) {
            val = gateway_state.io_statistics[key];
        } else {
            val = 0;
        }

        gateway_state.io_statistics[key] = val+1;
        utils.log_debug("inc_statistics " + key + " - " + gateway_state.io_statistics[key]);
    },
    dec_statistics: function(gateway_state, key) {
        var val = null;
        if(key in gateway_state.io_statistics) {
            val = gateway_state.io_statistics[key];
        } else {
            val = 0;
        }

        if(val-1 >= 0) {
            gateway_state.io_statistics[key] = val - 1;
        }

        utils.log_debug("stat_dec " + key + " - " + gateway_state.io_statistics[key]);
    },
    */
    create_file_handle: function(gateway_state, path, fh, flag) {
        gateway_state.last_fd++;
        var fd = gateway_state.last_fd;
        utils.log_debug(util.format("generate a new file handle - %d", fd));

        gateway_state.fd_map.set(fd, {
            'fd': fd,
            'fh': fh,
            'path': path,
            'flag': flag
        });

        return fd;
    },
    destroy_file_handle: function(gateway_state, fd) {
        utils.log_debug(util.format("closing a file handle - %s", fd));

        var stat = gateway_state.fd_map.get(fd);
        if(stat !== null) {
            utils.log_debug(util.format("file handle closed - fh(%d), path(%s), flag(%s)", stat.fh, stat.path, stat.flag));
        }

        gateway_state.fd_map.del(fd);
    },
    stat_file_handle: function(gateway_state, fd) {
        var stat = gateway_state.fd_map.get(fd);

        if(stat !== undefined) {
            // extend cache's ttl
            gateway_state.fd_map.ttl(fd);
            return stat;
        } else {
            return null;
        }
    },
    extend_file_handle_ttl: function(gateway_state, fd) {
        var stat = gateway_state.fd_map.get(fd);

        if(stat !== undefined) {
            // extend cache's ttl
            gateway_state.fd_map.ttl(fd);
            return true;
        }

        return false;
    }
};
<commit_msg>Remove removed file handle obj from log print<commit_after>/*
   Copyright 2016 The Trustees of University of Arizona

   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

       http://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.
*/

var util = require('util');
var utils = require('./utils.js');
var syndicate = require('syndicate-drive');
var nodeCache = require('node-cache');

function safe_close_fh(ug, fh) {
    if(ug) {
        utils.log_debug("SAFECLOSE: calling syndicate.close");
        syndicate.close(ug, fh);
    }
}

function safe_close_gateway(ug) {
    if(ug) {
        // shutdown UG
        utils.log_debug("SHUTDOWN: calling syndicate.shutdown");
        syndicate.shutdown(ug);
    }
}

/**
 * Expose root class
 */
module.exports = {
    // create a new gateway state
    create: function(user, volume, gateway, config_path) {
        utils.log_debug("INIT: calling syndicate.create_opts");
        var conf_file = util.format("%s/syndicate.conf", config_path);
        var opts = syndicate.create_opts(user, volume, gateway, 0, conf_file);

        // init UG
        utils.log_debug("INIT: calling syndicate.init");
        var ug = syndicate.init(opts);

        // setup state
        var fd_map = new nodeCache({
            stdTTL: 3600,
            checkperiod: 600,
            useClones: false
        });

        fd_map.on("expired", function(key, fh) {
            utils.log_debug(util.format("closing an expired file handle - %s", key));
            safe_close_fh(ug, fh);
        });

        var gateway_state = {
            user: user,
            volume: volume,
            gateway: gateway,
            config_path: conf_file,
            opts: opts,
            ug: ug,
            fd_map: fd_map,
            last_fd: 0,
            io_statistics: {},
        };

        return gateway_state;
    },
    // destroy a gateway state
    destroy: function(gateway_state) {
        // destroy
        // close all files opened
        var key;
        for(key in gateway_state.fd_map) {
            utils.log_debug(util.format("closing a missing file handle - %s", key));
            var stat = gateway_state.fd_map.get(key);
            if(stat !== null) {
                safe_close_fh(gateway_state.ug, stat.fh);
                utils.log_debug(util.format("file handle closed - path(%s), flag(%s)", stat.path, stat.flag));
            }

            gateway_state.fd_map.del(key);
        }

        // close ug
        safe_close_gateway(gateway_state.ug);
    },
    /*
    statistics_keys: {
        RESPONSE: "response",
        RESPONSE_DATA: "response_data",
        RESPONSE_ERROR: "response_error",
        REQUEST: "request",
        REQUEST_GET: "request_get",
        REQUEST_POST: "request_post",
        REQUEST_DELETE: "request_delete",
        FILE_OPENED: "file_opened",
        FILE_READ: "file_read",
        FILE_WRITE: "file_write",
    },
    // statistics
    get_statistics: function(gateway_state, key) {
        var val = null;
        if(key in gateway_state.io_statistics) {
            val = gateway_state.io_statistics[key];
        } else {
            val = 0;
        }
        return val;
    },
    inc_statistics: function(gateway_state, key) {
        var val = null;
        if(key in gateway_state.io_statistics) {
            val = gateway_state.io_statistics[key];
        } else {
            val = 0;
        }

        gateway_state.io_statistics[key] = val+1;
        utils.log_debug("inc_statistics " + key + " - " + gateway_state.io_statistics[key]);
    },
    dec_statistics: function(gateway_state, key) {
        var val = null;
        if(key in gateway_state.io_statistics) {
            val = gateway_state.io_statistics[key];
        } else {
            val = 0;
        }

        if(val-1 >= 0) {
            gateway_state.io_statistics[key] = val - 1;
        }

        utils.log_debug("stat_dec " + key + " - " + gateway_state.io_statistics[key]);
    },
    */
    create_file_handle: function(gateway_state, path, fh, flag) {
        gateway_state.last_fd++;
        var fd = gateway_state.last_fd;
        utils.log_debug(util.format("generate a new file handle - %d", fd));

        gateway_state.fd_map.set(fd, {
            'fd': fd,
            'fh': fh,
            'path': path,
            'flag': flag
        });

        return fd;
    },
    destroy_file_handle: function(gateway_state, fd) {
        utils.log_debug(util.format("closing a file handle - %s", fd));

        var stat = gateway_state.fd_map.get(fd);
        if(stat !== null) {
            utils.log_debug(util.format("file handle closed - fh(%d), path(%s), flag(%s)", stat.fh, stat.path, stat.flag));
        }

        gateway_state.fd_map.del(fd);
    },
    stat_file_handle: function(gateway_state, fd) {
        var stat = gateway_state.fd_map.get(fd);

        if(stat !== undefined) {
            // extend cache's ttl
            gateway_state.fd_map.ttl(fd);
            return stat;
        } else {
            return null;
        }
    },
    extend_file_handle_ttl: function(gateway_state, fd) {
        var stat = gateway_state.fd_map.get(fd);

        if(stat !== undefined) {
            // extend cache's ttl
            gateway_state.fd_map.ttl(fd);
            return true;
        }

        return false;
    }
};
<|endoftext|>


<commit_before>const {Cu} = require('chrome');
Cu.importGlobalProperties(['Blob']);
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/Preferences.jsm');
Cu.import('resource://gre/modules/Timer.jsm'); /* globals setTimeout */

const {Log} = require('./Log.js');
const {Http} = require('./Http.js');

// const STARTUP_DELAY_MS = 5000;
const STARTUP_DELAY_MS = 0;

exports.RecipeRunner = {
  init({waitForTabs: waitForTabs=true}) {
    const log = Log.makeNamespace('RecipeRunner.init');
    // Only run if Unified Telemetry is enabled.
    if (!Preferences.get('toolkit.telemetry.unified', false)) {
      log.config('Disabling RecipeRunner because Unified Telemetry is disabled.');
      return;
    }

    if (!Preferences.get('extensions.recipeclient.enabled', true)) {
      log.config('Recipe Client is disabled.');
      return;
    }

    if (waitForTabs) {
      // Wait for tabs to be loaded. This calls `this.observe` as callback.
      log.debug('Waiting for tabs to load');
      Services.obs.addObserver(this, 'sessionstore-windows-restored', false);
    } else {
      log.debug('Not waiting for tabs, starting immediately');
      // `setTimeout` so this is always an async action.
      setTimeout(this.start.bind(this), 0);
    }
  },

  uninit() {
    Services.obs.removeObserver(this, 'sessionstore-windows-restored');
  },

  /**
   * Handle notifications from `Services.obs.addObserver`.
   */
  observe(subject, topic, data) {
    const log = Log.makeNamespace('RecipeRunner.observe');
    if (topic === 'sessionstore-windows-restored') {
      // All tabs and windows are loaded now. Wait a bit more, just in case.
      log.debug(`Tabs are loaded, waiting ${STARTUP_DELAY_MS} and then loading recipes.`);
      setTimeout(this.start.bind(this), STARTUP_DELAY_MS);
    } else {
      log.config(`Unexpected topic: "${topic}"`, data);
    }
  },

  start() {
    const log = Log.makeNamespace('RecipeRunner.start');

    this.fetchRecipeList()
    .then(({recipes}) => {
      Log.info('recipes=');
      Log.info(recipes);
      return Promise.all(recipes.map(this.executeRecipe.bind(this)));
    })
    .catch(err => {
      log.error('Error executing recipes:');
      log.error(err);
    });
  },

  /**
   * Query recipe server for recipes, and execute them.
   * @return {[type]} [description]
   */
  fetchRecipeList() {
    // Fetch the Self Support URL from the preferences.
    const log = Log.makeNamespace('RecipeRunner.fetchRecipes');
    const url = Preferences.get('extensions.recipeclient.recipe_url', null);

    if (url === null) {
      log.error('Preference extensions.recipeclient.recipe_url is not defined');
      return;
    }

    if (!url.startsWith('https://')) {
      log.error(`Non HTTPS URL provided: ${url}`);
      return;
    }

    log.config(`Loading recipes from ${url}`);

    return Http.post({url, headers: {'Accept': 'application/json'}})
    .then(response => JSON.parse(response.text));
  },

  executeRecipe(recipe) {
    const log = Log.makeNamespace('RecipeRunner.executeRecipe');

    return Promise.all(recipe.actions.map(this.fetchAction.bind(this)))
    .then(actions => {
      log.info('actions=');
      log.info(actions);
      var promiseChain = Promise.resolve();
      for (let action of actions) { // eslint-disable-line prefer-const
        promiseChain = promiseChain.then(() => action());
      }
      return promiseChain;
    });
  },

  fetchAction(actionSpec) {
    const log = Log.makeNamespace('RecipeRunner.fetchAction');
    return Http.get({url: actionSpec.implementation.url})
    .then(response => {
      const sandboxScript = response.text;
      const sandbox = Cu.Sandbox(null);

      sandbox.postMessage = function(msg) {
        log.info(msg);
      }

      try {
        Cu.evalInSandbox(sandboxScript, sandbox);
        return sandbox.run;
      } catch (err) {
        log.error('failed to execute action');
        log.error(err);
        return function(){};
      }
    });
  },
};
<commit_msg>Pass arguments to functions.<commit_after>const {Cu} = require('chrome');
Cu.importGlobalProperties(['Blob']);
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/Preferences.jsm');
Cu.import('resource://gre/modules/Timer.jsm'); /* globals setTimeout */

const {Log} = require('./Log.js');
const {Http} = require('./Http.js');

// const STARTUP_DELAY_MS = 5000;
const STARTUP_DELAY_MS = 0;

exports.RecipeRunner = {
  init({waitForTabs: waitForTabs=true}) {
    const log = Log.makeNamespace('RecipeRunner.init');
    // Only run if Unified Telemetry is enabled.
    if (!Preferences.get('toolkit.telemetry.unified', false)) {
      log.config('Disabling RecipeRunner because Unified Telemetry is disabled.');
      return;
    }

    if (!Preferences.get('extensions.recipeclient.enabled', true)) {
      log.config('Recipe Client is disabled.');
      return;
    }

    if (waitForTabs) {
      // Wait for tabs to be loaded. This calls `this.observe` as callback.
      log.debug('Waiting for tabs to load');
      Services.obs.addObserver(this, 'sessionstore-windows-restored', false);
    } else {
      log.debug('Not waiting for tabs, starting immediately');
      // `setTimeout` so this is always an async action.
      setTimeout(this.start.bind(this), 0);
    }
  },

  uninit() {
    Services.obs.removeObserver(this, 'sessionstore-windows-restored');
  },

  /**
   * Handle notifications from `Services.obs.addObserver`.
   */
  observe(subject, topic, data) {
    const log = Log.makeNamespace('RecipeRunner.observe');
    if (topic === 'sessionstore-windows-restored') {
      // All tabs and windows are loaded now. Wait a bit more, just in case.
      log.debug(`Tabs are loaded, waiting ${STARTUP_DELAY_MS} and then loading recipes.`);
      setTimeout(this.start.bind(this), STARTUP_DELAY_MS);
    } else {
      log.config(`Unexpected topic: "${topic}"`, data);
    }
  },

  start() {
    const log = Log.makeNamespace('RecipeRunner.start');

    this.fetchRecipeList()
    .then(({recipes}) => {
      return Promise.all(recipes.map(this.executeRecipe.bind(this)));
    })
    .catch(err => {
      log.error('Error executing recipes:');
      log.error(err);
    });
  },

  /**
   * Query recipe server for recipes, and execute them.
   * @return {[type]} [description]
   */
  fetchRecipeList() {
    // Fetch the Self Support URL from the preferences.
    const log = Log.makeNamespace('RecipeRunner.fetchRecipes');
    const url = Preferences.get('extensions.recipeclient.recipe_url', null);

    if (url === null) {
      log.error('Preference extensions.recipeclient.recipe_url is not defined');
      return;
    }

    if (!url.startsWith('https://')) {
      log.error(`Non HTTPS URL provided: ${url}`);
      return;
    }

    log.config(`Loading recipes from ${url}`);

    return Http.post({url, headers: {'Accept': 'application/json'}})
    .then(response => JSON.parse(response.text));
  },

  executeRecipe(recipe) {
    return Promise.all(recipe.actions.map(this.fetchAction.bind(this)))
    .then(actions => {
      var promiseChain = Promise.resolve();
      for (let action of actions) { // eslint-disable-line prefer-const
        promiseChain = promiseChain.then(() => action());
      }
      return promiseChain;
    });
  },

  fetchAction(actionSpec) {
    const log = Log.makeNamespace('RecipeRunner.fetchAction');
    return Http.get({url: actionSpec.implementation.url})
    .then(response => {
      const sandboxScript = response.text;
      const sandbox = Cu.Sandbox(null);

      sandbox.postMessage = function(msg) {
        log.info(msg);
      };

      try {
        Cu.evalInSandbox(sandboxScript, sandbox);
      } catch (err) {
        log.error('failed to execute action');
        log.error(err);
        return function(){};
      }

      const sandboxedArgs = Cu.cloneInto(actionSpec.arguments, sandbox)
      log.info('sandboxedArgs=');
      log.info(sandboxedArgs);
      return function() {
        sandbox.run(sandboxedArgs);
      }
    });
  },
};
<|endoftext|>


<commit_before>/* @flow */
var React = require('react');
var AppActions = require('../actions.js');
var PlayerCell = require('./player_cell.js');
var Nav = require('react-bootstrap/Nav');
var Table = require('react-bootstrap/Table');
var Panel = require('react-bootstrap/Panel');
var Grid = require('react-bootstrap/Grid');
var Row = require('react-bootstrap/Row');
var Accordion = require('react-bootstrap/Accordion');
var PageHeader = require('react-bootstrap/PageHeader');

var GameRow = React.createClass({
	handleChange: function(weekNumber, player1Name, player2Name) {
		return function(event) {
			AppActions.updateGame(weekNumber, player1Name, player2Name, event.target.value);
		};
	},
	render: function() {
		var winnerRow = (<PlayerCell player={this.props.winner} admin={this.props.admin} />	);
		if (this.props.admin && this.props.admin !== "false") {
			winnerRow = (

					<select onChange={this.handleChange(this.props.week, this.props.player1.Name, this.props.player2.Name)}
						defaultValue={this.props.winner && this.props.winner.Name}>
							<option value="">-</option>
							<option value={this.props.player1.Name}>{this.props.player1.Name}</option>
							<option value={this.props.player2.Name}>{this.props.player2.Name}</option>
					</select>

			);
		}
		return (

				<PlayerCell player={this.props.player1} admin={this.props.admin} />
				<PlayerCell player={this.props.player2} admin={this.props.admin} />
				{winnerRow}

		);
	}
});

var WeekGroup = React.createClass({
	updateWeek: function(weekNumber) {
		return function(event) {
			AppActions.updateWeek(weekNumber, this.refs.playDate.getDOMNode().value, this.refs.scenarios.getDOMNode().value);
		}.bind(this);
	},
	render: function() {
		var rows = [];
		var admin = this.props.admin;
		var number = this.props.week.Number;
		var count = 0;
		this.props.week.Games.forEach(function(game) {
			rows.push(
					<GameRow player1={game.Players[0]}
							   player2={game.Players[1]}
							   hasWinner={game.Winner !== null}
							   winner={game.Winner}
							   week={number}
							   key={count}
							   admin={admin} />
			);
			count++;
		});
		var weekEdit = "";
		function pad(number) {
			if (number < 10) {
				return '0' + number;
			}
			return number;
		}
		if(admin) {
			var playDateId  = "play-date-" + number;
			var scenariosId = "scenarios-" + number;
			var dateDefault = "";
			var playDate = this.props.week.PlayDate;

			if(playDate) {
				playDate = new Date(playDate);
				dateDefault = playDate.getFullYear() + '-' + pad(playDate.getMonth() + 1) + '-' + pad(playDate.getDate());
			}
			weekEdit = (

						Play Date
						<input id={playDateId} className="form-control" type="date" ref="playDate" placeholder="YYYY-MM-DD"
							defaultValue={dateDefault}  />

						Scenarios (comma separated)
						<input id={scenariosId} className="form-control" type="text" ref="scenarios" pattern="((\d+)(,\d+)*)?"
							defaultValue={this.props.week.Scenarios && this.props.week.Scenarios.join(",")} />

					<button type="submit" className="btn btn-default" onClick={this.updateWeek(number)}>Submit</button>

			);
		}
		return (

				{weekEdit}

						Player 1
						Player 2
						Winner

{rows}

		);
	}
});

module.exports = React.createClass({
	propTypes: {
		season: React.PropTypes.object.isRequired
	},
	render: function(): ?ReactElement {
		var admin = this.props.admin;
		var rows = this.props.season.Weeks.map(function(week) {
			var header = "Week " + week.Number;
			if(week.PlayDate)
				header += " (" + new Date(week.PlayDate).toLocaleDateString() + ")";
			if(week.Scenarios)
				header += " - Scenario Numbers: [" + week.Scenarios.join(", ") + "]";
			return(
					<Panel header={header} eventKey={week.Number}>
						<WeekGroup week={week} admin={admin} key={week.Number}/>
					</Panel>
			);
		});
		return (

				<Grid>
					<Row>
						<PageHeader>{this.props.season.Name + " (" + this.props.season.Year + ")"}</PageHeader>
					</Row>
					<Row>
						<Accordion>{rows}</Accordion>
					</Row>
				</Grid>

		);
	}
});
<commit_msg>Refactored the season schedule to split the table into a separate element.<commit_after>/* @flow */
var React = require('react');
var AppActions = require('../actions.js');
var PlayerCell = require('./player_cell.js');
var Nav = require('react-bootstrap/Nav');
var Table = require('react-bootstrap/Table');
var Panel = require('react-bootstrap/Panel');
var Grid = require('react-bootstrap/Grid');
var Row = require('react-bootstrap/Row');
var Accordion = require('react-bootstrap/Accordion');
var PageHeader = require('react-bootstrap/PageHeader');

var GameRow = React.createClass({
	propTypes: {
		weekNumber: React.PropTypes.number.isRequired,
		game: React.PropTypes.object.isRequired,
		admin: React.PropTypes.bool
	},
	handleChange: function(weekNumber, player1Name, player2Name) {
		return function(event) {
			AppActions.updateGame(weekNumber, player1Name, player2Name, event.target.value);
		};
	},
	render: function() {
		var game = this.props.game;
		var player1 = game.Players[0];
		var player2 = game.Players[1];
		var winner = game.Winner;
		var admin = this.props.admin;
		var winnerRow = <PlayerCell player={winner} admin={admin} />	;
		if (admin) {
			winnerRow = (

					<select onChange={this.handleChange(this.props.weekNumber, player1.Name, player2.Name)}
						defaultValue={winner && winner.Name}>
							<option value="">-</option>
							<option value={player1.Name}>{player1.Name}</option>
							<option value={player2.Name}>{player2.Name}</option>
					</select>

			);
		}
		return (

				<PlayerCell player={player1} admin={admin} />
				<PlayerCell player={player2} admin={admin} />
				{winnerRow}

		);
	}
});

var WeekTable = React.createClass({
	propTypes: {
		week: React.PropTypes.object.isRequired,
		admin: React.PropTypes.bool
	},
	render: function() {
		var rows = this.props.week.Games.map(function(game, i) {
			return <GameRow game={game} weekNumber={this.props.week.Number} key={i} admin={this.props.admin} />;
		}.bind(this));
		return (

					Player 1
					Player 2
					Winner

{rows}

		);
	}
});

var WeekGroup = React.createClass({
	propTypes: {
		week: React.PropTypes.object.isRequired,
		admin: React.PropTypes.bool
	},
	updateWeek: function(weekNumber) {
		return function(event) {
			AppActions.updateWeek(weekNumber, this.refs.playDate.getDOMNode().value, this.refs.scenarios.getDOMNode().value);
		}.bind(this);
	},
	render: function() {
		var admin = this.props.admin;
		var number = this.props.week.Number;
		var weekEdit = "";
		function pad(number) {
			if (number < 10) {
				return '0' + number;
			}
			return number;
		}
		if(admin) {
			var playDateId  = "play-date-" + number;
			var scenariosId = "scenarios-" + number;
			var dateDefault = "";
			var playDate = this.props.week.PlayDate;

			if(playDate) {
				playDate = new Date(playDate);
				dateDefault = playDate.getFullYear() + '-' + pad(playDate.getMonth() + 1) + '-' + pad(playDate.getDate());
			}
			weekEdit = (

						Play Date
						<input id={playDateId} className="form-control" type="date" ref="playDate" placeholder="YYYY-MM-DD"
							defaultValue={dateDefault}  />

						Scenarios (comma separated)
						<input id={scenariosId} className="form-control" type="text" ref="scenarios" pattern="((\d+)(,\d+)*)?"
							defaultValue={this.props.week.Scenarios && this.props.week.Scenarios.join(",")} />

					<button type="submit" className="btn btn-default" onClick={this.updateWeek(number)}>Submit</button>

			);
		}
		return (

				{weekEdit}
				<WeekTable week={this.props.week} admin={this.props.admin} />

		);
	}
});

module.exports = React.createClass({
	propTypes: {
		season: React.PropTypes.object.isRequired
	},
	render: function(): ?ReactElement {
		var admin = this.props.admin;
		var rows = this.props.season.Weeks.map(function(week) {
			var header = "Week " + week.Number;
			if(week.PlayDate)
				header += " (" + new Date(week.PlayDate).toLocaleDateString() + ")";
			if(week.Scenarios)
				header += " - Scenario Numbers: [" + week.Scenarios.join(", ") + "]";
			return(
					<Panel header={header} eventKey={week.Number}>
						<WeekGroup week={week} admin={admin} key={week.Number}/>
					</Panel>
			);
		});
		return (

				<Grid>
					<Row>
						<PageHeader>{this.props.season.Name + " (" + this.props.season.Year + ")"}</PageHeader>
					</Row>
					<Row>
						<Accordion>{rows}</Accordion>
					</Row>
				</Grid>

		);
	}
});
<|endoftext|>


<commit_before>import {badRequest, notFound} from 'boom'
import Joi from 'joi'
import Logger from '@modulus/logger'
import Slug from 'slug'

import Post from '../models/blog/post'

let logger = Logger('handlers/post')

export default {

  /////////// Post.create \\\\\\\\\\
  create: {
    validate: {
      payload: {
        title: Joi.string().required(),
        image: Joi.string(),
        caption: Joi.string(),
        content: Joi.string().required(),
        tags: Joi.array()
      }
    },
    handler: function (request, reply) {
      let {caption, content, image, tags, title} = request.payload

      let newPost =  {
        title: title,
        slug: Slug(title, { lower: true }),
        image: image,
        caption: caption,
        content: content,
        tags: tags
      }

      new Post(newPost).save((err, created) => {
        if (err) {
          logger.error(`Post.create error: ${err.message}`)
          return reply(badRequest(err.message))
        }

        logger.debug(`Post.create saved ${JSON.stringify(created)}`)
        reply(created)
      })
    }
  },

  ////////// Post.get \\\\\\\\\\
  get: {
    validate: {
      params: {
        slug: Joi.string().required()
      }
    },
    handler: function (request, reply) {
      Post.findOne({ slug: request.params.slug }, (err, post) => {
        if (err) {
          logger.error(`Job.findOne error: ${err.message}`)
          return reply(badRequest(err.message))
        }

        logger.debug(`Post.findOne found ${JSON.stringify(post)}`)
        reply(post)
      })
    }
  },

  ////////// Post.getAll \\\\\\\\\\
  getAll: {
    handler: function (request, reply) {
      Post.find({}, (err, posts) => {
        if (err) {
          logger.error(`Post.find error: ${err.message}`)
          return reply(badRequest(err.message))
        }

        logger.debug(`Post.find found ${JSON.stringify(posts)}`)
        reply(posts)
      })
    }
  },

  ////////// Post.remove \\\\\\\\\\
  remove: {
    validate: {
      params: {
        slug: Joi.string().required()
      }
    },
    handler: function (request, reply) {
      Post.remove({ id: request.params.id }, (err) => {
        if (err) {
          logger.error(`Post.remove error: ${err.message}`)
          return reply(badRequest(err.message))
        }

        logger.debug(`Post.remove removed ${request.params.id}`)
        reply()
      })
    }
  },

  ////////// Post.update \\\\\\\\\\
  update: {
    validate: {
      params: {
        slug: Joi.string().required()
      },
      payload: {
        title: Joi.string(),
        image: Joi.string(),
        caption: Joi.string(),
        content: Joi.string(),
        tags: Joi.array()
      }
    },
    handler: function (request, reply) {
      let {params, payload} = request

      Post.update({ id: params.id }, payload, (err) => {
        if (err) {
          logger.error(`Post.update error: ${err.message}`)
          return reply(badRequest(err.message))
        }

        logger.debug(`Post.update updated ${params.id}`)
        reply(params.id)
      })
    }
  }
}
<commit_msg>Add `latest` to various<commit_after>import {badRequest, notFound} from 'boom'
import Joi from 'joi'
import Logger from '@modulus/logger'
import Slug from 'slug'

import Post from '../models/blog/post'

let logger = Logger('handlers/post')

export default {

  /////////// Post.create \\\\\\\\\\
  create: {
    validate: {
      payload: {
        title: Joi.string().required(),
        image: Joi.string(),
        caption: Joi.string(),
        content: Joi.string().required(),
        tags: Joi.array()
      }
    },
    handler: function (request, reply) {
      let {caption, content, image, tags, title} = request.payload

      let newPost =  {
        title: title,
        slug: Slug(title, { lower: true }),
        image: image,
        caption: caption,
        content: content,
        tags: tags
      }

      new Post(newPost).save((err, created) => {
        if (err) {
          logger.error(`Post.create error: ${err.message}`)
          return reply(badRequest(err.message))
        }

        Post.update(
          { slug: { $ne: created.slug } },
          { latest: false },
          { multi: true },
          (err, count) => {
            if (err) {
              logger.error(`Post.update error: ${err.message}`)
              return reply(badRequest(err.message))
            }

            logger.debug(`Post.update updated latest`)
            logger.debug(`Post.create saved ${JSON.stringify(created)}`)

            reply(created)
          })
      })
    }
  },

  ////////// Post.get \\\\\\\\\\
  get: {
    validate: {
      params: {
        slug: Joi.string().required()
      }
    },
    handler: function (request, reply) {
      Post.findOne({ slug: request.params.slug }, (err, post) => {
        if (err) {
          logger.error(`Job.findOne error: ${err.message}`)
          return reply(badRequest(err.message))
        }

        logger.debug(`Post.findOne found ${JSON.stringify(post)}`)
        reply(post)
      })
    }
  },

  ////////// Post.getAll \\\\\\\\\\
  getAll: {
    validate: {
      query: {
        latest: Joi.boolean()
      }
    },
    handler: function (request, reply) {
      let query = request.query && request.query.latest ? { latest: true } : {}

      Post.find(query, (err, posts) => {
        if (err) {
          logger.error(`Post.find error: ${err.message}`)
          return reply(badRequest(err.message))
        }

        logger.debug(`Post.find found ${JSON.stringify(posts)}`)
        reply(posts)
      })
    }
  },

  ////////// Post.remove \\\\\\\\\\
  remove: {
    validate: {
      params: {
        slug: Joi.string().required()
      }
    },
    handler: function (request, reply) {
      Post.remove({ id: request.params.id }, (err) => {
        if (err) {
          logger.error(`Post.remove error: ${err.message}`)
          return reply(badRequest(err.message))
        }

        logger.debug(`Post.remove removed ${request.params.id}`)
        reply()
      })
    }
  },

  ////////// Post.update \\\\\\\\\\
  update: {
    validate: {
      params: {
        slug: Joi.string().required()
      },
      payload: {
        title: Joi.string(),
        image: Joi.string(),
        caption: Joi.string(),
        content: Joi.string(),
        tags: Joi.array(),
        latest: Joi.boolean()
      }
    },
    handler: function (request, reply) {
      let {params, payload} = request

      Post.update({ id: params.id }, payload, (err) => {
        if (err) {
          logger.error(`Post.update error: ${err.message}`)
          return reply(badRequest(err.message))
        }

        logger.debug(`Post.update updated ${params.id}`)
        reply(params.id)
      })
    }
  }
}
<|endoftext|>


<commit_before>'use strict';

// A way to enable/disable this Server Extension even when it is included in the /server_extensions/ directory
var EXTENSION_ENABLED = false;

var Configuration = require('./configuration/configuration');

var gcm = require('node-gcm');
var gcmsender = new gcm.Sender(Configuration.gcmApiKey);

var winston = require('winston');

// Logger
var wlog = new (winston.Logger)({
    transports: [
      new (winston.transports.Console)(),
      // Logger is first loaded from ../../server.js so the path is relative to it!
      new (winston.transports.File)({ filename: './server_extensions/android-gcm/log/log.json' })
    ]
});

// Our custom Database functions
var Database = require('./database/database');

// Database functions borrowed from Server that we might need
//var ServerClientDatabase = require('../../database/clientdb');
//var ServerBaseDatabase = require('../../database/basedb');

// Entry points for this Server Extension
module.exports = {
    // Used by ../server_extensions.js
    isEnabled: function () {
        return EXTENSION_ENABLED;
    },

    // Base sent a System Message to Server. We can see what is sent here.
    onBaseSystemMessage: function (params) {
        // "params" contains:
        // params.IDbase -> sender of this message
        // params.baseid -> sender of this message
        // params.bp -> contents of the message
    },

    // Base sent a Message to Server which is forwarded to all associated Clients.
    // This function is called for each Client that is supposed to receive it.
    // Here we can see if it was forwarded to Client right now, or it is queued on Server.
    onBaseMessage: function (params) {
        // "params" contains:
        // params.IDbase -> sender of this message
        // params.baseid -> sender of this message
        // params.IDclient -> IDclient of Client who is supposed to receive this message from Base
        // params.sent -> boolean saying if this message is sent to Client
        // params.bp -> contents of the message as Base sent it (in baseMessage.js format)
        // params.cm -> contens of the message as is being forwarded to Client (in clientMessage.js format)
        // To check if this is a notification-type message, simply do: params.bp.getIsNotification()

        if (!params.sent) {
            wlog.info('Sending New Message Android GCM to Client IDclient=', params.IDclient);

            var gcmmessage = new gcm.Message({
                collapseKey: 'tickle',
                delayWhileIdle: true,
                timeToLive: 3,
                data: { 'what': 'tickle-tickle', 'why': 'onBaseMessage', 'baseid': params.baseid }
            });

            notifyClient(params.IDclient, gcmmessage);
        }
    },

    // Base went offline or is now connected.
    // Here we can see if that notification was sent to Client or not because the Client is offline.
    onBaseStatusChange: function (params) {
        // "params" contains:
        // params.IDbase -> sender of this message
        // params.baseid -> sender of this message
        // params.IDclient -> IDclient of Client who is supposed to receive this notification
        // params.sent -> boolean saying if this message is sent to Client
        // params.connected -> boolean saying if Base is now connected or disconnected

        if (!params.sent) {
            wlog.info('Sending Base Status Android GCM to Client IDclient=', params.IDclient);

            var gcmmessage = new gcm.Message({
                collapseKey: 'tickle',
                delayWhileIdle: true,
                timeToLive: 3,
                data: { 'what': 'tickle-tickle', 'why': 'onBaseStatusChange', 'baseid': params.baseid, 'connected': params.connected }
            });

            notifyClient(params.IDclient, gcmmessage);
        }
    },

    // Client sent a System Message to Server. We can see what is sent here.
    onClientSystemMessage: function (params) {
        // "params" contains:
        // params.IDclient -> sender of this message
        // params.cm -> contents of the message

        var d = params.cm.getData();

        // Android Client sent us his Device RegId. Lets update it to Database
        if (("type" in d) && d.type == 'ext_android_gcm_myregid') {
            if (("regid" in d) && (typeof d.regid == "string")) {
                wlog.info("Adding/Updating Android regId:", d.regid, ", for IDclient=", params.IDclient);
                Database.updateAndroidRegId(params.IDclient, d.regid, function (err) {
                    if (err) {
                        wlog.error("Database Error in updateAndroidRegId()!");
                        return;
                    }
                });
            }
        }
    },

    // Client sent a Message to Server which is forwarded to all targeted Bases.
    // This function is called for each Base that is supposed to receive it.
    // Here we can see if it was forwarded to Base right now, or it is queued on Server.
    onClientMessage: function (params) {
        // "params" contains:
        // params.IDclient -> sender of this message
        // params.IDbase -> IDbase of Base who is supposed to receive this message from Client
        // params.baseid -> baseid of Base who is supposed to receive this message from Client
        // params.sent -> boolean saying if this message is sent to Base
        // params.cm -> contents of the message as Client sent it (in clientMessage.js format).
        // Note: there is no message in baseMessage.js format, but can be added if required.
        // To check if this is a notification-type message, simply do: params.cm.getIsNotification()
    },

    // Client went offline or is now connected.
    onClientStatusChange: function (params) {
        // "params" contains:
        // params.IDclient -> sender of this message
        // params.connected -> boolean saying if Client is now connected or disconnected
    }
};

// Private functions of this Extension
function notifyClient(IDclient, gcmmessage) {

    // Get regId of this IDclient
    Database.getClientRegId(IDclient, function (err, rows, columns) {
        if (err) {
            wlog.error("Database Error in getClientsRegId()!");
            return;
        }

        // No Android regId for this Client? Maybe he is not Android Client after all...
        if (rows.length <= 0) {
            return;
        }

        // We get just one record for each IDclient...
        // Note: It would be best if we could send just one GCM request for each Client that will
        // receve this notification, but we get called for each Client so this is not possible.
        // It can be made possible but then we would need to check wether each Client is actually
        // connected to Server or not, and then make a decision to send or not to send him a GCM.
        // Maybe it should be done that way... TODO!

        var regIds = [];
        regIds.push(rows[0].regid);

        // Params: message-literal, registrationIds-array, No. of retries, callback-function
        gcmsender.send(gcmmessage, regIds, 4, function (err, result) {
            if (err) {
                wlog.error('Error in gcmsender.send()', err, result);
                return;
            }

            wlog.info('GCM Request OK, handling response...');

            for (var i = 0; i < result.results.length; i++) {
                if (result.results[i].error == 'InvalidRegistration' || result.results[i].error == 'MissingRegistration') {
                    wlog.info('GCM said', result.results[i].error, ', will delete Android regId:', regIds[i].toString());

                    Database.deleteAndroidDevice(regIds[i], function (err, result) {
                        if (err) {
                            wlog.error("Database Error in deleteAndroidDevice()!");
                            return;
                        }
                    });
                }

                if (("registration_id" in result.results[i])) {
                    Database.changeAndroidRegId(result.results[i].registration_id, regIds[i], function (err, result) {
                        if (err) {
                            wlog.error("Database Error in changeAndroidRegId()!");
                            return;
                        }
                    });
                }
            }
        });

    });
}
<commit_msg>fixed a bug in android-gcm extension. now it works.<commit_after>'use strict';

// A way to enable/disable this Server Extension even when it is included in the /server_extensions/ directory
var EXTENSION_ENABLED = false;

var Configuration = require('./configuration/configuration');

var gcm = require('node-gcm');
var gcmsender = new gcm.Sender(Configuration.gcmApiKey);

var winston = require('winston');

// Logger
var wlog = new (winston.Logger)({
    transports: [
      new (winston.transports.Console)(),
      // Logger is first loaded from ../../server.js so the path is relative to it!
      new (winston.transports.File)({ filename: './server_extensions/android-gcm/log/log.json' })
    ]
});

// Our custom Database functions
var Database = require('./database/database');

// Database functions borrowed from Server that we might need
//var ServerClientDatabase = require('../../database/clientdb');
//var ServerBaseDatabase = require('../../database/basedb');

// Entry points for this Server Extension
module.exports = {
    // Used by ../server_extensions.js
    isEnabled: function () {
        return EXTENSION_ENABLED;
    },

    // Base sent a System Message to Server. We can see what is sent here.
    onBaseSystemMessage: function (params) {
        // "params" contains:
        // params.IDbase -> sender of this message
        // params.baseid -> sender of this message
        // params.bp -> contents of the message
    },

    // Base sent a Message to Server which is forwarded to all associated Clients.
    // This function is called for each Client that is supposed to receive it.
    // Here we can see if it was forwarded to Client right now, or it is queued on Server.
    onBaseMessage: function (params) {
        // "params" contains:
        // params.IDbase -> sender of this message
        // params.baseid -> sender of this message
        // params.IDclient -> IDclient of Client who is supposed to receive this message from Base
        // params.sent -> boolean saying if this message is sent to Client
        // params.bp -> contents of the message as Base sent it (in baseMessage.js format)
        // params.cm -> contens of the message as is being forwarded to Client (in clientMessage.js format)
        // To check if this is a notification-type message, simply do: params.bp.getIsNotification()

        if (!params.sent) {
            wlog.info('Sending New Message Android GCM to Client IDclient=', params.IDclient);

            var gcmmessage = new gcm.Message({
                collapseKey: 'tickle',
                delayWhileIdle: true,
                timeToLive: 3,
                data: { 'what': 'tickle-tickle', 'why': 'onBaseMessage', 'baseid': params.baseid }
            });

            notifyClient(params.IDclient, gcmmessage);
        }
    },

    // Base went offline or is now connected.
    // Here we can see if that notification was sent to Client or not because the Client is offline.
    onBaseStatusChange: function (params) {
        // "params" contains:
        // params.IDbase -> sender of this message
        // params.baseid -> sender of this message
        // params.IDclient -> IDclient of Client who is supposed to receive this notification
        // params.sent -> boolean saying if this message is sent to Client
        // params.connected -> boolean saying if Base is now connected or disconnected

        if (!params.sent) {
            wlog.info('Sending Base Status Android GCM to Client IDclient=', params.IDclient);

            var gcmmessage = new gcm.Message({
                collapseKey: 'tickle',
                delayWhileIdle: true,
                timeToLive: 3,
                data: { 'what': 'tickle-tickle', 'why': 'onBaseStatusChange', 'baseid': params.baseid, 'connected': params.connected }
            });

            notifyClient(params.IDclient, gcmmessage);
        }
    },

    // Client sent a System Message to Server. We can see what is sent here.
    onClientSystemMessage: function (params) {
        // "params" contains:
        // params.IDclient -> sender of this message
        // params.cm -> contents of the message

        var d = params.cm.getData();

        // Android Client sent us his Device RegId. Lets update it to Database
        if (("type" in d) && d.type == 'ext_android_gcm_myregid') {
            if (("regid" in d) && (typeof d.regid == "string")) {
                wlog.info("Adding/Updating Android regId:", d.regid, ", for IDclient=", params.IDclient);
                Database.updateAndroidRegId(params.IDclient, d.regid, function (err) {
                    if (err) {
                        wlog.error("Database Error in updateAndroidRegId()!");
                        return;
                    }
                });
            }
        }
    },

    // Client sent a Message to Server which is forwarded to all targeted Bases.
    // This function is called for each Base that is supposed to receive it.
    // Here we can see if it was forwarded to Base right now, or it is queued on Server.
    onClientMessage: function (params) {
        // "params" contains:
        // params.IDclient -> sender of this message
        // params.IDbase -> IDbase of Base who is supposed to receive this message from Client
        // params.baseid -> baseid of Base who is supposed to receive this message from Client
        // params.sent -> boolean saying if this message is sent to Base
        // params.cm -> contents of the message as Client sent it (in clientMessage.js format).
        // Note: there is no message in baseMessage.js format, but can be added if required.
        // To check if this is a notification-type message, simply do: params.cm.getIsNotification()
    },

    // Client went offline or is now connected.
    onClientStatusChange: function (params) {
        // "params" contains:
        // params.IDclient -> sender of this message
        // params.connected -> boolean saying if Client is now connected or disconnected
    }
};

// Private functions of this Extension
function notifyClient(IDclient, gcmmessage) {

    // Get regId of this IDclient
    Database.getClientRegId(IDclient, function (err, rows, columns) {
        if (err) {
            wlog.error("Database Error in getClientsRegId()!");
            return;
        }

        // No Android regId for this Client? Maybe he is not Android Client after all...
        if (rows.length <= 0) {
            return;
        }

        // We get just one record for each IDclient...
        // Note: It would be best if we could send just one GCM request for each Client that will
        // receve this notification, but we get called for each Client so this is not possible.
        // It can be made possible but then we would need to check wether each Client is actually
        // connected to Server or not, and then make a decision to send or not to send him a GCM.
        // Maybe it should be done that way... TODO!

        var regids = [
        	rows[0].regid.toString()
        ];

        // Params: message-literal, registrationIds-array, No. of retries, callback-function
        gcmsender.send(gcmmessage, regids, 3, function (err, result) {
            if (err) {
                wlog.error('Error in gcmsender.send()', err, result);
                return;
            }

            wlog.info('GCM Request OK, handling response...');

            for (var i = 0; i < result.results.length; i++) {
                if (result.results[i].error == 'InvalidRegistration' || result.results[i].error == 'MissingRegistration') {
                    wlog.info('GCM said', result.results[i].error, ', will delete Android regId:', regids[i].toString());

                    Database.deleteAndroidDevice(regids[i], function (err, result) {
                        if (err) {
                            wlog.error("Database Error in deleteAndroidDevice()!");
                            return;
                        }
                    });
                }

                if (("registration_id" in result.results[i])) {
                    Database.changeAndroidRegId(result.results[i].registration_id, regids[i], function (err, result) {
                        if (err) {
                            wlog.error("Database Error in changeAndroidRegId()!");
                            return;
                        }
                    });
                }
            }
        });

    });
}
<|endoftext|>


<commit_before>exports.balancer = function() {

}<commit_msg>Implemented a basic balancer function<commit_after>exports.balance = function(rm) {
    var sorted_instances = rm.getInstances().sort(function(a, b) {
        return a.load - b.load;
    });

    return sorted_instances[0];
}<|endoftext|>


<commit_before>var Firebase = require('firebase');
var _ = require('underscore');
var db = new Firebase('https://rebase.firebaseio.com/');
var lastGraphChildKeys = {};
var updating = false;

db.child('graph').on('value', function(snapshot) {
  var oldGraph = snapshot.val();
  if (updating || _.isEqual(lastGraphChildKeys, _.pluck(oldGraph, 'childKeys'))) {
    console.log('ignoring graph update');
    return;
  }

  console.log('recomputing graph');
  var graph = {};

  function expandGraph(frameKey, parentKey, ancestorKeys) {
    console.log('expandGraph', frameKey, parentKey, ancestorKeys);
    var edges = graph[frameKey];
    if (!edges) {
      edges = graph[frameKey] = {
        childKeys: oldGraph[frameKey] && oldGraph[frameKey].childKeys, descendantKeys: {},
        parentKeys: {}, ancestorKeys: {}
      };
    }
    var recurse = false;
    if (parentKey) {
      if (!_.has(edges.parentKeys, parentKey)) {
        edges.parentKeys[parentKey] = 1;
        recurse = true;
      }
    } else {
      recurse = true;
    }
    if (!_.isEmpty(_.omit(ancestorKeys, _.keys(edges.ancestorKeys)))) {
      _.extend(edges.ancestorKeys, ancestorKeys);
      recurse = true;
    }
    if (recurse) {
      var deeperAncestorKeys = _.clone(edges.ancestorKeys);
      deeperAncestorKeys[frameKey] = 1;
      _.each(edges.childKeys, function(unused, childKey) {
        expandGraph(childKey, frameKey, deeperAncestorKeys);
      });
    }
    edges.descendantKeys = _.extend({}, edges.childKeys);
    _.each(edges.childKeys, function(value, childKey) {
      if (childKey in graph) {
        _.extend(edges.descendantKeys, graph[childKey].descendantKeys);
      }
    });
  }

  _.each(oldGraph, function(edges, frameKey) {
    expandGraph(frameKey, null, {});
  });

  console.log(graph);
  lastGraphChildKeys = _.pluck(graph, 'childKeys');
  updating = true;
  try {
    _.each(graph, function(edges, frameKey) {
      var oldEdges = oldGraph[frameKey];
      var diffEdges = {};
      _.each(['parentKeys', 'descendantKeys', 'ancestorKeys'], function(attr) {
        if (!(oldEdges ? _.isEqual(edges[attr], oldEdges[attr] || {}) : _.isEmpty(edges[attr]))) {
          diffEdges[attr] = edges[attr];
        }
      });
      if (!_.isEmpty(diffEdges)) {
        console.log('updating', frameKey);
        db.child('graph/' + frameKey).update(diffEdges);
      }
    });
  } finally {
    updating = false;
  }
});

<commit_msg>Added --prod flag.<commit_after>var Firebase = require('firebase');
var _ = require('underscore');
var argv = require('yargs').argv;
var db = new Firebase(argv.prod ? 'https://learnful.firebaseio.com' : 'https://rebase.firebaseio.com/');
var lastGraphChildKeys = {};
var updating = false;

db.child('graph').on('value', function(snapshot) {
  var oldGraph = snapshot.val();
  if (updating || _.isEqual(lastGraphChildKeys, _.pluck(oldGraph, 'childKeys'))) {
    console.log('ignoring graph update');
    return;
  }

  console.log('recomputing graph');
  var graph = {};

  function expandGraph(frameKey, parentKey, ancestorKeys) {
    console.log('expandGraph', frameKey, parentKey, ancestorKeys);
    var edges = graph[frameKey];
    if (!edges) {
      edges = graph[frameKey] = {
        childKeys: oldGraph[frameKey] && oldGraph[frameKey].childKeys, descendantKeys: {},
        parentKeys: {}, ancestorKeys: {}
      };
    }
    var recurse = false;
    if (parentKey) {
      if (!_.has(edges.parentKeys, parentKey)) {
        edges.parentKeys[parentKey] = 1;
        recurse = true;
      }
    } else {
      recurse = true;
    }
    if (!_.isEmpty(_.omit(ancestorKeys, _.keys(edges.ancestorKeys)))) {
      _.extend(edges.ancestorKeys, ancestorKeys);
      recurse = true;
    }
    if (recurse) {
      var deeperAncestorKeys = _.clone(edges.ancestorKeys);
      deeperAncestorKeys[frameKey] = 1;
      _.each(edges.childKeys, function(unused, childKey) {
        expandGraph(childKey, frameKey, deeperAncestorKeys);
      });
    }
    edges.descendantKeys = _.extend({}, edges.childKeys);
    _.each(edges.childKeys, function(value, childKey) {
      if (childKey in graph) {
        _.extend(edges.descendantKeys, graph[childKey].descendantKeys);
      }
    });
  }

  _.each(oldGraph, function(edges, frameKey) {
    expandGraph(frameKey, null, {});
  });

  console.log(graph);
  lastGraphChildKeys = _.pluck(graph, 'childKeys');
  updating = true;
  try {
    _.each(graph, function(edges, frameKey) {
      var oldEdges = oldGraph[frameKey];
      var diffEdges = {};
      _.each(['parentKeys', 'descendantKeys', 'ancestorKeys'], function(attr) {
        if (!(oldEdges ? _.isEqual(edges[attr], oldEdges[attr] || {}) : _.isEmpty(edges[attr]))) {
          diffEdges[attr] = edges[attr];
        }
      });
      if (!_.isEmpty(diffEdges)) {
        console.log('updating', frameKey);
        db.child('graph/' + frameKey).update(diffEdges);
      }
    });
  } finally {
    updating = false;
  }
});

<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * 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
 *
 *     http://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.
 */

CLASS({
  name: 'QIssueTileView',
  package: 'foam.apps.quickbug.ui',
  label: 'QIssue Tile View',

  requires: [
    'PropertyView'
  ],

  extendsModel: 'foam.ui.View',

  properties: [
    {
      name:  'browser'
    },
    {
      name:  'issue'
    },
    {
      name: 'QIssue',
      defaultValueFn: function() { return this.X.QIssue; }
    }
  ],

  methods: {
    // Implement Sink
    put: function(issue) {
      if ( this.issue ) { this.issue.removeListener(this.onChange); }

      this.issue = issue.clone();
      this.issue.addListener(this.onChange);
    },

    // Implement Adapter
    f: function(issue) {
      var view = this.model_.create({ browser: this.browser }, this.Y);
      view.put(issue);
      return view;
    },

    toString: function() { return this.toHTML(); }
  },

  listeners: [
    {
      name: 'onChange',
      code: function() {
        this.browser.IssueDAO.put(this.issue);
      }
    },
    {
      name: 'dragStart',
      code: function(e) {
        e.dataTransfer.setData('application/x-foam-id', this.issue.id);
        e.dataTransfer.effectAllowed = 'move';
      },
    },
  ],

  templates:[
    { name: 'toHTML' }
  ]
});
<commit_msg>Update require in QIssueTileView<commit_after>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * 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
 *
 *     http://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.
 */

CLASS({
  name: 'QIssueTileView',
  package: 'foam.apps.quickbug.ui',
  label: 'QIssue Tile View',

  requires: [
    'foam.ui.PropertyView'
  ],

  extendsModel: 'foam.ui.View',

  properties: [
    {
      name:  'browser'
    },
    {
      name:  'issue'
    },
    {
      name: 'QIssue',
      defaultValueFn: function() { return this.X.QIssue; }
    }
  ],

  methods: {
    // Implement Sink
    put: function(issue) {
      if ( this.issue ) { this.issue.removeListener(this.onChange); }

      this.issue = issue.clone();
      this.issue.addListener(this.onChange);
    },

    // Implement Adapter
    f: function(issue) {
      var view = this.model_.create({ browser: this.browser }, this.Y);
      view.put(issue);
      return view;
    },

    toString: function() { return this.toHTML(); }
  },

  listeners: [
    {
      name: 'onChange',
      code: function() {
        this.browser.IssueDAO.put(this.issue);
      }
    },
    {
      name: 'dragStart',
      code: function(e) {
        e.dataTransfer.setData('application/x-foam-id', this.issue.id);
        e.dataTransfer.effectAllowed = 'move';
      },
    },
  ],

  templates:[
    { name: 'toHTML' }
  ]
});
<|endoftext|>


<commit_before>'use strict';

angular.module('StorageServices', []).factory('NotesStorage', function($http) {
  var markers = {};

  var createMarker = function(note) {
    var marker = {
      'lat': parseFloat(note.lat),
      'lng': parseFloat(note.lng),
      'message': note.text_content,
      'focus': true,
      'draggable': false
    };
    var id_ = note.id;
    markers[id_] = marker;
  };

  var addNote = function(note) {
    var fd = new FormData();
    fd.append('lat', note.lat);
    fd.append('lng', note.lng);
    fd.append('date', note.date);
    fd.append('text_content', note.text_content);
    // fd.append('media_content', note.mediaContent);
    $http.post('/geonotes', fd, {
      transformRequest: angular.identity,
      headers: {'Content-Type': undefined}
    })
    .success(function(data) {
      createMarker(data);
    })
    .error(function(data) {
      console.log('Error');
    });
  };

  var stored = angular.fromJson(localStorage.getItem('geonauts_cache'));
  if(stored) {
    angular.forEach(stored, addNote);
    localStorage.clear();
  }

  $http.get('/geonotes')
  .success(function(data) {
    angular.forEach(data, createMarker);
  });

  return {
    'markers': markers,
    'addNote': addNote
  };
});
<commit_msg>After load zoom to all visible markers<commit_after>'use strict';

angular.module('StorageServices', []).factory('NotesStorage', function($http, leafletData) {
  var markers = {};

  var createMarker = function(note) {
    var marker = {
      'lat': parseFloat(note.lat),
      'lng': parseFloat(note.lng),
      'message': note.text_content,
      'focus': true,
      'draggable': false
    };
    var id_ = note.id;
    markers[id_] = marker;
  };

  var addNote = function(note) {
    var fd = new FormData();
    fd.append('lat', note.lat);
    fd.append('lng', note.lng);
    fd.append('date', note.date);
    fd.append('text_content', note.text_content);
    // fd.append('media_content', note.mediaContent);
    $http.post('/geonotes', fd, {
      transformRequest: angular.identity,
      headers: {'Content-Type': undefined}
    })
    .success(function(data) {
      createMarker(data);
    })
    .error(function(data) {
      console.log('Error');
    });
  };

  var zoomToMarkers = function(current_loc) {
    var current_loc = current_loc || {};
    var minLat = current_loc.lat || 1000;
    var maxLat = current_loc.lat || -1000;
    var minLng = current_loc.lng || 1000;
    var maxLng = current_loc.lng || -1000;

    for (var key in markers) {
      var marker = markers[key]
      minLat = Math.min(minLat, marker.lat)
      maxLat = Math.max(maxLat, marker.lat)
      minLng = Math.min(minLng, marker.lng)
      maxLng = Math.max(maxLng, marker.lng)
    }

    var height = maxLat - minLat;
    var width = maxLng - minLng;
    leafletData.getMap().then(function(m) {
      m.fitBounds([
        [minLat - 0.05*height, minLng - 0.05*width],
        [maxLat + 0.05*height, maxLng + 0.05*width]
      ]);
    });
  };

  var stored = angular.fromJson(localStorage.getItem('geonauts_cache'));
  if(stored) {
    angular.forEach(stored, addNote);
    localStorage.clear();
  }

  $http.get('/geonotes')
  .success(function(data) {
    angular.forEach(data, createMarker);
    zoomToMarkers(null);
  });

  return {
    'markers': markers,
    'addNote': addNote,
    'createMarker': createMarker,
    'zoomToMarkers': zoomToMarkers,
  };
});

// Local Variables:
// js-indent-level: 2
// End:
<|endoftext|>


<commit_before>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
// @ts-check

/// <reference no-default-lib="true"/>
/// <reference lib="webworker" />

const sw = /** @type {ServiceWorkerGlobalScope} */ (/** @type {any} */ (self));

const VERSION = 2;

const resourceCacheName = `vscode-resource-cache-${VERSION}`;

const rootPath = sw.location.pathname.replace(/\/service-worker.js$/, '');

const searchParams = new URL(location.toString()).searchParams;

/**
 * Origin used for resources
 */
const resourceBaseAuthority = searchParams.get('vscode-resource-base-authority');

const resolveTimeout = 30000;

/**
 * @template T
 * @typedef {{
 *     resolve: (x: T) => void,
 *     promise: Promise<T>
 * }} RequestStoreEntry
 */

/**
 * Caches
 * @template T
 */
class RequestStore {
	constructor() {
		/** @type {Map<number, RequestStoreEntry<T>>} */
		this.map = new Map();

		this.requestPool = 0;
	}

	/**
	 * @param {number} requestId
	 * @return {Promise<T> | undefined}
	 */
	get(requestId) {
		const entry = this.map.get(requestId);
		return entry && entry.promise;
	}

	/**
	 * @returns {{ requestId: number, promise: Promise<T> }}
	 */
	create() {
		const requestId = ++this.requestPool;

		/** @type {undefined | ((x: T) => void)} */
		let resolve;

		/** @type {Promise<T>} */
		const promise = new Promise(r => resolve = r);

		/** @type {RequestStoreEntry<T>} */
		const entry = { resolve: /** @type {(x: T) => void} */ (resolve), promise };

		this.map.set(requestId, entry);

		const dispose = () => {
			clearTimeout(timeout);
			const existingEntry = this.map.get(requestId);
			if (existingEntry === entry) {
				return this.map.delete(requestId);
			}
		};
		const timeout = setTimeout(dispose, resolveTimeout);
		return { requestId, promise };
	}

	/**
	 * @param {number} requestId
	 * @param {T} result
	 * @return {boolean}
	 */
	resolve(requestId, result) {
		const entry = this.map.get(requestId);
		if (!entry) {
			return false;
		}
		entry.resolve(result);
		this.map.delete(requestId);
		return true;
	}
}

/**
 * Map of requested paths to responses.
 * @typedef {{ type: 'response', body: any, mime: string, etag: string | undefined, } | { type: 'not-modified', mime: string } | undefined} ResourceResponse
 * @type {RequestStore<ResourceResponse>}
 */
const resourceRequestStore = new RequestStore();

/**
 * Map of requested localhost origins to optional redirects.
 *
 * @type {RequestStore<string | undefined>}
 */
const localhostRequestStore = new RequestStore();

const notFound = () =>
	new Response('Not Found', { status: 404, });

sw.addEventListener('message', async (event) => {
	switch (event.data.channel) {
		case 'version':
			{
				const source = /** @type {Client} */ (event.source);
				sw.clients.get(source.id).then(client => {
					if (client) {
						client.postMessage({
							channel: 'version',
							version: VERSION
						});
					}
				});
				return;
			}
		case 'did-load-resource':
			{
				/** @type {ResourceResponse} */
				let response = undefined;

				const data = event.data.data;
				switch (data.status) {
					case 200:
						{
							response = { type: 'response', body: data.data, mime: data.mime, etag: data.etag };
							break;
						}
					case 304:
						{
							response = { type: 'not-modified', mime: data.mime };
							break;
						}
				}

				if (!resourceRequestStore.resolve(data.id, response)) {
					console.log('Could not resolve unknown resource', data.path);
				}
				return;
			}
		case 'did-load-localhost':
			{
				const data = event.data.data;
				if (!localhostRequestStore.resolve(data.id, data.location)) {
					console.log('Could not resolve unknown localhost', data.origin);
				}
				return;
			}
	}

	console.log('Unknown message');
});

sw.addEventListener('fetch', (event) => {
	const requestUrl = new URL(event.request.url);
	if (requestUrl.protocol === 'https:' && requestUrl.hostname.endsWith('.' + resourceBaseAuthority)) {
		return event.respondWith(processResourceRequest(event, requestUrl));
	}

	// See if it's a localhost request
	if (requestUrl.origin !== sw.origin && requestUrl.host.match(/^(localhost|127.0.0.1|0.0.0.0):(\d+)$/)) {
		return event.respondWith(processLocalhostRequest(event, requestUrl));
	}
});

sw.addEventListener('install', (event) => {
	event.waitUntil(sw.skipWaiting()); // Activate worker immediately
});

sw.addEventListener('activate', (event) => {
	event.waitUntil(sw.clients.claim()); // Become available to all pages
});

/**
 * @param {FetchEvent} event
 * @param {URL} requestUrl
 */
async function processResourceRequest(event, requestUrl) {
	const client = await sw.clients.get(event.clientId);
	if (!client) {
		console.error('Could not find inner client for request');
		return notFound();
	}

	const webviewId = getWebviewIdForClient(client);
	if (!webviewId) {
		console.error('Could not resolve webview id');
		return notFound();
	}

	/**
	 * @param {ResourceResponse} entry
	 * @param {Response | undefined} cachedResponse
	 */
	async function resolveResourceEntry(entry, cachedResponse) {
		if (!entry) {
			return notFound();
		}

		if (entry.type === 'not-modified') {
			if (cachedResponse) {
				return cachedResponse.clone();
			} else {
				throw new Error('No cache found');
			}
		}

		/** @type {Record<String, string>} */
		const headers = {
			'Content-Type': entry.mime,
			'Access-Control-Allow-Origin': '*',
		};
		if (entry.etag) {
			headers['ETag'] = entry.etag;
			headers['Cache-Control'] = 'no-cache';
		}
		const response = new Response(entry.body, {
			status: 200,
			headers
		});

		if (entry.etag) {
			caches.open(resourceCacheName).then(cache => {
				return cache.put(event.request, response);
			});
		}
		return response.clone();
	}

	const parentClients = await getOuterIframeClient(webviewId);
	if (!parentClients.length) {
		console.log('Could not find parent client for request');
		return notFound();
	}

	const cache = await caches.open(resourceCacheName);
	const cached = await cache.match(event.request);

	const { requestId, promise } = resourceRequestStore.create();

	const firstHostSegment = requestUrl.hostname.slice(0, requestUrl.hostname.length - (resourceBaseAuthority.length + 1));
	const scheme = firstHostSegment.split('+', 1)[0];
	const authority = firstHostSegment.slice(scheme.length + 1); // may be empty

	for (const parentClient of parentClients) {
		parentClient.postMessage({
			channel: 'load-resource',
			id: requestId,
			path: requestUrl.pathname,
			scheme,
			authority,
			query: requestUrl.search.replace(/^\?/, ''),
			ifNoneMatch: cached?.headers.get('ETag'),
		});
	}

	return promise.then(entry => resolveResourceEntry(entry, cached));
}

/**
 * @param {FetchEvent} event
 * @param {URL} requestUrl
 * @return {Promise<Response>}
 */
async function processLocalhostRequest(event, requestUrl) {
	const client = await sw.clients.get(event.clientId);
	if (!client) {
		// This is expected when requesting resources on other localhost ports
		// that are not spawned by vs code
		return fetch(event.request);
	}
	const webviewId = getWebviewIdForClient(client);
	if (!webviewId) {
		console.error('Could not resolve webview id');
		return fetch(event.request);
	}

	const origin = requestUrl.origin;

	/**
	 * @param {string | undefined} redirectOrigin
	 * @return {Promise<Response>}
	 */
	const resolveRedirect = async (redirectOrigin) => {
		if (!redirectOrigin) {
			return fetch(event.request);
		}
		const location = event.request.url.replace(new RegExp(`^${requestUrl.origin}(/|$)`), `${redirectOrigin}$1`);
		return new Response(null, {
			status: 302,
			headers: {
				Location: location
			}
		});
	};

	const parentClients = await getOuterIframeClient(webviewId);
	if (!parentClients.length) {
		console.log('Could not find parent client for request');
		return notFound();
	}

	const { requestId, promise } = localhostRequestStore.create();
	for (const parentClient of parentClients) {
		parentClient.postMessage({
			channel: 'load-localhost',
			origin: origin,
			id: requestId,
		});
	}

	return promise.then(resolveRedirect);
}

/**
 * @param {Client} client
 * @returns {string | null}
 */
function getWebviewIdForClient(client) {
	const requesterClientUrl = new URL(client.url);
	return requesterClientUrl.searchParams.get('id');
}

/**
 * @param {string} webviewId
 * @returns {Promise<Client[]>}
 */
async function getOuterIframeClient(webviewId) {
	const allClients = await sw.clients.matchAll({ includeUncontrolled: true });
	return allClients.filter(client => {
		const clientUrl = new URL(client.url);
		const hasExpectedPathName = (clientUrl.pathname === `${rootPath}/` || clientUrl.pathname === `${rootPath}/index.html` || clientUrl.pathname === `${rootPath}/electron-browser-index.html`);
		return hasExpectedPathName && clientUrl.searchParams.get('id') === webviewId;
	});
}
<commit_msg>Don't cache HEAD requests for local resources<commit_after>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
// @ts-check

/// <reference no-default-lib="true"/>
/// <reference lib="webworker" />

const sw = /** @type {ServiceWorkerGlobalScope} */ (/** @type {any} */ (self));

const VERSION = 2;

const resourceCacheName = `vscode-resource-cache-${VERSION}`;

const rootPath = sw.location.pathname.replace(/\/service-worker.js$/, '');

const searchParams = new URL(location.toString()).searchParams;

/**
 * Origin used for resources
 */
const resourceBaseAuthority = searchParams.get('vscode-resource-base-authority');

const resolveTimeout = 30000;

/**
 * @template T
 * @typedef {{
 *     resolve: (x: T) => void,
 *     promise: Promise<T>
 * }} RequestStoreEntry
 */

/**
 * Caches
 * @template T
 */
class RequestStore {
	constructor() {
		/** @type {Map<number, RequestStoreEntry<T>>} */
		this.map = new Map();

		this.requestPool = 0;
	}

	/**
	 * @param {number} requestId
	 * @return {Promise<T> | undefined}
	 */
	get(requestId) {
		const entry = this.map.get(requestId);
		return entry && entry.promise;
	}

	/**
	 * @returns {{ requestId: number, promise: Promise<T> }}
	 */
	create() {
		const requestId = ++this.requestPool;

		/** @type {undefined | ((x: T) => void)} */
		let resolve;

		/** @type {Promise<T>} */
		const promise = new Promise(r => resolve = r);

		/** @type {RequestStoreEntry<T>} */
		const entry = { resolve: /** @type {(x: T) => void} */ (resolve), promise };

		this.map.set(requestId, entry);

		const dispose = () => {
			clearTimeout(timeout);
			const existingEntry = this.map.get(requestId);
			if (existingEntry === entry) {
				return this.map.delete(requestId);
			}
		};
		const timeout = setTimeout(dispose, resolveTimeout);
		return { requestId, promise };
	}

	/**
	 * @param {number} requestId
	 * @param {T} result
	 * @return {boolean}
	 */
	resolve(requestId, result) {
		const entry = this.map.get(requestId);
		if (!entry) {
			return false;
		}
		entry.resolve(result);
		this.map.delete(requestId);
		return true;
	}
}

/**
 * Map of requested paths to responses.
 * @typedef {{ type: 'response', body: any, mime: string, etag: string | undefined, } | { type: 'not-modified', mime: string } | undefined} ResourceResponse
 * @type {RequestStore<ResourceResponse>}
 */
const resourceRequestStore = new RequestStore();

/**
 * Map of requested localhost origins to optional redirects.
 *
 * @type {RequestStore<string | undefined>}
 */
const localhostRequestStore = new RequestStore();

const notFound = () =>
	new Response('Not Found', { status: 404, });

const methodNotAllowed = () =>
	new Response('Method Not Allowed', { status: 405, });

sw.addEventListener('message', async (event) => {
	switch (event.data.channel) {
		case 'version':
			{
				const source = /** @type {Client} */ (event.source);
				sw.clients.get(source.id).then(client => {
					if (client) {
						client.postMessage({
							channel: 'version',
							version: VERSION
						});
					}
				});
				return;
			}
		case 'did-load-resource':
			{
				/** @type {ResourceResponse} */
				let response = undefined;

				const data = event.data.data;
				switch (data.status) {
					case 200:
						{
							response = { type: 'response', body: data.data, mime: data.mime, etag: data.etag };
							break;
						}
					case 304:
						{
							response = { type: 'not-modified', mime: data.mime };
							break;
						}
				}

				if (!resourceRequestStore.resolve(data.id, response)) {
					console.log('Could not resolve unknown resource', data.path);
				}
				return;
			}
		case 'did-load-localhost':
			{
				const data = event.data.data;
				if (!localhostRequestStore.resolve(data.id, data.location)) {
					console.log('Could not resolve unknown localhost', data.origin);
				}
				return;
			}
	}

	console.log('Unknown message');
});

sw.addEventListener('fetch', (event) => {
	const requestUrl = new URL(event.request.url);
	if (requestUrl.protocol === 'https:' && requestUrl.hostname.endsWith('.' + resourceBaseAuthority)) {
		switch (event.request.method) {
			case 'GET':
			case 'HEAD':
				return event.respondWith(processResourceRequest(event, requestUrl));

			default:
				return event.respondWith(methodNotAllowed());
		}
	}

	// See if it's a localhost request
	if (requestUrl.origin !== sw.origin && requestUrl.host.match(/^(localhost|127.0.0.1|0.0.0.0):(\d+)$/)) {
		return event.respondWith(processLocalhostRequest(event, requestUrl));
	}
});

sw.addEventListener('install', (event) => {
	event.waitUntil(sw.skipWaiting()); // Activate worker immediately
});

sw.addEventListener('activate', (event) => {
	event.waitUntil(sw.clients.claim()); // Become available to all pages
});

/**
 * @param {FetchEvent} event
 * @param {URL} requestUrl
 */
async function processResourceRequest(event, requestUrl) {
	const client = await sw.clients.get(event.clientId);
	if (!client) {
		console.error('Could not find inner client for request');
		return notFound();
	}

	const webviewId = getWebviewIdForClient(client);
	if (!webviewId) {
		console.error('Could not resolve webview id');
		return notFound();
	}

	const shouldTryCaching = (event.request.method === 'GET');

	/**
	 * @param {ResourceResponse} entry
	 * @param {Response | undefined} cachedResponse
	 */
	async function resolveResourceEntry(entry, cachedResponse) {
		if (!entry) {
			return notFound();
		}

		if (entry.type === 'not-modified') {
			if (cachedResponse) {
				return cachedResponse.clone();
			} else {
				throw new Error('No cache found');
			}
		}

		/** @type {Record<String, string>} */
		const headers = {
			'Content-Type': entry.mime,
			'Access-Control-Allow-Origin': '*',
		};
		if (entry.etag) {
			headers['ETag'] = entry.etag;
			headers['Cache-Control'] = 'no-cache';
		}
		const response = new Response(entry.body, {
			status: 200,
			headers
		});

		if (shouldTryCaching && entry.etag) {
			caches.open(resourceCacheName).then(cache => {
				return cache.put(event.request, response);
			});
		}
		return response.clone();
	}

	const parentClients = await getOuterIframeClient(webviewId);
	if (!parentClients.length) {
		console.log('Could not find parent client for request');
		return notFound();
	}

	/** @type {Response | undefined} */
	let cached;
	if (shouldTryCaching) {
		const cache = await caches.open(resourceCacheName);
		cached = await cache.match(event.request);
	}

	const { requestId, promise } = resourceRequestStore.create();

	const firstHostSegment = requestUrl.hostname.slice(0, requestUrl.hostname.length - (resourceBaseAuthority.length + 1));
	const scheme = firstHostSegment.split('+', 1)[0];
	const authority = firstHostSegment.slice(scheme.length + 1); // may be empty

	for (const parentClient of parentClients) {
		parentClient.postMessage({
			channel: 'load-resource',
			id: requestId,
			path: requestUrl.pathname,
			scheme,
			authority,
			query: requestUrl.search.replace(/^\?/, ''),
			ifNoneMatch: cached?.headers.get('ETag'),
		});
	}

	return promise.then(entry => resolveResourceEntry(entry, cached));
}

/**
 * @param {FetchEvent} event
 * @param {URL} requestUrl
 * @return {Promise<Response>}
 */
async function processLocalhostRequest(event, requestUrl) {
	const client = await sw.clients.get(event.clientId);
	if (!client) {
		// This is expected when requesting resources on other localhost ports
		// that are not spawned by vs code
		return fetch(event.request);
	}
	const webviewId = getWebviewIdForClient(client);
	if (!webviewId) {
		console.error('Could not resolve webview id');
		return fetch(event.request);
	}

	const origin = requestUrl.origin;

	/**
	 * @param {string | undefined} redirectOrigin
	 * @return {Promise<Response>}
	 */
	const resolveRedirect = async (redirectOrigin) => {
		if (!redirectOrigin) {
			return fetch(event.request);
		}
		const location = event.request.url.replace(new RegExp(`^${requestUrl.origin}(/|$)`), `${redirectOrigin}$1`);
		return new Response(null, {
			status: 302,
			headers: {
				Location: location
			}
		});
	};

	const parentClients = await getOuterIframeClient(webviewId);
	if (!parentClients.length) {
		console.log('Could not find parent client for request');
		return notFound();
	}

	const { requestId, promise } = localhostRequestStore.create();
	for (const parentClient of parentClients) {
		parentClient.postMessage({
			channel: 'load-localhost',
			origin: origin,
			id: requestId,
		});
	}

	return promise.then(resolveRedirect);
}

/**
 * @param {Client} client
 * @returns {string | null}
 */
function getWebviewIdForClient(client) {
	const requesterClientUrl = new URL(client.url);
	return requesterClientUrl.searchParams.get('id');
}

/**
 * @param {string} webviewId
 * @returns {Promise<Client[]>}
 */
async function getOuterIframeClient(webviewId) {
	const allClients = await sw.clients.matchAll({ includeUncontrolled: true });
	return allClients.filter(client => {
		const clientUrl = new URL(client.url);
		const hasExpectedPathName = (clientUrl.pathname === `${rootPath}/` || clientUrl.pathname === `${rootPath}/index.html` || clientUrl.pathname === `${rootPath}/electron-browser-index.html`);
		return hasExpectedPathName && clientUrl.searchParams.get('id') === webviewId;
	});
}
<|endoftext|>


<commit_before>function App(viewDiv, twitterScreenName)
{
    var app = this;

    this.view = new View(viewDiv);
    this.view.addClicked = function() { app.onViewAddClicked(); };
    this.view.itemRemoveClicked = function(item) { app.onViewItemRemoveClicked(item); };
    this.view.itemChangeClicked = function(item) { app.onViewItemChangeClicked(item); };

    this.model = new Model();
    this.model.itemsLoaded = function() { app.onModelItemsLoaded(); };
    this.model.itemRemoved = function(item) { app.onModelItemRemoved(item); };
    this.model.load(twitterScreenName);
}

App.prototype.onViewAddClicked = function()
{
    var model = this.model;
    var input = $('#newTextInput');
    input.val('');
    $('#newTextSubmit').unbind('click').click(function()
    {
	model.add(input.val());
	$('#newTextDialog').dialog('close');
    });
    $.mobile.changePage('#newTextDialog');
};

App.prototype.onViewItemRemoveClicked = function(item)
{
    this.model.remove(item.name);
};

App.prototype.onViewItemChangeClicked = function(item)
{
    var model = this.model;
    var input = $('#newTextInput');
    var name = item.name;
    input.val(name);
    $('#newTextSubmit').unbind('click').click(function()
    {
	model.change(name, input.val());
	$('#newTextDialog').dialog('close');
    });
    $.mobile.changePage('#newTextDialog');
};

App.prototype.onModelItemsLoaded = function()
{
    this.view.refresh(this.model.items);
};

App.prototype.onModelItemRemoved = function(item)
{
    this.view.remove(item);
};
<commit_msg>Extract duplicate code re new text dialog<commit_after>function App(viewDiv, twitterScreenName)
{
    var app = this;

    this.view = new View(viewDiv);
    this.view.addClicked = function() { app.onViewAddClicked(); };
    this.view.itemRemoveClicked = function(item) { app.onViewItemRemoveClicked(item); };
    this.view.itemChangeClicked = function(item) { app.onViewItemChangeClicked(item); };

    this.model = new Model();
    this.model.itemsLoaded = function() { app.onModelItemsLoaded(); };
    this.model.itemRemoved = function(item) { app.onModelItemRemoved(item); };
    this.model.load(twitterScreenName);
}

App.prototype.onViewAddClicked = function()
{
    var model = this.model;
	this.showNewTextDialog('', function(newText) { model.add(newText); });
};

App.prototype.onViewItemRemoveClicked = function(item)
{
    this.model.remove(item.name);
};

App.prototype.onViewItemChangeClicked = function(item)
{
    var model = this.model;
    var name = item.name;
	this.showNewTextDialog(name, function(newText) { model.change(name, newText); });
};

App.prototype.onModelItemsLoaded = function()
{
    this.view.refresh(this.model.items);
};

App.prototype.onModelItemRemoved = function(item)
{
    this.view.remove(item);
};

App.prototype.showNewTextDialog = function(text, callback)
{
    var input = $('#newTextInput');
    input.val(text);
    $('#newTextSubmit').unbind('click').click(function()
    {
        callback(input.val());
        $('#newTextDialog').dialog('close');
    });
    $.mobile.changePage('#newTextDialog');
};
<|endoftext|>


<commit_before>const uuid = require('uuid');
const request = require('request');

module.exports = function initialize(params) {
  const communicationsKey = params.communicationsKey;
  const knex = params.knex;
  const sebacon = params.sebacon;

  function login(req, res) {
    const ssoId = req.body.ssoid;
    const validationReq = {
      id: uuid.v4(),
      method: "GetUser",
      params: [
        communicationsKey,
        ssoId
      ],
      jsonrpc: "2.0"
    };
    request.post({
      url: 'https://tunnistus.avoine.fi/mmserver',
      json: validationReq
    }, (err, response, body) => {
      if (err) {
        console.error(err);
        return res.status(500).send('Jotain meni pieleen');
      }

      if (body.error) {
        console.log(body);
        req.session = null;
        return res.status(400).send('Kirjautuminen epäonnistui');
      }

      const sessionId = uuid.v4();
      const remoteId = body.result.local_id;
      return knex('users').where({ remote_id: remoteId })
        .then((resp) => {
          if (resp.length === 0) {
            return Promise.all([
              sebacon.getUserFirstName(remoteId),
              sebacon.getUserNickName(remoteId),
              sebacon.getUserPositions(remoteId),
              sebacon.getUserDomains(remoteId)
            ]).then(([firstname, nickname, positions, domains]) => {
              return knex('users')
                .insert({
                  remote_id: body.result.local_id,
                  data: {
                    name: nickname || firstname,
                    domains: domains.map(d => ({ heading: d, skill_level: 1 })),
                    positions: positions.map(d => ({ heading: d, skill_level: 1 })),
                    profile_creation_consented: false
                  }
                }, 'id') // postgres does not automatically return the id, ask for it explicitly
            })
              .then(insertResp => ({ id: insertResp[0] }))
          } else {
            return resp[0];
          }
        })
        .then((user) => {
          return knex('sessions').insert({
            id: sessionId,
            user_id: user.id
          }).then(() => {
            req.session.id = sessionId;
            return res.redirect(req.query.path || '/');
          });
        })
    });
  }

  function logout(req, res) {
    const sessionId = req.session.id || 'nosession';
    req.session = null;
    return knex('sessions').where({id: sessionId}).del()
      .then(() => res.redirect('https://tunnistus.avoine.fi/sso-logout/'));
  }

  return {
    login,
    logout
  };
}
<commit_msg>catch error if knex tries to insert same user twice<commit_after>const uuid = require('uuid');
const request = require('request');

module.exports = function initialize(params) {
  const communicationsKey = params.communicationsKey;
  const knex = params.knex;
  const sebacon = params.sebacon;

  function login(req, res) {
    const ssoId = req.body.ssoid;
    const validationReq = {
      id: uuid.v4(),
      method: "GetUser",
      params: [
        communicationsKey,
        ssoId
      ],
      jsonrpc: "2.0"
    };
    request.post({
      url: 'https://tunnistus.avoine.fi/mmserver',
      json: validationReq
    }, (err, response, body) => {
      if (err) {
        console.error(err);
        return res.status(500).send('Jotain meni pieleen');
      }

      if (body.error) {
        console.log(body);
        req.session = null;
        return res.status(400).send('Kirjautuminen epäonnistui');
      }

      const sessionId = uuid.v4();
      const remoteId = body.result.local_id;
      return knex('users').where({ remote_id: remoteId })
        .then((resp) => {
          if (resp.length === 0) {
            return Promise.all([
              sebacon.getUserFirstName(remoteId),
              sebacon.getUserNickName(remoteId),
              sebacon.getUserPositions(remoteId),
              sebacon.getUserDomains(remoteId)
            ]).then(([firstname, nickname, positions, domains]) => {
              return knex('users')
                .insert({
                  remote_id: body.result.local_id,
                  data: {
                    name: nickname || firstname,
                    domains: domains.map(d => ({ heading: d, skill_level: 1 })),
                    positions: positions.map(d => ({ heading: d, skill_level: 1 })),
                    profile_creation_consented: false
                  }
                }, 'id') // postgres does not automatically return the id, ask for it explicitly
            })
              .then(insertResp => ({ id: insertResp[0] }))
          } else {
            return resp[0];
          }
        })
        .then((user) => {
          return knex('sessions').insert({
            id: sessionId,
            user_id: user.id
          }).then(() => {
            req.session.id = sessionId;
            return res.redirect(req.query.path || '/');
          });
        })
        // There is a race condition problem, where knex tries to insert same user more than once.
        // remote_id is unique, so this won't happen, but it will throw an error which is caught here.
        .catch(e => res.end());
    });
  }

  function logout(req, res) {
    const sessionId = req.session.id || 'nosession';
    req.session = null;
    return knex('sessions').where({id: sessionId}).del()
      .then(() => res.redirect('https://tunnistus.avoine.fi/sso-logout/'));
  }

  return {
    login,
    logout
  };
}
<|endoftext|>