<commit_before>var Module = undefined;

function JSMESS(canvas, module, game, precallback, callback, scale) {
  var js_data;
  var moduledata;
  var requests = [];
  var drawloadingtimer;
  var file_countdown;
  var spinnerrot = 0;
  var splashimg = new Image();
  var spinnerimg = new Image();
  var mute = true;

  var hasaudioinit = function() {
      return !!(typeof Module != 'undefined' && typeof SDL != 'undefined' && SDL.audio);
  }

  var muteonce = function() {
    if(!hasaudioinit()) {
        window.setTimeout(muteonce, 0)
    } else {
        // FIXME: Initial mute is timing dependent
        window.setTimeout(function() {setmuted(mute)}, 500)
    }
  }

  this.setmuted = function(_mute) {
    mute = _mute;
    if ((!mute && typeof Module != 'undefined') || hasaudioinit()) {
        Module.ccall('SDL_PauseAudio', '', ['number'], [mute ? 1 : 0])
    }
    return this;
  }
  var setmuted = this.setmuted

  this.setscale = function(_scale) {
    scale = _scale
    return this;
  }

  this.setprecallback = function(_precallback) {
    precallback = _precallback;
    return this;
  }

  this.setcallback = function(_callback) {
    callback = _callback;
    return this;
  }

  this.setmodule = function(_module) {
    module = _module;
    return this;
  }

  this.setgame = function(_game) {
    game = _game;
    return this;
  }

  var draw_loading_status = function() {
    var context = canvas.getContext('2d');
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.drawImage(splashimg, canvas.width / 2 - (splashimg.width / 2), canvas.height / 3 - (splashimg.height / 2));
    var spinnerpos = (canvas.height / 2 + splashimg.height / 2) + 16;
    context.save();
    context.translate((canvas.width / 2), spinnerpos);
    context.rotate(spinnerrot);
    context.drawImage(spinnerimg, -(64/2), -(64/2), 64, 64);
    context.restore();
    spinnerrot += .25;
  };

  var progress_fetch_file = function(e) {
    if (e.lengthComputable) {
      e.target.progress = e.loaded / e.total;
      e.target.loaded = e.loaded;
      e.target.total = e.total;
      e.target.lengthComputable = e.lengthComputable;
    }
  };

  var fetch_file = function(title, url, cb, rt, raw, unmanaged) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.responseType = rt ? rt : 'arraybuffer';
    xhr.onload = function(e) {
      if (xhr.status != 200) {
        return;
      }
      if (!unmanaged) {
        xhr.progress = 1.0;
      }
      var ints = raw ? xhr.response :  new Int8Array(xhr.response);
      cb(ints);
    };
    if (!unmanaged) {
      xhr.onprogress = progress_fetch_file;
      xhr.title = title;
      xhr.progress = 0;
      xhr.total = 0;
      xhr.loaded = 0;
      xhr.lengthComputable = false;
      requests.push(xhr);
    }
    xhr.send();
  };

  var update_countdown = function() {
    file_countdown -= 1
    if (file_countdown <= 0) {
      window.clearInterval(drawloadingtimer);
      var headID = document.getElementsByTagName('head')[0];
      var newScript = document.createElement('script');
      newScript.type = 'text/javascript';
      newScript.text = js_data;
      headID.appendChild(newScript);
    }
  };

  var init_module = function() {
    var modulecfg = JSON.parse(moduledata);

    var game_file = null;
    var bios_filenames = modulecfg['bios_filenames'];
    var bios_files = {};

    var nr = modulecfg['native_resolution'];

    canvas.style.width = (nr[0] * scale) + 'px';
    canvas.style.height = (nr[1] * scale) + 'px';
    canvas.width = nr[0] * scale;
    canvas.height = nr[1] * scale;

    var arguments = [
      modulecfg['driver'],
      '-verbose',
      '-rompath','.',
      '-window',
      '-resolution', nr[0]+'x' + nr[1],
      '-nokeepaspect'
    ];
    if (game) {
      arguments.push('-' + modulecfg['peripherals'][0], game.replace(/\//g,'_'))
    }
    if (modulecfg['extra_args']) {
      arguments = arguments.concat(modulecfg['extra_args'])
    }

    var self = this;

    Module = {
      arguments: arguments,
      SDL_numSimultaneouslyQueuedBuffers: 5,
      print: (function() {
        return function(text) {
          console.log(text);
        };
      })(),
      canvas: canvas,
      noInitialRun: false,
      preInit: function() {
        // Load the downloaded binary files into the filesystem.
        for (var bios_fname in bios_files) {
          if (bios_files.hasOwnProperty(bios_fname)) {
            Module['FS_createDataFile']('/', bios_fname, bios_files[bios_fname], true, true);
          }
        }
        if (game) {
            Module['FS_createDataFile']('/', game.replace(/\//g,'_'), game_file, true, true);
        }
        if (callback) {
          modulecfg.canvas = canvas;
          window.setTimeout(function() {callback(modulecfg)}, 0);
        }
        if (mute) {
          muteonce();
        }
      }
    };

    bios_filenames = bios_filenames.filter(String);
    file_countdown = bios_filenames.length + (game ? 1 : 0) + 1

    // Fetch the BIOS and the game we want to run.
    for (var i=0; i < bios_filenames.length; i++) {
      var fname = bios_filenames[i];
      fetch_file('Bios', 'bios/' + fname, function(data) { bios_files[fname] = data; update_countdown(); });
    }

    if (game) {
      fetch_file('Game', game, function(data) { game_file = data; update_countdown(); });
    }

    fetch_file('Javascript', 'jsmess/' + modulecfg['js_filename'], function(data) { js_data = data; update_countdown(); }, 'text', true);
  };

  var keyevent = function(e) {
    if (e.which == 32) {
      e.preventDefault();
      start();
    }
  }

  this.hasStarted = false;
  var self = this;
  var start = function() {
    self.hasStarted = true;
    ignorecommonkeys();
    window.removeEventListener('keypress', keyevent);
    drawloadingtimer = window.setInterval(draw_loading_status, 1000/60);
    if (precallback) {
      window.setTimeout(function() {precallback()}, 0);
    }
    fetch_file('ModuleInfo', 'json/' + module + '.json', function(data) { moduledata = data; init_module(); }, 'text', true, true);
    return this;
  }
  this.start = start;

  var drawsplash = function() {
    var context = canvas.getContext('2d');
    context.clearRect(0, 0, canvas.width, canvas.height);
    splashimg.onload = function(){
      context.drawImage(splashimg, canvas.width / 2 - (splashimg.width / 2), canvas.height / 3 - (splashimg.height / 2));
      context.font = '18px sans-serif';
      context.fillStyle = 'Black';
      context.textAlign = 'center';
      context.fillText('Press the SPACEBAR to start.', canvas.width / 2, (canvas.height / 2) + (splashimg.height / 2));
      context.textAlign = 'start';
    };
    spinnerimg.onload = function() { splashimg.src = 'splash.png'; }
    spinnerimg.src = 'spinner.png';
  }

  var ignorecommonkeys = function() {
      window.addEventListener('keydown', function(e) {
      if([32, 37, 38, 39, 40].indexOf(e.keyCode) > -1) {
              e.preventDefault();
      }
      }, false);
  }

  window.addEventListener('keypress', keyevent);
  drawsplash();
}
<commit_msg>Add support for new ready() system<commit_after>var Module = undefined;

function JSMESS(canvas, module, game, precallback, callback, scale) {
  var js_data;
  var moduledata;
  var requests = [];
  var drawloadingtimer;
  var file_countdown;
  var spinnerrot = 0;
  var splashimg = new Image();
  var spinnerimg = new Image();
  var mute = true;

  this.setmuted = function(_mute) {
    mute = _mute;
    if (typeof Module != 'undefined') {
        Module.ccall('SDL_PauseAudio', '', ['number'], [mute ? 1 : 0])
    }
    return this;
  }

  this.setscale = function(_scale) {
    scale = _scale
    return this;
  }

  this.setprecallback = function(_precallback) {
    precallback = _precallback;
    return this;
  }

  this.setcallback = function(_callback) {
    callback = _callback;
    return this;
  }

  this.setmodule = function(_module) {
    module = _module;
    return this;
  }

  this.setgame = function(_game) {
    game = _game;
    return this;
  }

  var draw_loading_status = function() {
    var context = canvas.getContext('2d');
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.drawImage(splashimg, canvas.width / 2 - (splashimg.width / 2), canvas.height / 3 - (splashimg.height / 2));
    var spinnerpos = (canvas.height / 2 + splashimg.height / 2) + 16;
    context.save();
    context.translate((canvas.width / 2), spinnerpos);
    context.rotate(spinnerrot);
    context.drawImage(spinnerimg, -(64/2), -(64/2), 64, 64);
    context.restore();
    spinnerrot += .25;
  };

  var progress_fetch_file = function(e) {
    if (e.lengthComputable) {
      e.target.progress = e.loaded / e.total;
      e.target.loaded = e.loaded;
      e.target.total = e.total;
      e.target.lengthComputable = e.lengthComputable;
    }
  };

  var fetch_file = function(title, url, cb, rt, raw, unmanaged) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.responseType = rt ? rt : 'arraybuffer';
    xhr.onload = function(e) {
      if (xhr.status != 200) {
        return;
      }
      if (!unmanaged) {
        xhr.progress = 1.0;
      }
      var ints = raw ? xhr.response :  new Int8Array(xhr.response);
      cb(ints);
    };
    if (!unmanaged) {
      xhr.onprogress = progress_fetch_file;
      xhr.title = title;
      xhr.progress = 0;
      xhr.total = 0;
      xhr.loaded = 0;
      xhr.lengthComputable = false;
      requests.push(xhr);
    }
    xhr.send();
  };

  var update_countdown = function() {
    file_countdown -= 1
    if (file_countdown <= 0) {
      window.clearInterval(drawloadingtimer);
      var headID = document.getElementsByTagName('head')[0];
      var newScript = document.createElement('script');
      newScript.type = 'text/javascript';
      newScript.text = js_data;
      headID.appendChild(newScript);
    }
  };

  var self = this;

  var init_module = function() {
    var modulecfg = JSON.parse(moduledata);

    var game_file = null;
    var bios_filenames = modulecfg['bios_filenames'];
    var bios_files = {};

    var nr = modulecfg['native_resolution'];

    canvas.style.width = (nr[0] * scale) + 'px';
    canvas.style.height = (nr[1] * scale) + 'px';
    canvas.width = nr[0] * scale;
    canvas.height = nr[1] * scale;

    var arguments = [
      modulecfg['driver'],
      '-verbose',
      '-rompath','.',
      '-window',
      '-resolution', nr[0]+'x' + nr[1],
      '-nokeepaspect'
    ];
    if (game) {
      arguments.push('-' + modulecfg['peripherals'][0], game.replace(/\//g,'_'))
    }
    if (modulecfg['extra_args']) {
      arguments = arguments.concat(modulecfg['extra_args'])
    }

    Module = {
      arguments: arguments,
      SDL_numSimultaneouslyQueuedBuffers: 5,
      screenIsReadOnly: true,
      print: (function() {
        return function(text) {
          console.log(text);
        };
      })(),
      canvas: canvas,
      noInitialRun: false,
      preInit: function() {
        // Load the downloaded binary files into the filesystem.
        for (var bios_fname in bios_files) {
          if (bios_files.hasOwnProperty(bios_fname)) {
            Module['FS_createDataFile']('/', bios_fname, bios_files[bios_fname], true, true);
          }
        }
        if (game) {
            Module['FS_createDataFile']('/', game.replace(/\//g,'_'), game_file, true, true);
        }
        if (callback) {
          modulecfg.canvas = canvas;
          window.setTimeout(function() {callback(modulecfg)}, 0);
        }
      }
    };

    bios_filenames = bios_filenames.filter(String);
    file_countdown = bios_filenames.length + (game ? 1 : 0) + 1

    // Fetch the BIOS and the game we want to run.
    for (var i=0; i < bios_filenames.length; i++) {
      var fname = bios_filenames[i];
      fetch_file('Bios', 'bios/' + fname, function(data) { bios_files[fname] = data; update_countdown(); });
    }

    if (game) {
      fetch_file('Game', game, function(data) { game_file = data; update_countdown(); });
    }

    JSMESS.ready(function() {self.setmuted(mute);});

    fetch_file('Javascript', 'jsmess/' + modulecfg['js_filename'], function(data) { js_data = data; update_countdown(); }, 'text', true);
  };

  var keyevent = function(e) {
    if (e.which == 32) {
      e.preventDefault();
      start();
    }
  }

  this.hasStarted = false;
  var start = function() {
    self.hasStarted = true;
    ignorecommonkeys();
    window.removeEventListener('keypress', keyevent);
    drawloadingtimer = window.setInterval(draw_loading_status, 1000/60);
    if (precallback) {
      window.setTimeout(function() {precallback()}, 0);
    }
    fetch_file('ModuleInfo', 'json/' + module + '.json', function(data) { moduledata = data; init_module(); }, 'text', true, true);
    return this;
  }
  this.start = start;

  var drawsplash = function() {
    var context = canvas.getContext('2d');
    context.clearRect(0, 0, canvas.width, canvas.height);
    splashimg.onload = function(){
      context.drawImage(splashimg, canvas.width / 2 - (splashimg.width / 2), canvas.height / 3 - (splashimg.height / 2));
      context.font = '18px sans-serif';
      context.fillStyle = 'Black';
      context.textAlign = 'center';
      context.fillText('Press the SPACEBAR to start.', canvas.width / 2, (canvas.height / 2) + (splashimg.height / 2));
      context.textAlign = 'start';
    };
    spinnerimg.onload = function() { splashimg.src = 'splash.png'; }
    spinnerimg.src = 'spinner.png';
  }

  var ignorecommonkeys = function() {
      window.addEventListener('keydown', function(e) {
      if([32, 37, 38, 39, 40].indexOf(e.keyCode) > -1) {
              e.preventDefault();
      }
      }, false);
  }

  window.addEventListener('keypress', keyevent);
  drawsplash();
}

JSMESS._readySet = false;

JSMESS._readyList = [];

JSMESS._runReadies = function() {
  if (JSMESS._readyList) {
    for (var r=0; r < JSMESS._readyList.length; r++) {
      JSMESS._readyList[r].call(window, []);
    };
    JSMESS._readyList = [];
  };
};

JSMESS._readyCheck = function() {
  if (JSMESS.running) {
    JSMESS._runReadies();
  } else {
    JSMESS._readySet = setTimeout(JSMESS._readyCheck, 10);
  };
};

JSMESS.ready = function(r) {
  if (JSMESS.running) {
    r.call(window, []);
  } else {
    JSMESS._readyList.push(function() { return r.call(window, []); } );
    if (!(JSMESS._readySet)) {
      JSMESS._readyCheck();
    }
  };
}
<|endoftext|>


<commit_before>import LFAdapter from 'ember-localforage-adapter/adapters/localforage';

export default LFAdapter.extend({
  namespace: 'expenses',
  caching: 'model'
});
<commit_msg>refactor: Change adapter namespace to api<commit_after>import LFAdapter from 'ember-localforage-adapter/adapters/localforage';

export default LFAdapter.extend({
  namespace: 'api',
  caching: 'model'
});
<|endoftext|>


<commit_before>// Static file helpers

import ExecutionEnvironment from 'react/lib/ExecutionEnvironment';

const PRODUCTION_STATIC_ROOT = 'http://static.tonikarttunen.com/static/';
const DEVELOPMENT_STATIC_ROOT = 'http://127.0.0.1:8888/';

const getStaticRootUrl = () => {
  if (ExecutionEnvironment.canUseDOM) {
    const HOST_BASE_URL =
    window.location.origin || /* Modern browsers */
    window.location.protocol + '//' + window.location.hostname +
    (window.location.port ? ':' + window.location.port : ''); /* IE */

    return (HOST_BASE_URL.includes('tonikarttunen.com') ?
      PRODUCTION_STATIC_ROOT :
      DEVELOPMENT_STATIC_ROOT);
  } else {
    return (process.env.WEBSITE_HOSTNAME ?
      PRODUCTION_STATIC_ROOT :
      DEVELOPMENT_STATIC_ROOT);
  }
};

export default {
  PRODUCTION_STATIC_ROOT: PRODUCTION_STATIC_ROOT,

  DEVELOPMENT_STATIC_ROOT: DEVELOPMENT_STATIC_ROOT,

  staticPath: (path) => {
    return getStaticRootUrl() + path;
  }
};
<commit_msg>Fix server-rendered static paths<commit_after>// Static file helpers

import { canUseDOM } from 'react/lib/ExecutionEnvironment';

const os = require('os');

const PRODUCTION_STATIC_ROOT = 'http://static.tonikarttunen.com/static/';
const DEVELOPMENT_STATIC_ROOT = 'http://127.0.0.1:8888/';

const getStaticRootUrl = () => {
  if (canUseDOM) {
    const HOST_BASE_URL =
    window.location.origin || /* Modern browsers */
    window.location.protocol + '//' + window.location.hostname +
    (window.location.port ? ':' + window.location.port : ''); /* IE */

    return (HOST_BASE_URL.includes('tonikarttunen.com') ?
      PRODUCTION_STATIC_ROOT :
      DEVELOPMENT_STATIC_ROOT);
  } else {
    return (os.hostname().includes('tonikarttunen.com') ?
      PRODUCTION_STATIC_ROOT :
      DEVELOPMENT_STATIC_ROOT);
  }
};

export default {
  PRODUCTION_STATIC_ROOT: PRODUCTION_STATIC_ROOT,

  DEVELOPMENT_STATIC_ROOT: DEVELOPMENT_STATIC_ROOT,

  staticPath: (path) => {
    return getStaticRootUrl() + path;
  }
};
<|endoftext|>


<commit_before>const Aggregate = require('./Aggregate');

exports.mongo = (self, message, done) => {
    //parse the body of the messager
    const json = JSON.parse(message.Body);

    //check the parsed object for the data we need
    if (json.Records &&
        json.Records[0] &&
        json.Records[0].s3 &&
        json.Records[0].s3.bucket &&
        json.Records[0].s3.bucket.name &&
        json.Records[0].s3.object &&
        json.Records[0].s3.object.key) {

        //s3 read
        let bucket = json.Records[0].s3.bucket.name;
        let key = json.Records[0].s3.object.key;
        let readParams = { Bucket: bucket, Key: key };

        self.aggregate = new Aggregate(self.c, self.mongo, self.config);
        self.aggregate.save(readParams, (err) => {
            done(err);
        });

    } else {
        done();
    }
};

exports.redshift = (self, message, done) => {
    //parse the body of the messager
    const json = JSON.parse(message.Body);

    //check the parsed object for the data we need
    if (json.Records &&
        json.Records[0] &&
        json.Records[0].s3 &&
        json.Records[0].s3.bucket &&
        json.Records[0].s3.bucket.name &&
        json.Records[0].s3.object &&
        json.Records[0].s3.object.key) {

        //s3 read
        let bucket = json.Records[0].s3.bucket.name;
        let key = json.Records[0].s3.object.key;
        let readParams = { Bucket: bucket, Key: key };
        let query;

        if (self.env === 'sandbox') {
            query = `COPY dax from 's3://${readParams.Bucket}/${readParams.Key}'
credentials 'aws_access_key_id=${self.sqsConfig.accessKeyId};aws_secret_access_key=${self.sqsConfig.secretAccessKey}'
gzip delimiter ',' removequotes escape TRUNCATECOLUMNS TRIMBLANKS NULL AS 'NULL';`;
        } else {
            query = `COPY dax from 's3://${readParams.Bucket}/${readParams.Key}'
iam_role '${self.config.output.postgresql.iam}'
gzip delimiter ',' removequotes escape TRUNCATECOLUMNS TRIMBLANKS NULL AS 'NULL';`;
        }

        console.log(query);

        self.postgresql.query(query, (err) => {
            if (err) {
                self.c.a('Error Copying ' + key + ' to redshift', 3, 'Poller');
                self.c.a(JSON.stringify(err), 3, 'Poller-Redshift');
            } else {
                self.c.a('Finsihed Copying ' + key + ' to redshift', 1, 'Poller');
            }
            done();
        });

    } else {
        done();
    }
};<commit_msg>updated environment var<commit_after>const Aggregate = require('./Aggregate');

exports.mongo = (self, message, done) => {
    //parse the body of the messager
    const json = JSON.parse(message.Body);

    //check the parsed object for the data we need
    if (json.Records &&
        json.Records[0] &&
        json.Records[0].s3 &&
        json.Records[0].s3.bucket &&
        json.Records[0].s3.bucket.name &&
        json.Records[0].s3.object &&
        json.Records[0].s3.object.key) {

        //s3 read
        let bucket = json.Records[0].s3.bucket.name;
        let key = json.Records[0].s3.object.key;
        let readParams = { Bucket: bucket, Key: key };

        self.aggregate = new Aggregate(self.c, self.mongo, self.config);
        self.aggregate.save(readParams, (err) => {
            done(err);
        });

    } else {
        done();
    }
};

exports.redshift = (self, message, done) => {
    //parse the body of the messager
    const json = JSON.parse(message.Body);

    //check the parsed object for the data we need
    if (json.Records &&
        json.Records[0] &&
        json.Records[0].s3 &&
        json.Records[0].s3.bucket &&
        json.Records[0].s3.bucket.name &&
        json.Records[0].s3.object &&
        json.Records[0].s3.object.key) {

        //s3 read
        let bucket = json.Records[0].s3.bucket.name;
        let key = json.Records[0].s3.object.key;
        let readParams = { Bucket: bucket, Key: key };
        let query;

        if (self.config.environment === 'sandbox') {
            query = `COPY dax from 's3://${readParams.Bucket}/${readParams.Key}'
credentials 'aws_access_key_id=${self.sqsConfig.accessKeyId};aws_secret_access_key=${self.sqsConfig.secretAccessKey}'
gzip delimiter ',' removequotes escape TRUNCATECOLUMNS TRIMBLANKS NULL AS 'NULL';`;
        } else {
            query = `COPY dax from 's3://${readParams.Bucket}/${readParams.Key}'
iam_role '${self.config.output.postgresql.iam}'
gzip delimiter ',' removequotes escape TRUNCATECOLUMNS TRIMBLANKS NULL AS 'NULL';`;
        }

        self.postgresql.query(query, (err) => {
            if (err) {
                self.c.a('Error Copying ' + key + ' to redshift', 3, 'Poller');
                self.c.a(JSON.stringify(err), 3, 'Poller-Redshift');
            } else {
                self.c.a('Finsihed Copying ' + key + ' to redshift', 1, 'Poller');
            }
            done();
        });

    } else {
        done();
    }
};<|endoftext|>


<commit_before>import AdapterFetch from 'ember-fetch/mixins/adapter-fetch';
import JSONAPIAdapter from 'ember-data/adapters/json-api';
import ENV from '../config/environment';

export default JSONAPIAdapter.extend(AdapterFetch, {
  host: ENV.host,

  ajaxOptions() {
    const options = this._super(...arguments);
    options.headers['Content-Type'] = 'application/vnd.api+json';
    return options;
  }
});
<commit_msg>Guard against undefined options<commit_after>import AdapterFetch from 'ember-fetch/mixins/adapter-fetch';
import JSONAPIAdapter from 'ember-data/adapters/json-api';
import ENV from '../config/environment';

export default JSONAPIAdapter.extend(AdapterFetch, {
  host: ENV.host,

  ajaxOptions() {
    const options = this._super(...arguments) || {};
    options.headers['Content-Type'] = 'application/vnd.api+json';
    return options;
  }
});
<|endoftext|>


<commit_before>const EventEmitter = require('events')

const createPromiseNotifier = (emitter, results, handleError) => (promise, i) => {
  return promise
    .then(result => {
      if (emitter.listenerCount('data') > 0) {
        emitter.emit('data', { result, id: i })
      } else {
        results.push(result)
      }
    })
    .catch(async e => {
      try {
        await handleError(e)
        emitter.emit('error', e)
      } catch (newError) {
        emitter.emit('error', newError)
      }
    })
}

const createGetResolvedPromise = (emitter, results) => {
  let runningPromises = 0
  const fulfilledPromises = []

  return () => {
    runningPromises++
    return new Promise((resolve, reject) => {
      if (results.length > 0) {
        return resolve(results.shift())
      }

      const handler = ({ result, id }) => {
        /**
         * Since we have a single emitter for all running promises we have to skip
         * already delivered results as we will have one listener per promise
         * running, so once one promise resolves all of the listeners will receive
         * the same value
         */
        if (fulfilledPromises.includes(id)) {
          return
        }

        /**
         * When there is a single promise running, we can safely deliver the result
         * of the emitter since we won't have the risk of getting results from
         * other promises
         */
        if (runningPromises <= 1) {
          runningPromises--
          emitter.off('data', handler)

          return resolve(result)
        }

        /**
         * When multiple promises are running the emitter will receive data from all
         * running promises, thus the results can get mixed up.
         *
         * To avoid that and always unblock the first promises with the fastest results,
         * we need to keep track of the id, so we don't accidentally resolve the same
         * value multiple times.
         */
        runningPromises--
        emitter.off('data', handler)
        fulfilledPromises.push(id)

        resolve(result)
      }

      emitter.on('data', handler)
      emitter.on('error', reject)
    })
  }
}
const defaultErrorHandler = e => {
  throw e
}

function* BufferedAsyncIterator(promises, handleError = defaultErrorHandler) {
  const results = []
  const emitter = new EventEmitter()
  const wrap = createPromiseNotifier(emitter, results, handleError)
  const getResolvedPromise = createGetResolvedPromise(emitter, results)
  const wrappedPromises = promises.map(wrap)

  emitter.setMaxListeners(wrappedPromises.length)

  for (let i = 0; i < wrappedPromises.length; i++) {
    yield getResolvedPromise()
  }
}

module.exports = BufferedAsyncIterator
<commit_msg>Use async syntax for promise notifier<commit_after>const EventEmitter = require('events')

const createPromiseNotifier = (emitter, results, handleError) => async (promise, i) => {
  try {
    const result = await promise
    if (emitter.listenerCount('data') > 0) {
      emitter.emit('data', { result, id: i })
    } else {
      results.push(result)
    }
  } catch (e) {
    try {
      await handleError(e)
      emitter.emit('error', e)
    } catch (newError) {
      emitter.emit('error', newError)
    }
  }
}

const createGetResolvedPromise = (emitter, results) => {
  let runningPromises = 0
  const fulfilledPromises = []

  return () => {
    runningPromises++
    return new Promise((resolve, reject) => {
      if (results.length > 0) {
        return resolve(results.shift())
      }

      const handler = ({ result, id }) => {
        /**
         * Since we have a single emitter for all running promises we have to skip
         * already delivered results as we will have one listener per promise
         * running, so once one promise resolves all of the listeners will receive
         * the same value
         */
        if (fulfilledPromises.includes(id)) {
          return
        }

        /**
         * When there is a single promise running, we can safely deliver the result
         * of the emitter since we won't have the risk of getting results from
         * other promises
         */
        if (runningPromises <= 1) {
          runningPromises--
          emitter.off('data', handler)

          return resolve(result)
        }

        /**
         * When multiple promises are running the emitter will receive data from all
         * running promises, thus the results can get mixed up.
         *
         * To avoid that and always unblock the first promises with the fastest results,
         * we need to keep track of the id, so we don't accidentally resolve the same
         * value multiple times.
         */
        runningPromises--
        emitter.off('data', handler)
        fulfilledPromises.push(id)

        resolve(result)
      }

      emitter.on('data', handler)
      emitter.on('error', reject)
    })
  }
}
const defaultErrorHandler = e => {
  throw e
}

function* BufferedAsyncIterator(promises, handleError = defaultErrorHandler) {
  const results = []
  const emitter = new EventEmitter()
  const wrap = createPromiseNotifier(emitter, results, handleError)
  const getResolvedPromise = createGetResolvedPromise(emitter, results)
  const wrappedPromises = promises.map(wrap)

  emitter.setMaxListeners(wrappedPromises.length)

  for (let i = 0; i < wrappedPromises.length; i++) {
    yield getResolvedPromise()
  }
}

module.exports = BufferedAsyncIterator
<|endoftext|>


<commit_before>//interacts with GAPI, sending updates to gameboard object
var width = 400;
var height = 400;
var board;			//canva
var context;		//canvas context
var container;		//holds color score, player names and join button

//displays above game canvas
var gameList = ["Dots", "Reversi"];
var dropDownMenu = "";
for (var i = 0; i < gameList.length; i++){
	dropDownMenu += '<option value="' + gameList[i] + '">' + gameList[i] +'</option>';
}
dropDownMenu = '<select  id="gameMenu">' + dropDownMenu + '</select>';

var startGameButton = "<input type='button' value='Play' onclick='startNewGameClick();' />";
var startGameHTML = startGameButton + " a game of " + dropDownMenu;
var infoDisplay = startGameHTML;

//stores participantID and corrisponding team color
var participantID = [];
var participantTeam = [];

//video canvas, display to the right of gameboard and info
var VC;

//contains game state and methods
var Game;
var gameName;

//
function startNewGameClick(){
	var selectedGame = gameList[document.getElementById("gameMenu").selectedIndex];
	eval("Game = new " + selectedGame +"();");
	setupCanvasObjects();
	Game.startGame();
	serverUpdate();
}

//called by game object when it has data to send out
function sendStateToServer(boardString){
	save = boardString;
	if (boardString) {
		gapi.hangout.data.submitDelta({boardString: boardString});
	}
}

//passes updated state to gameboard
function sendStateToGame(boardString){
	Game.recieveState(boardString);
}

function sendClickToGame(e) {
	Game.click(e);
}

function isPlayerTurn(color) {
	return participantTeam[idIndex(gapi.hangout.getParticipantId())] == color
}

//updates info div with winner info and button to start new game
function gameEnded(winnerText){
	infoDisplay = winnerText + " . " + startGameHTML;
	gapi.hangout.data.submitDelta({
		infoDisplay:	infoDisplay
	});
}

//creates on context object and listener
function setupCanvasObjects() {
	board = document.getElementById("board");
	context = board.getContext("2d");
	container = document.getElementById("container");
	//listens for clicks on the board
	board.addEventListener("mousedown",sendClickToGame,false);
}

//game starts when hangout API is ready
gapi.hangout.onApiReady.add(function(eventObj){
	if (eventObj.isApiReady) {
		try {
			var state = gapi.hangout.data.getState();

			//game running, join it
			if (state.gameName) {
				gameName = state.gameName;
				eval("Game = new " + gameName +"();");
			}
			else {
				gapi.hangout.data.submitDelta({
					infoDisplay:	startGameHTML
				});
			}

			//checks to see if there are other players present
			if (state.participantID) {
				participantID = JSON.parse(state.participantID);
				participantTeam = JSON.parse(state.participantTeam);
			}

			//adds the local player to team and saves id
			participantID[participantID.length] = gapi.hangout.getParticipantId();
			participantTeam[participantTeam.length] = 0;

			//rejoining creates a duplicate memembers - removes those
			for(var i = 0; i <participantID.length; i++) {
				for(var j = i + 1; j<participantID.length; j++) {
					if (participantID[i] == participantID[j]) {
						participantID.splice(j,j);
						participantTeam.splice(j,j);
					}
				}
			}

			//creates a listener for state changes. calls serverUpdate() when activated
			gapi.hangout.data.onStateChanged.add(function(stateChangeEvent) {
				try {
					serverUpdate(stateChangeEvent.state);
				}
				catch (e) {
					alert("update error");
					log1 = e;
				}
			});

			//updates server with particpant info
			gapi.hangout.data.submitDelta({
				participantID:	JSON.stringify(participantID),
				participantTeam:JSON.stringify(participantTeam),
			});

			//adds videos canvas to the display
			VC = gapi.hangout.layout.getVideoCanvas();
			positionVideoCanvas();
		}
		catch(e) {
			alert("init error");
			log = e;
		}
	}
});

//if global state is changed, update local copy of global varibles and redraw board
function serverUpdate(){
	try {
		var state = gapi.hangout.data.getState();
		participantID = JSON.parse(state.participantID);
		participantTeam = JSON.parse(state.participantTeam);
		participantUpdate();

		infoDisplay = state.infoDisplay;
		document.getElementById("info").innerHTML = infoDisplay;

		sendStateToGame(state.boardString);

		if (gameName != state.gameName) {
			eval("Game = new " + state.gameName +"();");
		}
	}
	catch(e)
	{
		log2 = e;
	}
}

//updates list of particpants and the presence of switch team buttons
function participantUpdate(){
	//team of the local user
	var team = participantTeam[idIndex(gapi.hangout.getParticipantId())];

	//adds buttons
	addButton('joinBlack',team);
	addButton('joinNone',team);
	addButton('joinWhite',team);

	document.getElementById('blackPlayers').innerHTML = findTeamMembers(1);
	document.getElementById('nonePlayers').innerHTML = findTeamMembers(0);
	document.getElementById('whitePlayers').innerHTML = findTeamMembers(-1);

}

function findTeamMembers(team) {
	var rv = "";
	for (var i = 0; i < participantTeam.length; i++){
		if (participantTeam[i] == team) {
			rv = rv + " " + gapi.hangout.getParticipantById(participantID[i]).person.displayName + "
";
		}
	}
	return rv;
}

function addButton(bName, team){
	//true if player is currently on team - no join Button displayed
	if (buttonNameToTeam(bName) == team ) {
		document.getElementById(bName).innerHTML = "";
	}
	//displays join button
	else {
		document.getElementById(bName).innerHTML = "<input type='button' value='Join' onclick='changeTeam(" + buttonNameToTeam(bName) + ");' />";
	}
}

//takes a button name and returns a team number
function buttonNameToTeam(bName) {
	if (bName == 'joinBlack') {
		return 1;
	}
	else if (bName == 'joinNone') {
		return 0;
	}
	else if (bName == 'joinWhite') {
		return -1;
	}
}

//passed a team color and changes to it
function changeTeam(team){
	participantTeam[idIndex(gapi.hangout.getParticipantId())] = team;
	//sends switch to server
	gapi.hangout.data.submitDelta({
		participantID:	JSON.stringify(participantID),
		participantTeam:JSON.stringify(participantTeam),
	});
}

//finds index of passed ID in participantID array
function idIndex(id) {
	var i = 0;
	while(i < participantID.length)
	{
		if (participantID[i] == id) {
			return i;
		}
		i++;
	}
	//passed id not in array, add entry
	participantID[i] = id;
	participantTeam[i] = 0;
	return i;
}

//positions video canvas to take up largest possible area without covering board
function positionVideoCanvas() {
	maxHeight = window.innerHeight;
	maxWidth = window.innerWidth - 430;

	if (VC){
		if (maxWidth/maxHeight > VC.getAspectRatio()){
			VC.setHeight(maxHeight);
		}
		else {
			VC.setWidth(maxWidth);
		}
		VC.setPosition(430,0);
		VC.setVisible(true);
	}
	else {
		VC = gapi.hangout.layout.getVideoCanvas();
	}
}

//creates info on game start
function gameStartInfo() {
		var gameStarterID = gapi.hangout.getParticipantId();
		var gameStarterObject = gapi.hangout.getParticipantById(gameStarterID);
		var gameStarterName = gameStarterObject.person.displayName;
		infoDisplay = gameStarterName + " has started a new game";
}<commit_msg>gameName changes propagate<commit_after>//interacts with GAPI, sending updates to gameboard object
var width = 400;
var height = 400;
var board;			//canva
var context;		//canvas context
var container;		//holds color score, player names and join button

//displays above game canvas
var gameList = ["Dots", "Reversi"];
var dropDownMenu = "";
for (var i = 0; i < gameList.length; i++){
	dropDownMenu += '<option value="' + gameList[i] + '">' + gameList[i] +'</option>';
}
dropDownMenu = '<select  id="gameMenu">' + dropDownMenu + '</select>';

var startGameButton = "<input type='button' value='Play' onclick='startNewGameClick();' />";
var startGameHTML = startGameButton + " a game of " + dropDownMenu;
var infoDisplay = startGameHTML;

//stores participantID and corrisponding team color
var participantID = [];
var participantTeam = [];

//video canvas, display to the right of gameboard and info
var VC;

//contains game state and methods
var Game;
var gameName;

//
function startNewGameClick(){
	var selectedGame = gameList[document.getElementById("gameMenu").selectedIndex];
	eval("Game = new " + selectedGame +"();");
	setupCanvasObjects();
	Game.startGame();
	gameName = selectedGame;
}

//called by game object when it has data to send out
function sendStateToServer(boardString){
	save = boardString;
	if (boardString) {
		gapi.hangout.data.submitDelta({
			boardString: 	boardString,
			gameName: 		gameName
		});
	}
}

//passes updated state to gameboard
function sendStateToGame(boardString){
	Game.recieveState(boardString);
}

function sendClickToGame(e) {
	Game.click(e);
}

function isPlayerTurn(color) {
	return participantTeam[idIndex(gapi.hangout.getParticipantId())] == color
}

//updates info div with winner info and button to start new game
function gameEnded(winnerText){
	infoDisplay = winnerText + " . " + startGameHTML;
	gapi.hangout.data.submitDelta({
		infoDisplay:	infoDisplay
	});
}

//creates on context object and listener
function setupCanvasObjects() {
	board = document.getElementById("board");
	context = board.getContext("2d");
	container = document.getElementById("container");
	//listens for clicks on the board
	board.addEventListener("mousedown",sendClickToGame,false);
}

//game starts when hangout API is ready
gapi.hangout.onApiReady.add(function(eventObj){
	if (eventObj.isApiReady) {
		try {
			var state = gapi.hangout.data.getState();

			//game running, join it
			if (state.gameName) {
				gameName = state.gameName;
				eval("Game = new " + gameName +"();");
			}
			else {
				gapi.hangout.data.submitDelta({
					infoDisplay:	startGameHTML
				});
			}

			//checks to see if there are other players present
			if (state.participantID) {
				participantID = JSON.parse(state.participantID);
				participantTeam = JSON.parse(state.participantTeam);
			}

			//adds the local player to team and saves id
			participantID[participantID.length] = gapi.hangout.getParticipantId();
			participantTeam[participantTeam.length] = 0;

			//rejoining creates a duplicate memembers - removes those
			for(var i = 0; i <participantID.length; i++) {
				for(var j = i + 1; j<participantID.length; j++) {
					if (participantID[i] == participantID[j]) {
						participantID.splice(j,j);
						participantTeam.splice(j,j);
					}
				}
			}

			//creates a listener for state changes. calls serverUpdate() when activated
			gapi.hangout.data.onStateChanged.add(function(stateChangeEvent) {
				try {
					serverUpdate(stateChangeEvent.state);
				}
				catch (e) {
					alert("update error");
					log1 = e;
				}
			});

			//updates server with particpant info
			gapi.hangout.data.submitDelta({
				participantID:	JSON.stringify(participantID),
				participantTeam:JSON.stringify(participantTeam),
			});

			//adds videos canvas to the display
			VC = gapi.hangout.layout.getVideoCanvas();
			positionVideoCanvas();
		}
		catch(e) {
			alert("init error");
			log = e;
		}
	}
});

//if global state is changed, update local copy of global varibles and redraw board
function serverUpdate(){
	try {
		var state = gapi.hangout.data.getState();
		participantID = JSON.parse(state.participantID);
		participantTeam = JSON.parse(state.participantTeam);
		participantUpdate();

		infoDisplay = state.infoDisplay;
		document.getElementById("info").innerHTML = infoDisplay;

		sendStateToGame(state.boardString);

		if (gameName != state.gameName) {
			eval("Game = new " + state.gameName +"();");
		}
	}
	catch(e)
	{
		log2 = e;
	}
}

//updates list of particpants and the presence of switch team buttons
function participantUpdate(){
	//team of the local user
	var team = participantTeam[idIndex(gapi.hangout.getParticipantId())];

	//adds buttons
	addButton('joinBlack',team);
	addButton('joinNone',team);
	addButton('joinWhite',team);

	document.getElementById('blackPlayers').innerHTML = findTeamMembers(1);
	document.getElementById('nonePlayers').innerHTML = findTeamMembers(0);
	document.getElementById('whitePlayers').innerHTML = findTeamMembers(-1);

}

function findTeamMembers(team) {
	var rv = "";
	for (var i = 0; i < participantTeam.length; i++){
		if (participantTeam[i] == team) {
			rv = rv + " " + gapi.hangout.getParticipantById(participantID[i]).person.displayName + "
";
		}
	}
	return rv;
}

function addButton(bName, team){
	//true if player is currently on team - no join Button displayed
	if (buttonNameToTeam(bName) == team ) {
		document.getElementById(bName).innerHTML = "";
	}
	//displays join button
	else {
		document.getElementById(bName).innerHTML = "<input type='button' value='Join' onclick='changeTeam(" + buttonNameToTeam(bName) + ");' />";
	}
}

//takes a button name and returns a team number
function buttonNameToTeam(bName) {
	if (bName == 'joinBlack') {
		return 1;
	}
	else if (bName == 'joinNone') {
		return 0;
	}
	else if (bName == 'joinWhite') {
		return -1;
	}
}

//passed a team color and changes to it
function changeTeam(team){
	participantTeam[idIndex(gapi.hangout.getParticipantId())] = team;
	//sends switch to server
	gapi.hangout.data.submitDelta({
		participantID:	JSON.stringify(participantID),
		participantTeam:JSON.stringify(participantTeam),
	});
}

//finds index of passed ID in participantID array
function idIndex(id) {
	var i = 0;
	while(i < participantID.length)
	{
		if (participantID[i] == id) {
			return i;
		}
		i++;
	}
	//passed id not in array, add entry
	participantID[i] = id;
	participantTeam[i] = 0;
	return i;
}

//positions video canvas to take up largest possible area without covering board
function positionVideoCanvas() {
	maxHeight = window.innerHeight;
	maxWidth = window.innerWidth - 430;

	if (VC){
		if (maxWidth/maxHeight > VC.getAspectRatio()){
			VC.setHeight(maxHeight);
		}
		else {
			VC.setWidth(maxWidth);
		}
		VC.setPosition(430,0);
		VC.setVisible(true);
	}
	else {
		VC = gapi.hangout.layout.getVideoCanvas();
	}
}

//creates info on game start
function gameStartInfo() {
		var gameStarterID = gapi.hangout.getParticipantId();
		var gameStarterObject = gapi.hangout.getParticipantById(gameStarterID);
		var gameStarterName = gameStarterObject.person.displayName;
		infoDisplay = gameStarterName + " has started a new game";
}<|endoftext|>


<commit_before>/* eslint-disable react/prop-types */
import { createElement } from 'rax';
import View from 'rax-view';
import Text from 'rax-text';
import Image from 'rax-image';

const Main = ({ children, ...props }) => (
  <View
    {...props}
    style={{
      margin: 15,
      fontFamily: '"Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif',
    }}
  >
    {children}
  </View>
);

const P = ({ children, ...props }) => (
  <View {...props} style={{ marginBottom: 10 }}>
    <Text style={{ fontSize: 12 }}>{children}</Text>
  </View>
);

const Title = ({ children, ...props }) => (
  <Text {...props} style={{ fontSize: 40, lineHeight: '80px', fontWeight: 'bold' }}>
    {children}
  </Text>
);

export const Welcome = ({ showApp }) => (

    <Title>Welcome to storybook for Rax</Title>
    <Image
      source={{
        uri: './rax-logo.png',
      }}
      fallbackSource={{
        uri:
          'https://user-images.githubusercontent.com/677114/49848760-999e7d00-fe11-11e8-978f-264ea31f6739.png',
      }}
      style={{
        width: 100,
        height: 100,
        margin: '0 auto',
      }}
      resizeMode="cover"
    />

This is a UI component dev environment for your Rax app.

      We've added some basic stories inside the 'src/stories' directory. A story is a single state
      of one or more UI components. You can have as many stories as you want. (Basically a story is
      like a visual test case.)

See these sample

    <button onPress={showApp} type="button">

button

    </button>

for a component called 'Button'.

      Just like that, you can add your own components as stories. You can also edit those components
      and see changes right away. (Try editing the 'Button' stories located at
      'src/stories/index.js' .)

);
<commit_msg>fix: component name<commit_after>/* eslint-disable react/prop-types */
import { createElement } from 'rax';
import View from 'rax-view';
import Text from 'rax-text';
import Image from 'rax-image';

const Main = ({ children, ...props }) => (
  <View
    {...props}
    style={{
      margin: 15,
      fontFamily: '"Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif',
    }}
  >
    {children}
  </View>
);

const P = ({ children, ...props }) => (
  <View {...props} style={{ marginBottom: 10 }}>
    <Text style={{ fontSize: 12 }}>{children}</Text>
  </View>
);

const Title = ({ children, ...props }) => (
  <Text {...props} style={{ fontSize: 40, lineHeight: '80px', fontWeight: 'bold' }}>
    {children}
  </Text>
);

export const App = ({ showApp }) => (

    <Title>Welcome to storybook for Rax</Title>
    <Image
      source={{
        uri: './rax-logo.png',
      }}
      fallbackSource={{
        uri:
          'https://user-images.githubusercontent.com/677114/49848760-999e7d00-fe11-11e8-978f-264ea31f6739.png',
      }}
      style={{
        width: 100,
        height: 100,
        margin: '0 auto',
      }}
      resizeMode="cover"
    />

This is a UI component dev environment for your Rax app.

      We've added some basic stories inside the 'src/stories' directory. A story is a single state
      of one or more UI components. You can have as many stories as you want. (Basically a story is
      like a visual test case.)

See these sample

    <button onPress={showApp} type="button">

button

    </button>

for a component called 'Button'.

      Just like that, you can add your own components as stories. You can also edit those components
      and see changes right away. (Try editing the 'Button' stories located at
      'src/stories/index.js' .)

);
<|endoftext|>


<commit_before>describe('skatejs-web-components', () => {

});
<commit_msg>test: Add test that ensures all V1 APIs exist when the library is imported.<commit_after>import '../src/index';

describe('skatejs-web-components', () => {
  it('should create a custom element with a shadow root', () => {
    const Elem = class extends HTMLElement {
      constructor() {
        super();
        this.attachShadow({ mode: 'open' });
      }
    };
    window.customElements.define('x-test', Elem);
    const elem = new Elem();
    expect(!!elem.shadowRoot).to.equal(true);
  });
});
<|endoftext|>


<commit_before>/*
This file is part of the Juju GUI, which lets users view and manage Juju
environments within a graphical interface (https://launchpad.net/juju-gui).
Copyright (C) 2012-2013 Canonical Ltd.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License version 3, as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
General Public License for more details.

You should have received a copy of the GNU Affero General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

describe('charm panel', function() {
  var Y, container, models, views, juju, ENTER,
      searchResult = '{"results": [{"data_url": "this is my URL", ' +
      '"name": "membase", "series": "precise", "summary": ' +
      '"Membase Server", "relevance": 8.728194117350437, ' +
      '"owner": "charmers", "store_url": "cs:precise/membase-6"}]}';

  before(function(done) {
    Y = YUI(GlobalConfig).use(
        'juju-models',
        'juju-views',
        'juju-gui',
        'juju-env',
        'juju-tests-utils',
        'node-event-simulate',
        'node',
        'event-key',
        'juju-charm-store',

        function(Y) {
          models = Y.namespace('juju.models');
          views = Y.namespace('juju.views');
          juju = Y.namespace('juju');
          ENTER = Y.Node.DOM_EVENTS.key.eventDef.KEY_MAP.enter;
          done();
        });

  });

  beforeEach(function() {
    // The charms panel needs these elements
    container = Y.namespace('juju-tests.utils').makeContainer('test-container');
    container.append(
        Y.Node.create('
' +
        '

' +
                    '

' +
                    '<input type="text" id="charm-search-field" />' +
                    '
'));
  });

  afterEach(function() {
    Y.namespace('juju.views').CharmPanel.killInstance();
    if (container) {
      container.remove(true);
    }
  });

  it('must be able to show and hide the panel', function() {
    var panel = Y.namespace('juju.views').CharmPanel.getInstance({
      testing: true,
      container: container,
      app: { views: { environment: {}}}
    });
    var node = panel.node;
    panel.setActivePanelName('configuration');
    node.getStyle('display').should.equal('none');
    panel.show();
    node.getStyle('display').should.equal('block');
    panel.hide();
    node.getStyle('display').should.equal('none');
    panel.toggle();
    node.getStyle('display').should.equal('block');
    panel.toggle();
    node.getStyle('display').should.equal('none');
  });

  it('does not set config.options if config is defined', function() {
    var panel = Y.namespace('juju.views').CharmPanel
          .getInstance({
          testing: true,
          container: container,
          app: { views: { environment: {}}}
        }),
        node = panel.node;
    panel.setActivePanelName('configuration');
    var charm = {
      id: 'cs:precise/juju-gui-7',
      get: function(name) {
        if (name === 'id') {
          return 'cs:precise/juju-gui-7';
        } else if (name === 'config') {
          return {};
        }
      },
      set: function(name, value) {
        if (name === 'config') {
          assert.fail(null, null, 'config should not have been set');
        }
      }
    };
    panel.deploy(charm, undefined, function() {});
  });

  describe('service ghost', function() {
    var app, db, env, panel, serviceName, store;

    before(function() {
      serviceName = 'membase';
      // Mock the relevant environment calls.
      env = {
        deploy: function(url, service, config, config_raw, units, callback) {
          callback({err: false});
        },
        update_annotations: function(service, type, annotations, callback) {
          if (typeof callback === 'function') {
            callback({err: false});
          }
        }
      };
      // Mock the charm store.
      store = new juju.Charmworld2({
        datasource: {
          sendRequest: function(params) {
            params.callback.success({
              response: {results: [{responseText: searchResult}]}
            });
          }
        }
      });
    });

    beforeEach(function() {
      db = new models.Database();
      // Mock the base application.
      app = {db: db, views: {environment: {}}, env: env};
      panel = views.CharmPanel.getInstance({container: container, app: app});
      panel.setActivePanelName('configuration');
      panel.show();
    });

    // Search for a charm using the charm search input.
    var search = function(contents) {
      var field = Y.one('#charm-search-field');
      field.set('value', contents);
      field.simulate('keydown', {keyCode: ENTER});
    };

    // Start deploying a charm, without confirming.
    var startDeployment = function(ghostXY) {
      panel.deploy(new models.BrowserCharm({id: 'cs:precise/membase-6'}), ghostXY);
    };

    // Cancel an unconfirmed deployment.
    var cancelDeployment = function() {
      panel.node.one('.btn.cancel').simulate('click');
    };

    // Confirm a charm deployment.
    var confirmDeployment = function() {
      panel.node.one('.btn-primary').simulate('click');
    };

    it('is created in the database when deployment is started', function() {
      startDeployment();
      assert.strictEqual(1, db.services.size());
      var service = db.services.item(0);
      assert.isTrue(service.get('pending'));
      assert.include(service.get('id'), serviceName);
    });

    it('is created with x/y coordinates if set', function() {
      startDeployment({coordinates: [100, 100]});
      assert.strictEqual(1, db.services.size());
      var service = db.services.item(0);
      assert.isTrue(service.get('pending'));
      assert.include(service.get('id'), serviceName);
      assert.isTrue(service.get('hasBeenPositioned'));
      assert.equal(service.get('x'), 100);
      assert.equal(service.get('y'), 100);
    });

    it('is created with an icon if set', function() {
      startDeployment({icon: '/juju-ui/assets/images/zoom_plus.png'});
      assert.strictEqual(1, db.services.size());
      var service = db.services.item(0);
      assert.isTrue(service.get('pending'));
      assert.include(service.get('id'), serviceName);
      assert.isTrue(service.get('hasBeenPositioned'));
      assert.equal(service.get('icon'),
          '/juju-ui/assets/images/zoom_plus.png');
    });

    it('is removed from the database if deployment is cancelled', function() {
      startDeployment();
      assert.equal(db.services.size(), 1);
      cancelDeployment();
      assert.equal(db.services.size(), 0);
    });

    it('is removed from the database if another ghost is created', function() {
      // Pending services will be removed.
      db.services.add([
        {id: 'mysql', pending: true},
        {id: 'rails', pending: true}
      ]);
      // A deployed service will be preserved.
      var django = db.services.add({id: 'django', pendiong: false});
      startDeployment();
      assert.strictEqual(2, db.services.size());
      // The pending services have been removed.
      assert.isNull(db.services.getById('mysql'));
      assert.isNull(db.services.getById('rails'));
      // The deployed service has been preserved.
      assert.deepEqual(django, db.services.getById('django'));
    });

    it('updates his name on blur', function() {
      if (Y.UA.ie === 10) {
        // IE10 Can't simulate blur at time of writing.
        // See https://github.com/yui/yui3/issues/489
        return;
      }
      startDeployment();
      var serviceNameNode = Y.one('#service-name');
      assert.strictEqual(serviceName, serviceNameNode.get('value'));
      serviceNameNode.simulate('blur');
      var expected = '(' + serviceName + ')';
      assert.strictEqual(expected, db.services.item(0).get('id'));
    });

    it('is no longer ghosted on deploy', function() {
      startDeployment();
      // Fake a service drag to test that the service is cleaned on deploy.
      var service = db.services.item(0);
      service.setAttrs({'x': 123, 'y': 321});
      service.set('hasBeenPositioned', true);
      confirmDeployment();
      assert.isFalse(service.get('pending'));
      assert.include(service.get('id'), serviceName);
      // Check that annotations were set from dragging.
      var annotations = service.get('annotations');
      assert.deepEqual(annotations, {'gui-x': 123, 'gui-y': 321});
    });

  });

});
<commit_msg>Shut up, lint.<commit_after>/*
This file is part of the Juju GUI, which lets users view and manage Juju
environments within a graphical interface (https://launchpad.net/juju-gui).
Copyright (C) 2012-2013 Canonical Ltd.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License version 3, as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
General Public License for more details.

You should have received a copy of the GNU Affero General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

describe('charm panel', function() {
  var Y, container, models, views, juju, ENTER,
      searchResult = '{"results": [{"data_url": "this is my URL", ' +
      '"name": "membase", "series": "precise", "summary": ' +
      '"Membase Server", "relevance": 8.728194117350437, ' +
      '"owner": "charmers", "store_url": "cs:precise/membase-6"}]}';

  before(function(done) {
    Y = YUI(GlobalConfig).use(
        'juju-models',
        'juju-views',
        'juju-gui',
        'juju-env',
        'juju-tests-utils',
        'node-event-simulate',
        'node',
        'event-key',
        'juju-charm-store',

        function(Y) {
          models = Y.namespace('juju.models');
          views = Y.namespace('juju.views');
          juju = Y.namespace('juju');
          ENTER = Y.Node.DOM_EVENTS.key.eventDef.KEY_MAP.enter;
          done();
        });

  });

  beforeEach(function() {
    // The charms panel needs these elements
    container = Y.namespace('juju-tests.utils').makeContainer('test-container');
    container.append(
        Y.Node.create('
' +
        '

' +
                    '

' +
                    '<input type="text" id="charm-search-field" />' +
                    '
'));
  });

  afterEach(function() {
    Y.namespace('juju.views').CharmPanel.killInstance();
    if (container) {
      container.remove(true);
    }
  });

  it('must be able to show and hide the panel', function() {
    var panel = Y.namespace('juju.views').CharmPanel.getInstance({
      testing: true,
      container: container,
      app: { views: { environment: {}}}
    });
    var node = panel.node;
    panel.setActivePanelName('configuration');
    node.getStyle('display').should.equal('none');
    panel.show();
    node.getStyle('display').should.equal('block');
    panel.hide();
    node.getStyle('display').should.equal('none');
    panel.toggle();
    node.getStyle('display').should.equal('block');
    panel.toggle();
    node.getStyle('display').should.equal('none');
  });

  it('does not set config.options if config is defined', function() {
    var panel = Y.namespace('juju.views').CharmPanel
          .getInstance({
          testing: true,
          container: container,
          app: { views: { environment: {}}}
        }),
        node = panel.node;
    panel.setActivePanelName('configuration');
    var charm = {
      id: 'cs:precise/juju-gui-7',
      get: function(name) {
        if (name === 'id') {
          return 'cs:precise/juju-gui-7';
        } else if (name === 'config') {
          return {};
        }
      },
      set: function(name, value) {
        if (name === 'config') {
          assert.fail(null, null, 'config should not have been set');
        }
      }
    };
    panel.deploy(charm, undefined, function() {});
  });

  describe('service ghost', function() {
    var app, db, env, panel, serviceName, store;

    before(function() {
      serviceName = 'membase';
      // Mock the relevant environment calls.
      env = {
        deploy: function(url, service, config, config_raw, units, callback) {
          callback({err: false});
        },
        update_annotations: function(service, type, annotations, callback) {
          if (typeof callback === 'function') {
            callback({err: false});
          }
        }
      };
      // Mock the charm store.
      store = new juju.Charmworld2({
        datasource: {
          sendRequest: function(params) {
            params.callback.success({
              response: {results: [{responseText: searchResult}]}
            });
          }
        }
      });
    });

    beforeEach(function() {
      db = new models.Database();
      // Mock the base application.
      app = {db: db, views: {environment: {}}, env: env};
      panel = views.CharmPanel.getInstance({container: container, app: app});
      panel.setActivePanelName('configuration');
      panel.show();
    });

    // Search for a charm using the charm search input.
    var search = function(contents) {
      var field = Y.one('#charm-search-field');
      field.set('value', contents);
      field.simulate('keydown', {keyCode: ENTER});
    };

    // Start deploying a charm, without confirming.
    var startDeployment = function(ghostXY) {
      panel.deploy(
          new models.BrowserCharm({id: 'cs:precise/membase-6'}),
          ghostXY);
    };

    // Cancel an unconfirmed deployment.
    var cancelDeployment = function() {
      panel.node.one('.btn.cancel').simulate('click');
    };

    // Confirm a charm deployment.
    var confirmDeployment = function() {
      panel.node.one('.btn-primary').simulate('click');
    };

    it('is created in the database when deployment is started', function() {
      startDeployment();
      assert.strictEqual(1, db.services.size());
      var service = db.services.item(0);
      assert.isTrue(service.get('pending'));
      assert.include(service.get('id'), serviceName);
    });

    it('is created with x/y coordinates if set', function() {
      startDeployment({coordinates: [100, 100]});
      assert.strictEqual(1, db.services.size());
      var service = db.services.item(0);
      assert.isTrue(service.get('pending'));
      assert.include(service.get('id'), serviceName);
      assert.isTrue(service.get('hasBeenPositioned'));
      assert.equal(service.get('x'), 100);
      assert.equal(service.get('y'), 100);
    });

    it('is created with an icon if set', function() {
      startDeployment({icon: '/juju-ui/assets/images/zoom_plus.png'});
      assert.strictEqual(1, db.services.size());
      var service = db.services.item(0);
      assert.isTrue(service.get('pending'));
      assert.include(service.get('id'), serviceName);
      assert.isTrue(service.get('hasBeenPositioned'));
      assert.equal(service.get('icon'),
          '/juju-ui/assets/images/zoom_plus.png');
    });

    it('is removed from the database if deployment is cancelled', function() {
      startDeployment();
      assert.equal(db.services.size(), 1);
      cancelDeployment();
      assert.equal(db.services.size(), 0);
    });

    it('is removed from the database if another ghost is created', function() {
      // Pending services will be removed.
      db.services.add([
        {id: 'mysql', pending: true},
        {id: 'rails', pending: true}
      ]);
      // A deployed service will be preserved.
      var django = db.services.add({id: 'django', pendiong: false});
      startDeployment();
      assert.strictEqual(2, db.services.size());
      // The pending services have been removed.
      assert.isNull(db.services.getById('mysql'));
      assert.isNull(db.services.getById('rails'));
      // The deployed service has been preserved.
      assert.deepEqual(django, db.services.getById('django'));
    });

    it('updates his name on blur', function() {
      if (Y.UA.ie === 10) {
        // IE10 Can't simulate blur at time of writing.
        // See https://github.com/yui/yui3/issues/489
        return;
      }
      startDeployment();
      var serviceNameNode = Y.one('#service-name');
      assert.strictEqual(serviceName, serviceNameNode.get('value'));
      serviceNameNode.simulate('blur');
      var expected = '(' + serviceName + ')';
      assert.strictEqual(expected, db.services.item(0).get('id'));
    });

    it('is no longer ghosted on deploy', function() {
      startDeployment();
      // Fake a service drag to test that the service is cleaned on deploy.
      var service = db.services.item(0);
      service.setAttrs({'x': 123, 'y': 321});
      service.set('hasBeenPositioned', true);
      confirmDeployment();
      assert.isFalse(service.get('pending'));
      assert.include(service.get('id'), serviceName);
      // Check that annotations were set from dragging.
      var annotations = service.get('annotations');
      assert.deepEqual(annotations, {'gui-x': 123, 'gui-y': 321});
    });

  });

});
<|endoftext|>


<commit_before>/**
 * AlgoliaApp, simply creating its own scope
 * TODO: this could be done in other ways, with separate modules (input form, add form, algolia related code)
 */
const AlgoliaApp = (function() {
    const resultsPerPage = 5;
    let msgTimeout = null;

    let searchClient = null;
    let index = null;

    let msgContainer = null;
    let msgContentEl = null;
    let searchInput = null;
    let addButton = null;
    let addForm = null;
    let addFormTextarea = null;
    let resultsEl = null;
    let resultTemplateContent = null;

    function initApp(config) {
        initElements();

        initSearchClient(config);

        initEvents();
    }

    function initSearchClient(config) {
        try {
            searchClient = algoliasearch(config.algolia_applicationID, config.algolia_apiKey);
            index = searchClient.initIndex(config.algolia_indexName);
            enableApp();
        } catch (err) {
            updateMsg(err.name + ': ' + err.message, 'error');
        }
    }

    function initElements() {
        msgContainer = document.getElementById('msg');
        msgContentEl = msgContainer.querySelector('.content');
        searchInput = document.getElementById('searchInput');
        addButton = document.getElementById('addButton');
        addForm = document.getElementById('addForm');
        addFormTextarea = addForm.querySelector('textarea');
        resultsEl = document.getElementById('results');
        resultTemplateContent = document.getElementById('resultTpl').content;
    }

    function initEvents() {
        // Message box hide button
        msgContainer.querySelector('.hide').addEventListener('click', function (e) {
            msgContainer.classList.add('hidden');
        });

        // Click event on the delete buttons
        resultsEl.addEventListener('click', function (e) {
            if (e.target.type === 'button' && e.target.classList.contains('delete')) {
                // TODO: make sure this works wherever the parent containing the
                // id is
                const objectID = e.target.parentElement.dataset.id;

                // TODO: add some css animation to make it fade away
                // TODO: move this anonymous function somewhere else
                deleteEntity(objectID, function () {e.target.parentElement.remove();});
            }
        });

        // Pressing keys in the search input
        searchInput.addEventListener('keyup', function (e) {
            executeSearch(this.value);
        });

        addButton.addEventListener('click', showAddForm);

        document.addEventListener('keyup', function (e) {
            if (e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA' && e.key === '/' && !e.ctrlKey && !e.altKey) {
                searchInput.select();
            }

            if (e.key === 'n' && e.ctrlKey && !e.altKey) {
                showAddForm();
            }
        });

        initAddFormEvents();
    }

    function initAddFormEvents() {
        const addFormCancelButton = addForm.querySelector('button.cancel');

        addFormCancelButton.addEventListener('click', hideAddForm);

        addForm.addEventListener('submit', function (e) {
            e.preventDefault();

            addEntity(addFormTextarea.value)
            .then(function (response) {
                // TODO: check for response.ok instead?
                if (response.status !== 201) {
                    return response.text().then(function (response) {
                        throw response;
                    });
                } else {
                    return response.text().then(function (response) {
                        hideAddForm();
                        updateMsg('Entity added (id: ' + response + ')', 'info');
                    });
                }
            }).catch(function (error) {
                updateMsg(error, 'error');
            });
        });
    }

    function enableApp() {
        searchInput.disabled = false;
        addButton.disabled = false;

        searchInput.select();
    }

    function showAddForm() {
        if (!addButton.disabled) {
            addForm.classList.remove('hidden');
            addFormTextarea.select();
        }
    }

    function hideAddForm() {
        addForm.classList.add('hidden');
        addForm.reset();
    }

    function hideMsg() {
        msgContainer.classList.add('hidden');
        msgContentEl.innerText = '';
    }

    function removeAllChildren(parent) {
        while (parent.firstChild) {
            parent.removeChild(parent.firstChild);
        }
    }

    function updateMsg(argMsg, type) {
        const types = [
            'info',
            // 'warning',
            'error',
        ];
        const msg = argMsg.toString();

        if (types.indexOf(type) === -1) {
            type = types[0];
        }

        // Removing obsolete classes
        for (let i = 0; i < types.length; i++) {
            if (type !== types[i] && msgContainer.classList.contains(types[i])) {
                msgContainer.classList.remove(types[i]);
            }
        }

        msgContentEl.innerText = msg;
        msgContainer.classList.add(type);
        msgContainer.classList.remove('hidden');
        console[type](msg);

        // Hide the message after a few seconds if it's only informational
        if (type === 'info') {
            clearTimeout(msgTimeout);
            msgTimeout = setTimeout(function () {
                // TODO: css animation to make it fade away
                // TODO: cancel timeout if the user hovered the message?
                msgContainer.classList.add('hidden');
            }, 5000);
        }
    }

    function createResultRow(content) {
        let mainEl = resultTemplateContent.querySelector('.result');
        let nameEl = resultTemplateContent.querySelector('.name');
        let categoryEl = resultTemplateContent.querySelector('.category');

        mainEl.dataset.id = content.objectID;

        // name and category may contain em tags for highlights and escaped chars
        nameEl.innerHTML = content._highlightResult.name.value;
        nameEl.href = content.link;

        categoryEl.innerHTML = content._highlightResult.category.value;

        return document.importNode(resultTemplateContent, true);
    }

    // TODO: use promises instead of callbacks
    function executeSearch(toSearch) {
        if (toSearch === '') {
            removeAllChildren(resultsEl);
        } else {
            // the last optional argument can be used to add search parameters
            index.search(
                toSearch, {
                    hitsPerPage: resultsPerPage,
                    facets: '*',
                    maxValuesPerFacet: 10
                },
                searchCallback
            );
        }
    }

    function searchCallback(err, content) {
        if (err) {
            updateMsg(error, 'error');
        } else {
            removeAllChildren(resultsEl);

            if (content.hits.length > 0) {
                for (let i = 0; i < content.hits.length; i++) {
                    resultsEl.appendChild(createResultRow(content.hits[i]));
                }
            }
        }
    }

    /**
     * @param  {string|int}   id
     * @param  {Function} callback
     * @param  {Boolean}  isConfirmed
     */
    function deleteEntity(id, callback, isConfirmed) {
        // just making sure it's a string for concatenations
        const idAsStr = id.toString();
        callback = callback || function() {};

        if (isConfirmed === undefined) {
            deleteEntity(id, callback, window.confirm('Are you sure you want to delete this object?'));
        } else if(isConfirmed) {
            fetch('/api/1/apps/' + idAsStr, {method: 'DELETE'})
            .then(function (response) {
                if (!response.ok) {
                    return response.text().then(function (response) {
                        throw response;
                    });
                }

                updateMsg('Entity deleted (id: ' + idAsStr + ')');
                callback(id);
            }).catch(function deleteEntityPromiseError(error) {
                updateMsg('Could not delete entity: ' + error, 'error');
            });
        }
    }

    function addEntity(json) {
        let data = new FormData();
        data.append('data', json);

        return fetch('/api/1/apps', {
            method: 'POST',
            body: data,
        });
    }

    return {
        /**
         * Initializes the "module"
         * @param  {object} config Configuration for the Algolia search client
         */
        init: function (config) {
            initApp(config);
        }
    };
}());
<commit_msg>front: different message if the server could not be reached (fetch error)<commit_after>/**
 * AlgoliaApp, simply creating its own scope
 * TODO: this could be done in other ways, with separate modules (input form, add form, algolia related code)
 */
const AlgoliaApp = (function() {
    const resultsPerPage = 5;
    let msgTimeout = null;

    let searchClient = null;
    let index = null;

    let msgContainer = null;
    let msgContentEl = null;
    let searchInput = null;
    let addButton = null;
    let addForm = null;
    let addFormTextarea = null;
    let resultsEl = null;
    let resultTemplateContent = null;

    function initApp(config) {
        initElements();

        initSearchClient(config);

        initEvents();
    }

    function initSearchClient(config) {
        try {
            searchClient = algoliasearch(config.algolia_applicationID, config.algolia_apiKey);
            index = searchClient.initIndex(config.algolia_indexName);
            enableApp();
        } catch (err) {
            updateMsg(err.name + ': ' + err.message, 'error');
        }
    }

    function initElements() {
        msgContainer = document.getElementById('msg');
        msgContentEl = msgContainer.querySelector('.content');
        searchInput = document.getElementById('searchInput');
        addButton = document.getElementById('addButton');
        addForm = document.getElementById('addForm');
        addFormTextarea = addForm.querySelector('textarea');
        resultsEl = document.getElementById('results');
        resultTemplateContent = document.getElementById('resultTpl').content;
    }

    function initEvents() {
        // Message box hide button
        msgContainer.querySelector('.hide').addEventListener('click', function (e) {
            msgContainer.classList.add('hidden');
        });

        // Click event on the delete buttons
        resultsEl.addEventListener('click', function (e) {
            if (e.target.type === 'button' && e.target.classList.contains('delete')) {
                // TODO: make sure this works wherever the parent containing the
                // id is
                const objectID = e.target.parentElement.dataset.id;

                // TODO: add some css animation to make it fade away
                // TODO: move this anonymous function somewhere else
                deleteEntity(objectID, function () {e.target.parentElement.remove();});
            }
        });

        // Pressing keys in the search input
        searchInput.addEventListener('keyup', function (e) {
            executeSearch(this.value);
        });

        addButton.addEventListener('click', showAddForm);

        document.addEventListener('keyup', function (e) {
            if (e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA' && e.key === '/' && !e.ctrlKey && !e.altKey) {
                searchInput.select();
            }

            if (e.key === 'n' && e.ctrlKey && !e.altKey) {
                showAddForm();
            }
        });

        initAddFormEvents();
    }

    function initAddFormEvents() {
        const addFormCancelButton = addForm.querySelector('button.cancel');

        addFormCancelButton.addEventListener('click', hideAddForm);

        addForm.addEventListener('submit', function (e) {
            e.preventDefault();

            addEntity(addFormTextarea.value)
            .then(function (response) {
                // TODO: check for response.ok instead?
                if (response.status !== 201) {
                    return response.text().then(function (response) {
                        throw response;
                    });
                } else {
                    return response.text().then(function (response) {
                        hideAddForm();
                        updateMsg('Entity added (id: ' + response + ')', 'info');
                    });
                }
            }).catch(function (error) {
                updateMsg(error, 'error');
            });
        });
    }

    function enableApp() {
        searchInput.disabled = false;
        addButton.disabled = false;

        searchInput.select();
    }

    function showAddForm() {
        if (!addButton.disabled) {
            addForm.classList.remove('hidden');
            addFormTextarea.select();
        }
    }

    function hideAddForm() {
        addForm.classList.add('hidden');
        addForm.reset();
    }

    function hideMsg() {
        msgContainer.classList.add('hidden');
        msgContentEl.innerText = '';
    }

    function removeAllChildren(parent) {
        while (parent.firstChild) {
            parent.removeChild(parent.firstChild);
        }
    }

    function updateMsg(argMsg, type) {
        const types = [
            'info',
            // 'warning',
            'error',
        ];
        let msg = argMsg.toString();

        if (types.indexOf(type) === -1) {
            type = types[0];
        }

        // Removing obsolete classes
        for (let i = 0; i < types.length; i++) {
            if (type !== types[i] && msgContainer.classList.contains(types[i])) {
                msgContainer.classList.remove(types[i]);
            }
        }

        // some errors sent by fetch aren't very explicit
        if (msg === 'TypeError: Failed to fetch') {
            msg = 'Server could not be reached: "' + msg + '"';
        }

        msgContentEl.innerText = msg;
        msgContainer.classList.add(type);
        msgContainer.classList.remove('hidden');
        console[type](msg);

        // Hide the message after a few seconds if it's only informational
        if (type === 'info') {
            clearTimeout(msgTimeout);
            msgTimeout = setTimeout(function () {
                // TODO: css animation to make it fade away
                // TODO: cancel timeout if the user hovered the message?
                hideMsg();
            }, 5000);
        }
    }

    function createResultRow(content) {
        let mainEl = resultTemplateContent.querySelector('.result');
        let nameEl = resultTemplateContent.querySelector('.name');
        let categoryEl = resultTemplateContent.querySelector('.category');

        mainEl.dataset.id = content.objectID;

        // name and category may contain em tags for highlights and escaped chars
        nameEl.innerHTML = content._highlightResult.name.value;
        nameEl.href = content.link;

        categoryEl.innerHTML = content._highlightResult.category.value;

        return document.importNode(resultTemplateContent, true);
    }

    // TODO: use promises instead of callbacks
    function executeSearch(toSearch) {
        if (toSearch === '') {
            removeAllChildren(resultsEl);
        } else {
            // the last optional argument can be used to add search parameters
            index.search(
                toSearch, {
                    hitsPerPage: resultsPerPage,
                    facets: '*',
                    maxValuesPerFacet: 10
                },
                searchCallback
            );
        }
    }

    function searchCallback(err, content) {
        if (err) {
            updateMsg(error, 'error');
        } else {
            removeAllChildren(resultsEl);

            if (content.hits.length > 0) {
                for (let i = 0; i < content.hits.length; i++) {
                    resultsEl.appendChild(createResultRow(content.hits[i]));
                }
            }
        }
    }

    /**
     * @param  {string|int}   id
     * @param  {Function} callback
     * @param  {Boolean}  isConfirmed
     */
    function deleteEntity(id, callback, isConfirmed) {
        // just making sure it's a string for concatenations
        const idAsStr = id.toString();
        callback = callback || function() {};

        if (isConfirmed === undefined) {
            deleteEntity(id, callback, window.confirm('Are you sure you want to delete this object?'));
        } else if(isConfirmed) {
            fetch('/api/1/apps/' + idAsStr, {method: 'DELETE'})
            .then(function (response) {
                if (!response.ok) {
                    return response.text().then(function (response) {
                        throw response;
                    });
                }

                updateMsg('Entity deleted (id: ' + idAsStr + ')');
                callback(id);
            }).catch(function deleteEntityPromiseError(error) {
                updateMsg('Could not delete entity: ' + error, 'error');
            });
        }
    }

    function addEntity(json) {
        let data = new FormData();
        data.append('data', json);

        return fetch('/api/1/apps', {
            method: 'POST',
            body: data,
        });
    }

    return {
        /**
         * Initializes the "module"
         * @param  {object} config Configuration for the Algolia search client
         */
        init: function (config) {
            initApp(config);
        }
    };
}());
<|endoftext|>


<commit_before>var distribute_content;

distribute_content = function (content_json)
{
	var data, element, paragraphs, paragraph, i, function_name;

	data = jQuery.parseJSON(content_json);

	for(element in data.content)
	{
		if (typeof data.content[element] === 'string')
		{
			$('[data-content-editable=' + element + ']').html(data.content[element]);
			$('[data-content=' + element + ']').html(data.content[element]);
		}
		else
		{
			paragraphs = data.content[element];
			paragraph = $('[data-content-editable=' + element + ']');

			// add content to paragraph
			paragraph.html(paragraphs[0]);

			// create new paragraphs
			for (i = paragraphs.length - 1; i > 0; i--)
			{
				paragraph.after('
' + paragraphs[i] + '
')
			}
		}
	}

	// functions for specific page
	function_name = 'render_' + $('body').attr('id').replace(/-/g, '_');

	if (typeof window[function_name] == 'function')
	{
		window[function_name]();
	}

}

$(document).ready(function ()
{
	var secret, page_id;

	page_id = $('body').attr('class');

	$.ajax({
		type: 'POST',
		url: 'page-data/get.php',
		data: {
			'page_id': page_id
		},
		success: function (response)
		{
			// has auth?
			if (response.auth)
			{
				// make admin panel available
				$('body').addClass('auth');
				make_editable(true);
			}
			else if (localStorage.secret)
			{
				// session exired
				alert(response.error.auth);

				// remove secret from localstorage
				localStorage.removeItem('secret');
			}

			// has data?
			if (response.data)
			{
				distribute_content(response.data);
			}
			else
			{
				alert(response.error.data);
			}
		}
	});
});<commit_msg>little fix<commit_after>var distribute_content;

distribute_content = function (content_json)
{
	var data, element, paragraphs, paragraph, i, function_name;

	data = jQuery.parseJSON(content_json);

	for(element in data.content)
	{
		if (typeof data.content[element] === 'string')
		{
			$('[data-content-editable=' + element + ']').html(data.content[element]);
			$('[data-content=' + element + ']').html(data.content[element]);
		}
		else
		{
			paragraphs = data.content[element];
			paragraph = $('[data-content-editable=' + element + ']');

			// add content to paragraph
			paragraph.html(paragraphs[0]);

			// create new paragraphs
			for (i = paragraphs.length - 1; i > 0; i--)
			{
				paragraph.after('
' + paragraphs[i] + '
')
			}
		}
	}

	// functions for specific page
	function_name = 'render_' + $('body').attr('id').replace(/-/g, '_');

	if (typeof window[function_name] == 'function')
	{
		window[function_name]();
	}

}

$(document).ready(function ()
{
	var secret, page_id;

	page_id = $('body').attr('id');

	$.ajax({
		type: 'POST',
		url: 'page-data/get.php',
		data: {
			'page_id': page_id
		},
		success: function (response)
		{
			// has auth?
			if (response.auth)
			{
				// make admin panel available
				$('body').addClass('auth');
				make_editable(true);
			}
			else if (localStorage.secret)
			{
				// session exired
				alert(response.error.auth);

				// remove secret from localstorage
				localStorage.removeItem('secret');
			}

			// has data?
			if (response.data)
			{
				distribute_content(response.data);
			}
			else
			{
				alert(response.error.data);
			}
		}
	});
});<|endoftext|>


<commit_before>var servPort = process.env.TS_PORT || 8080; // default TCP port 8080

// for each URL route, import environment variable or set default for
// maximum added response latency (milliseconds) and error 503 probability (percentage)
//
// parameters for / (main)
var latencyMax_main = process.env.TS_LAT_MAIN || 1000;
var errorProb_main  = process.env.TS_ERR_MAIN || 10;
// parameters for /alt
var latencyMax_alt  = process.env.TS_LAT_ALT  || 2000;
var errorProb_alt   = process.env.TS_ERR_ALT  || 20;

// for error 503 case, import environment variable or set default for
// extra maximum added response latency (milliseconds)
var latencyMax_err  = process.env.TS_LAT_ALT  || 3000;

// example custom header
var metaVersion = process.env.TS_META_VER || "1.20(3)";

var sleep = require('sleep'); //npm install sleep
var express = require('express'); //npm install express
var app = express();

app.get('/', function (request, response) {
        console.log("Route / (main)")
        var basicSnooze = Math.round(Math.random()*latencyMax_main);
        console.log("Adding basic response latency of  "+basicSnooze+" milliseconds");
        sleep.usleep(basicSnooze*1000);
        // respond with simulated overload
        if(Math.random()*100 <= errorProb_main) {
        var errorSnooze = Math.round(Math.random()*latencyMax_err);
        sleep.usleep(errorSnooze*1000);
        console.log("Adding error response latency of  "+errorSnooze+" milliseconds");
        console.log("Responding with 503 error");
        var totalSnooze = basicSnooze+errorSnooze;
        response.writeHead(503, {"Content-Type": "text/plain"});
        response.write("503 Service Unavailable\n\nAdded response latency "+totalSnooze+" milliseconds\n");
        response.end();
        // respond normally
        } else {
        console.log("Responding with normal page");
        response.writeHead(200, {"Content-Type": "text/html"});
        response.write("<!DOCTYPE html>");
        response.write("<title>Demo Server Main</title>");
        response.write("<meta version=\""+metaVersion+"\">");
        response.write("");
        response.write("");
        response.write("Surprise!
Something completely different
");
        if (basicSnooze>0) {response.write("but you had to wait an extra "+basicSnooze+" milliseconds

");        }
        response.write("");
        response.write("

Comments to Larry Lang");
        response.write("");
        response.end();
        }});

app.get('/alt', function (request, response) {
        console.log("Route /alt")
        var basicSnooze = Math.round(Math.random()*latencyMax_alt);
        console.log("Adding basic response latency of  "+basicSnooze+" milliseconds");
        sleep.usleep(basicSnooze*1000);
        // respond with simulated overload
        if(Math.random()*100 <= errorProb_alt) {
        var errorSnooze = Math.round(Math.random()*latencyMax_err);
        sleep.usleep(errorSnooze*1000);
        console.log("Adding error response latency of  "+errorSnooze+" milliseconds");
        console.log("Responding with 503 error");
        var totalSnooze = basicSnooze+errorSnooze;
        response.writeHead(503, {"Content-Type": "text/plain"});
        response.write("503 Service Unavailable\n\nAdded response latency "+totalSnooze+" milliseconds\n");
        response.end();
        // respond normally
        } else {
        console.log("Responding with normal page");
        response.writeHead(200, {"Content-Type": "text/html"});
        response.write("<!DOCTYPE html>");
        response.write("<title>Demo Server Alt</title>");
        response.write("<meta version=\""+metaVersion+"\">");
        response.write("");
        response.write("");
        response.write("Cheers!
Everyone loves instant gratification
");
        if (basicSnooze>0) {response.write("but you had to wait an extra "+basicSnooze+" milliseconds

");        }
        response.write("");
        response.write("

Comments to Larry Lang");
        response.write("");
        response.end();
        }});

var server = app.listen(servPort, function () {
                        var host = server.address().address;
                        var port = server.address().port;
                        console.log('Demo server listening at http://%s:%s', host, port);
                        });<commit_msg>Eliminated superfluous <!DOCTYPE html> to avoid error on AWS Ubuntu<commit_after>var servPort = process.env.TS_PORT || 8080; // default TCP port 8080

// for each URL route, import environment variable or set default for
// maximum added response latency (milliseconds) and error 503 probability (percentage)
//
// parameters for / (main)
var latencyMax_main = process.env.TS_LAT_MAIN || 1000;
var errorProb_main  = process.env.TS_ERR_MAIN || 10;
// parameters for /alt
var latencyMax_alt  = process.env.TS_LAT_ALT  || 2000;
var errorProb_alt   = process.env.TS_ERR_ALT  || 20;

// for error 503 case, import environment variable or set default for
// extra maximum added response latency (milliseconds)
var latencyMax_err  = process.env.TS_LAT_ALT  || 3000;

// example custom header
var metaVersion = process.env.TS_META_VER || "1.20(3)";

var sleep = require('sleep'); //npm install sleep
var express = require('express'); //npm install express
var app = express();

app.get('/', function (request, response) {
        console.log("Route / (main)")
        var basicSnooze = Math.round(Math.random()*latencyMax_main);
        console.log("Adding basic response latency of  "+basicSnooze+" milliseconds");
        sleep.usleep(basicSnooze*1000);
        // respond with simulated overload
        if(Math.random()*100 <= errorProb_main) {
        var errorSnooze = Math.round(Math.random()*latencyMax_err);
        sleep.usleep(errorSnooze*1000);
        console.log("Adding error response latency of  "+errorSnooze+" milliseconds");
        console.log("Responding with 503 error");
        var totalSnooze = basicSnooze+errorSnooze;
        response.writeHead(503, {"Content-Type": "text/plain"});
        response.write("503 Service Unavailable\n\nAdded response latency "+totalSnooze+" milliseconds\n");
        response.end();
        // respond normally
        } else {
        console.log("Responding with normal page");
        response.writeHead(200, {"Content-Type": "text/html"});
        response.write("");
        response.write("<title>Demo Server Main</title>");
        response.write("<meta version=\""+metaVersion+"\">");
        response.write("");
        response.write("");
        response.write("Surprise!
Something completely different
");
        if (basicSnooze>0) {response.write("but you had to wait an extra "+basicSnooze+" milliseconds

"); }
        response.write("");
        response.write("

Comments to Larry Lang");
        response.write("");
        response.end();
        }});

app.get('/alt', function (request, response) {
        console.log("Route /alt")
        var basicSnooze = Math.round(Math.random()*latencyMax_alt);
        console.log("Adding basic response latency of  "+basicSnooze+" milliseconds");
        sleep.usleep(basicSnooze*1000);
        // respond with simulated overload
        if(Math.random()*100 <= errorProb_alt) {
        var errorSnooze = Math.round(Math.random()*latencyMax_err);
        sleep.usleep(errorSnooze*1000);
        console.log("Adding error response latency of  "+errorSnooze+" milliseconds");
        console.log("Responding with 503 error");
        var totalSnooze = basicSnooze+errorSnooze;
        response.writeHead(503, {"Content-Type": "text/plain"});
        response.write("503 Service Unavailable\n\nAdded response latency "+totalSnooze+" milliseconds\n");
        response.end();
        // respond normally
        } else {
        console.log("Responding with normal page");
        response.writeHead(200, {"Content-Type": "text/html"});
        response.write("");
        response.write("<title>Demo Server Alt</title>");
        response.write("<meta version=\""+metaVersion+"\">");
        response.write("");
        response.write("");
        response.write("Cheers!
Everyone loves instant gratification
");
        if (basicSnooze>0) {response.write("but you had to wait an extra "+basicSnooze+" milliseconds

"); }
        response.write("");
        response.write("

Comments to Larry Lang");
        response.write("");
        response.end();
        }});

var server = app.listen(servPort, function () {
                        var host = server.address().address;
                        var port = server.address().port;
                        console.log('Demo server listening at http://%s:%s', host, port);
                        });<|endoftext|>


<commit_before>import React, { Component } from 'react';

import Node from './Node'

class TreeSublist extends Component {
    constructor(props){
        super(props);
        this.state = {
            isOpen:true
        };
    }

    /**
     * Fire when the user presses the +/- icons.
     *
     * @param event e
     */
    handleOpenClose(e){
        let isOpen = true;
        if(this.state.isOpen){
            isOpen = false;
        }
        this.setState({isOpen});
    }

    render() {
        const { listData, listTitle, filters, filterFieldName, handleChangeSelectedFilter, searchString } = this.props;
        const { isOpen } = this.state;

        let sublist = [];

        listData.map(function(itemName){
            const safeName = itemName.toLowerCase();

            const node = <Node key={itemName}
                               handleChangeSelectedFilter={handleChangeSelectedFilter}
                               filterFieldName={filterFieldName}
                               filters={filters}
                               searchString={searchString}
                               itemName={itemName}
                            />;

            if( searchString !=="" && safeName.includes(searchString)){
                sublist.push(node);
            } else if (searchString===""){
                sublist.push(node);
            }

        });

        let iconClasses = "fa fa-plus-circle khb-treelist-icon";
        let sublistContent = "";
        if(isOpen){
            iconClasses = "fa fa-minus-circle khb-treelist-icon";
            sublistContent = sublist;
        }

        return (

                     {listTitle}

                    {sublistContent}

        );
    }
}

TreeSublist.propTypes = {
    listData:React.PropTypes.array,
    listTitle:React.PropTypes.string,
    filters:React.PropTypes.object,
    filterFieldName:React.PropTypes.string,
    handleChangeSelectedFilter:React.PropTypes.func,
    searchString:React.PropTypes.string
};

export default TreeSublist;<commit_msg>Moved propTypes to static.<commit_after>import React, { Component } from 'react';

import Node from './Node'

class TreeSublist extends Component {

    static propTypes = {
        listData:React.PropTypes.array,
        listTitle:React.PropTypes.string,
        filters:React.PropTypes.object,
        filterFieldName:React.PropTypes.string,
        handleChangeSelectedFilter:React.PropTypes.func,
        searchString:React.PropTypes.string
    };

    constructor(props){
        super(props);
        this.state = {
            isOpen:true
        };
    }

    /**
     * Fire when the user presses the +/- icons.
     *
     * @param event e
     */
    handleOpenClose(e){
        let isOpen = true;
        if(this.state.isOpen){
            isOpen = false;
        }
        this.setState({isOpen});
    }

    render() {
        const { listData, listTitle, filters, filterFieldName, handleChangeSelectedFilter, searchString } = this.props;
        const { isOpen } = this.state;

        let sublist = [];

        listData.map(function(itemName){
            const safeName = itemName.toLowerCase();

            const node = <Node key={itemName}
                               handleChangeSelectedFilter={handleChangeSelectedFilter}
                               filterFieldName={filterFieldName}
                               filters={filters}
                               searchString={searchString}
                               itemName={itemName}
                            />;

            if( searchString !=="" && safeName.includes(searchString)){
                sublist.push(node);
            } else if (searchString===""){
                sublist.push(node);
            }

        });

        let iconClasses = "fa fa-plus-circle khb-treelist-icon";
        let sublistContent = "";
        if(isOpen){
            iconClasses = "fa fa-minus-circle khb-treelist-icon";
            sublistContent = sublist;
        }

        return (

                     {listTitle}

                    {sublistContent}

        );
    }
}

export default TreeSublist;<|endoftext|>