<commit_before>import batchUpdate from '../client/batchUpdate'
import $meta from './$meta'

import {
  VUE_META_KEY_NAME,
  VUE_META_ATTRIBUTE,
  VUE_META_SERVER_RENDERED_ATTRIBUTE,
  VUE_META_TAG_LIST_ID_KEY_NAME,
  VUE_META_TEMPLATE_KEY_NAME, VUE_META_CONTENT_KEY
} from './constants'

// automatic install
if (typeof window !== 'undefined' && typeof window.Vue !== 'undefined') {
  Vue.use(VueMeta)
}

/**
 * Plugin install function.
 * @param {Function} Vue - the Vue constructor.
 */
export default function VueMeta(Vue, options = {}) {
  // set some default options
  const defaultOptions = {
    keyName: VUE_META_KEY_NAME,
    contentKeyName: VUE_META_CONTENT_KEY,
    metaTemplateKeyName: VUE_META_TEMPLATE_KEY_NAME,
    attribute: VUE_META_ATTRIBUTE,
    ssrAttribute: VUE_META_SERVER_RENDERED_ATTRIBUTE,
    tagIDKeyName: VUE_META_TAG_LIST_ID_KEY_NAME
  }

  // combine options
  options = typeof options === 'object' ? options : {}

  for (const key in defaultOptions) {
    if (!options[key]) {
      options[key] = defaultOptions[key]
    }
  }

  // bind the $meta method to this component instance
  Vue.prototype.$meta = $meta(options)

  // store an id to keep track of DOM updates
  let batchID = null

  const triggerUpdate = (vm) => {
    // batch potential DOM updates to prevent extraneous re-rendering
    batchID = batchUpdate(batchID, () => vm.$meta().refresh())
  }

  // watch for client side component updates
  Vue.mixin({
    beforeCreate() {
      // Add a marker to know if it uses metaInfo
      // _vnode is used to know that it's attached to a real component
      // useful if we use some mixin to add some meta tags (like nuxt-i18n)
      if (typeof this.$options[options.keyName] !== 'undefined' && this.$options[options.keyName] !== null) {
        this._hasMetaInfo = true

        // coerce function-style metaInfo to a computed prop so we can observe
        // it on creation
        if (typeof this.$options[options.keyName] === 'function') {
          if (typeof this.$options.computed === 'undefined') {
            this.$options.computed = {}
          }
          this.$options.computed.$metaInfo = this.$options[options.keyName]

          if (!this.$isServer) {
            // if computed $metaInfo exists, watch it for updates & trigger a refresh
            // when it changes (i.e. automatically handle async actions that affect metaInfo)
            // credit for this suggestion goes to [Sébastien Chopin](https://github.com/Atinux)
            this.$options.created = this.$options.created || []
            this.$options.created.push(() => {
              this.$watch('$metaInfo', () => triggerUpdate(this))
            })
          }
        }

        ['activated', 'deactivated', 'beforeMount'].forEach((lifecycleHook) => {
          this.$options[lifecycleHook] = this.$options[lifecycleHook] || []
          this.$options[lifecycleHook].push(() => triggerUpdate(this))
        })

        // do not trigger refresh on the server side
        if (!this.$isServer) {
          // re-render meta data when returning from a child component to parent
          this.$options.destroyed = this.$options.destroyed || []
          this.$options.destroyed.push(() => {
            // Wait that element is hidden before refreshing meta tags (to support animations)
            const interval = setInterval(() => {
              if (this.$el && this.$el.offsetParent !== null) {
                return
              }

              clearInterval(interval)

              if (!this.$parent) {
                return
              }

              triggerUpdate(this)
            }, 50)
          })
        }
      }
    }
    /* Not yet removed
    created() {
      // if computed $metaInfo exists, watch it for updates & trigger a refresh
      // when it changes (i.e. automatically handle async actions that affect metaInfo)
      // credit for this suggestion goes to [Sébastien Chopin](https://github.com/Atinux)
      if (!this.$isServer && this.$metaInfo) {
        this.$watch('$metaInfo', () => triggerUpdate(this))
      }

    },
    activated() {
      if (this._hasMetaInfo) {
        triggerUpdate(this)
      }
    },
    deactivated() {
      if (this._hasMetaInfo) {
        triggerUpdate(this)
      }
    },
    beforeMount() {
      if (this._hasMetaInfo) {
        triggerUpdate(this)
      }
    },
    destroyed() {
      // do not trigger refresh on the server side
      if (this.$isServer) {
        return
      }

      // re-render meta data when returning from a child component to parent
      if (this._hasMetaInfo) {
        // Wait that element is hidden before refreshing meta tags (to support animations)
        const interval = setInterval(() => {
          if (this.$el && this.$el.offsetParent !== null) {
            return
          }

          clearInterval(interval)

          if (!this.$parent) {
            return
          }

          triggerUpdate(this)
        }, 50)
      }
    }/**/
  })
}
<commit_msg>fix: another inline array to const<commit_after>import batchUpdate from '../client/batchUpdate'
import $meta from './$meta'

import {
  VUE_META_KEY_NAME,
  VUE_META_ATTRIBUTE,
  VUE_META_SERVER_RENDERED_ATTRIBUTE,
  VUE_META_TAG_LIST_ID_KEY_NAME,
  VUE_META_TEMPLATE_KEY_NAME, VUE_META_CONTENT_KEY
} from './constants'

// automatic install
if (typeof window !== 'undefined' && typeof window.Vue !== 'undefined') {
  Vue.use(VueMeta)
}

/**
 * Plugin install function.
 * @param {Function} Vue - the Vue constructor.
 */
export default function VueMeta(Vue, options = {}) {
  // set some default options
  const defaultOptions = {
    keyName: VUE_META_KEY_NAME,
    contentKeyName: VUE_META_CONTENT_KEY,
    metaTemplateKeyName: VUE_META_TEMPLATE_KEY_NAME,
    attribute: VUE_META_ATTRIBUTE,
    ssrAttribute: VUE_META_SERVER_RENDERED_ATTRIBUTE,
    tagIDKeyName: VUE_META_TAG_LIST_ID_KEY_NAME
  }

  // combine options
  options = typeof options === 'object' ? options : {}

  for (const key in defaultOptions) {
    if (!options[key]) {
      options[key] = defaultOptions[key]
    }
  }

  // bind the $meta method to this component instance
  Vue.prototype.$meta = $meta(options)

  // store an id to keep track of DOM updates
  let batchID = null

  // for which Vue lifecycle hooks should the metaInfo be refreshed
  const updateOnLifecycleHook = ['activated', 'deactivated', 'beforeMount']

  const triggerUpdate = (vm) => {
    // batch potential DOM updates to prevent extraneous re-rendering
    batchID = batchUpdate(batchID, () => vm.$meta().refresh())
  }

  // watch for client side component updates
  Vue.mixin({
    beforeCreate() {
      // Add a marker to know if it uses metaInfo
      // _vnode is used to know that it's attached to a real component
      // useful if we use some mixin to add some meta tags (like nuxt-i18n)
      if (typeof this.$options[options.keyName] !== 'undefined' && this.$options[options.keyName] !== null) {
        this._hasMetaInfo = true

        // coerce function-style metaInfo to a computed prop so we can observe
        // it on creation
        if (typeof this.$options[options.keyName] === 'function') {
          if (typeof this.$options.computed === 'undefined') {
            this.$options.computed = {}
          }
          this.$options.computed.$metaInfo = this.$options[options.keyName]

          if (!this.$isServer) {
            // if computed $metaInfo exists, watch it for updates & trigger a refresh
            // when it changes (i.e. automatically handle async actions that affect metaInfo)
            // credit for this suggestion goes to [Sébastien Chopin](https://github.com/Atinux)
            this.$options.created = this.$options.created || []
            this.$options.created.push(() => {
              this.$watch('$metaInfo', () => triggerUpdate(this))
            })
          }
        }

        updateOnLifecycleHook.forEach((lifecycleHook) => {
          this.$options[lifecycleHook] = this.$options[lifecycleHook] || []
          this.$options[lifecycleHook].push(() => triggerUpdate(this))
        })

        // do not trigger refresh on the server side
        if (!this.$isServer) {
          // re-render meta data when returning from a child component to parent
          this.$options.destroyed = this.$options.destroyed || []
          this.$options.destroyed.push(() => {
            // Wait that element is hidden before refreshing meta tags (to support animations)
            const interval = setInterval(() => {
              if (this.$el && this.$el.offsetParent !== null) {
                return
              }

              clearInterval(interval)

              if (!this.$parent) {
                return
              }

              triggerUpdate(this)
            }, 50)
          })
        }
      }
    }
    /* Not yet removed
    created() {
      // if computed $metaInfo exists, watch it for updates & trigger a refresh
      // when it changes (i.e. automatically handle async actions that affect metaInfo)
      // credit for this suggestion goes to [Sébastien Chopin](https://github.com/Atinux)
      if (!this.$isServer && this.$metaInfo) {
        this.$watch('$metaInfo', () => triggerUpdate(this))
      }

    },
    activated() {
      if (this._hasMetaInfo) {
        triggerUpdate(this)
      }
    },
    deactivated() {
      if (this._hasMetaInfo) {
        triggerUpdate(this)
      }
    },
    beforeMount() {
      if (this._hasMetaInfo) {
        triggerUpdate(this)
      }
    },
    destroyed() {
      // do not trigger refresh on the server side
      if (this.$isServer) {
        return
      }

      // re-render meta data when returning from a child component to parent
      if (this._hasMetaInfo) {
        // Wait that element is hidden before refreshing meta tags (to support animations)
        const interval = setInterval(() => {
          if (this.$el && this.$el.offsetParent !== null) {
            return
          }

          clearInterval(interval)

          if (!this.$parent) {
            return
          }

          triggerUpdate(this)
        }, 50)
      }
    }/**/
  })
}
<|endoftext|>


<commit_before>/**
 * @depend ../sinon.js
 * @depend collection.js
 * @depend util/timers.js
 */
/*jslint indent: 2, eqeqeq: false, onevar: false*/
/*global module, require, sinon*/
/**
 * Sandboxes are like collections, except they also handle
 * Manages fake collections as well as fake utilities such as Sinon's
 * timers and fake XHR implementation in one convenient object.
 *
 * @author Christian Johansen (christian@cjohansen.no)
 * @license BSD
 *
 * Copyright (c) 2010 Christian Johansen
 */
(function (sinon) {
  var commonJSModule = typeof module == "object" && typeof require == "function";

  if (!sinon && commonJSModule) {
    sinon = require("sinon");
  }

  if (!sinon) {
    return;
  }

  var sandbox = sinon.extend(sinon.create(sinon.collection), {
    useFakeTimers: function useFakeTimers() {
      this.clock = sinon.useFakeTimers.apply(sinon, arguments);

      return this.add(this.clock);
    }
  });

  if (commonJSModule) {
    module.exports = sandbox;
  } else {
    sinon.sandbox = sandbox;
  }
}(typeof sinon == "object" && sinon || null));
<commit_msg>Remove dead doc line<commit_after>/**
 * @depend ../sinon.js
 * @depend collection.js
 * @depend util/timers.js
 */
/*jslint indent: 2, eqeqeq: false, onevar: false*/
/*global module, require, sinon*/
/**
 * Manages fake collections as well as fake utilities such as Sinon's
 * timers and fake XHR implementation in one convenient object.
 *
 * @author Christian Johansen (christian@cjohansen.no)
 * @license BSD
 *
 * Copyright (c) 2010 Christian Johansen
 */
(function (sinon) {
  var commonJSModule = typeof module == "object" && typeof require == "function";

  if (!sinon && commonJSModule) {
    sinon = require("sinon");
  }

  if (!sinon) {
    return;
  }

  var sandbox = sinon.extend(sinon.create(sinon.collection), {
    useFakeTimers: function useFakeTimers() {
      this.clock = sinon.useFakeTimers.apply(sinon, arguments);

      return this.add(this.clock);
    }
  });

  if (commonJSModule) {
    module.exports = sandbox;
  } else {
    sinon.sandbox = sandbox;
  }
}(typeof sinon == "object" && sinon || null));
<|endoftext|>


<commit_before>var claimer = require('role.claimer');
var optimizeWorkers = require('optimize.workers');

function countRoles(room, role) {
  return _.filter(room.find(FIND_MY_CREEPS), (creep) => creep.memory.role == role).length;
}

function getCost(body) {
  var cost = 0;
  for (var piece of body) {
    cost += BODYPART_COST[piece];
  }
  return cost;
}

var WORK_ADDS = [
  [WORK, CARRY, MOVE],
  [WORK, MOVE],
  [CARRY, MOVE],
  [MOVE]
];

var DEFENSE_ADDS = [
  [TOUGH, RANGED_ATTACK, MOVE, MOVE],
  [TOUGH, ATTACK, MOVE, MOVE],
  [ATTACK, MOVE],
  [TOUGH, MOVE],
  [MOVE],
];

function getBody(role, energy) {
  let adds, base, movesPerBody;
  if (role === 'attacker' || role === 'defender') {
    base = [TOUGH, TOUGH, MOVE, ATTACK, ATTACK, MOVE];
    adds = DEFENSE_ADDS;
    movesPerBody = 1;
  } else {
    adds = WORK_ADDS;
    base = [WORK, CARRY, MOVE];
    movesPerBody = 0.5;
  }
  var cost = getCost(base);

  while (cost < energy && base.length < MAX_CREEP_SIZE) {
    var remaining = energy - cost;
    var added = false;

    // add the largest chunk we can, bail if there isn't enough energy left
    for (var i in adds) {
      var toAdd = adds[i];
      if (getCost(toAdd) < remaining && (toAdd.length + base.length) <= MAX_CREEP_SIZE) {
        base = base.concat(toAdd);
        cost = getCost(base);
        added = true;
        break;
      }
    }

    if (!added) {
      break;
    }
  }

  // now remove any extra MOVE body parts
  var numMoves = _.filter(base, b => b === MOVE).length;
  var movesRequired = Math.ceil((base.length - numMoves) * movesPerBody);
  for (var i in base) {
    if (numMoves <= movesRequired) break;
    if (base[i] === MOVE) {
      base[i] = null;
      numMoves -= 1;
    }
  }

  return _.filter(base, b => b != null);
}

function spawnCreep(spawn, role, energy) {
  var body = getBody(role, energy);
  var cost = getCost(body);
  if (spawn.canCreateCreep(body) === OK) {
    spawn.room.log('Spawning a ' + role + ' using ' + cost + ' energy ');
    spawn.createCreep(body, undefined, {role: role});
  }
}

function switchRole(room, count, from, to) {
  var fromCreeps = room.find(FIND_MY_CREEPS, {
    filter: (creep) => creep.memory.role === from
  });
  for (var i = 0; i < count && i < fromCreeps.length; i++) {
    var toSwitch = fromCreeps[i];
    toSwitch.memory.role = to;
    room.log('Switched ' + toSwitch.name + ' to ' + to);
  }
}

function run() {
  optimizeWorkers.initMemory();
  optimizeWorkers.checkEnergy();

  var spawnedMiner = false;

  for (var name in Game.spawns) {
    var spawn = Game.spawns[name];
    var room = spawn.room;

    var creeps = room.find(FIND_MY_CREEPS);
    var numCreeps = countRoles(room, 'harvester');
    var noCreeps = numCreeps === 0 && room.energyAvailable >= 300;
    var tooManyCreeps = numCreeps >= optimizeWorkers.getMaxCreeps(room.name);
    var maxEnergy = room.energyAvailable === room.energyCapacityAvailable;
    var usingFatCreeps = _.filter(creeps, c => c.memory.cost > room.energyCapacityAvailable).length > 0;

    var wartime = Memory.warTarget && tooManyCreeps;

    var spawnExpander = !noCreeps && countRoles(room, 'claimer') === 0 && claimer.shouldExpand(room);
    var extractors = room.find(FIND_MY_STRUCTURES, {
      filter: s => s.structureType === STRUCTURE_EXTRACTOR
    });

    var baddies = room.find(FIND_HOSTILE_CREEPS);
    var towers = room.find(FIND_MY_STRUCTURES, {
      filter: s => s.structureType === STRUCTURE_TOWER
    });

    if (baddies.length > towers.length) {
      spawnCreep(spawn, 'defender', Math.min(1500, room.energyAvailable));
    } else if (spawnExpander) {
      claimer.spawnExpander(spawn);
    } else if (wartime) {
      spawnCreep(spawn, 'attacker', Math.min(2000, room.energyAvailable));
    } else if (!tooManyCreeps && !usingFatCreeps && (maxEnergy || noCreeps)) {
      spawnCreep(spawn, 'harvester', room.energyAvailable);
    } else if (!spawnedMiner && tooManyCreeps && extractors.length > 0 && countRoles(room, 'miner') === 0) {
      spawnedMiner = true;
      var minerals = spawn.pos.findClosestByRange(FIND_MINERALS, {
        filter: m => m.mineralAmount > 0
      });
      if (minerals) {
        spawnCreep(spawn, 'miner', room.energyAvailable);
      }
    }
  }
}

module.exports = {
  run: run,
  getBody: getBody,
  getCost: getCost,
  countRoles: countRoles
};
<commit_msg>spawn shittier attackers<commit_after>var claimer = require('role.claimer');
var optimizeWorkers = require('optimize.workers');

function countRoles(room, role) {
  return _.filter(room.find(FIND_MY_CREEPS), (creep) => creep.memory.role == role).length;
}

function getCost(body) {
  var cost = 0;
  for (var piece of body) {
    cost += BODYPART_COST[piece];
  }
  return cost;
}

var WORK_ADDS = [
  [WORK, CARRY, MOVE],
  [WORK, MOVE],
  [CARRY, MOVE],
  [MOVE]
];

var DEFENSE_ADDS = [
  [TOUGH, ATTACK, RANGED_ATTACK, MOVE, MOVE, MOVE],
  [TOUGH, ATTACK, MOVE, MOVE],
  [ATTACK, MOVE],
  [TOUGH, MOVE],
  [MOVE],
];

function getBody(role, energy) {
  let adds, base, movesPerBody;
  if (role === 'attacker' || role === 'defender') {
    base = [ATTACK, MOVE];
    adds = DEFENSE_ADDS;
    movesPerBody = 1;
  } else {
    adds = WORK_ADDS;
    base = [WORK, CARRY, MOVE];
    movesPerBody = 0.5;
  }
  var cost = getCost(base);

  while (cost < energy && base.length < MAX_CREEP_SIZE) {
    var remaining = energy - cost;
    var added = false;

    // add the largest chunk we can, bail if there isn't enough energy left
    for (var i in adds) {
      var toAdd = adds[i];
      if (getCost(toAdd) < remaining && (toAdd.length + base.length) <= MAX_CREEP_SIZE) {
        base = base.concat(toAdd);
        cost = getCost(base);
        added = true;
        break;
      }
    }

    if (!added) {
      break;
    }
  }

  // now remove any extra MOVE body parts
  var numMoves = _.filter(base, b => b === MOVE).length;
  var movesRequired = Math.ceil((base.length - numMoves) * movesPerBody);
  for (var i in base) {
    if (numMoves <= movesRequired) break;
    if (base[i] === MOVE) {
      base[i] = null;
      numMoves -= 1;
    }
  }

  return _.filter(base, b => b != null);
}

function spawnCreep(spawn, role, energy) {
  var body = getBody(role, energy);
  var cost = getCost(body);
  if (spawn.canCreateCreep(body) === OK) {
    spawn.room.log('Spawning a ' + role + ' using ' + cost + ' energy ');
    spawn.createCreep(body, undefined, {role: role});
  }
}

function switchRole(room, count, from, to) {
  var fromCreeps = room.find(FIND_MY_CREEPS, {
    filter: (creep) => creep.memory.role === from
  });
  for (var i = 0; i < count && i < fromCreeps.length; i++) {
    var toSwitch = fromCreeps[i];
    toSwitch.memory.role = to;
    room.log('Switched ' + toSwitch.name + ' to ' + to);
  }
}

function run() {
  optimizeWorkers.initMemory();
  optimizeWorkers.checkEnergy();

  var spawnedMiner = false;

  for (var name in Game.spawns) {
    var spawn = Game.spawns[name];
    var room = spawn.room;

    var creeps = room.find(FIND_MY_CREEPS);
    var numCreeps = countRoles(room, 'harvester');
    var noCreeps = numCreeps === 0 && room.energyAvailable >= 300;
    var tooManyCreeps = numCreeps >= optimizeWorkers.getMaxCreeps(room.name);
    var maxEnergy = room.energyAvailable === room.energyCapacityAvailable;
    var usingFatCreeps = _.filter(creeps, c => c.memory.cost > room.energyCapacityAvailable).length > 0;

    var wartime = Memory.warTarget && tooManyCreeps;

    var spawnExpander = !noCreeps && countRoles(room, 'claimer') === 0 && claimer.shouldExpand(room);
    var extractors = room.find(FIND_MY_STRUCTURES, {
      filter: s => s.structureType === STRUCTURE_EXTRACTOR
    });

    var baddies = room.find(FIND_HOSTILE_CREEPS);
    var towers = room.find(FIND_MY_STRUCTURES, {
      filter: s => s.structureType === STRUCTURE_TOWER
    });

    if (baddies.length > towers.length) {
      spawnCreep(spawn, 'defender', Math.min(1500, room.energyAvailable));
    } else if (spawnExpander) {
      claimer.spawnExpander(spawn);
    } else if (wartime) {
      spawnCreep(spawn, 'attacker', Math.min(2000, room.energyAvailable));
    } else if (!tooManyCreeps && !usingFatCreeps && (maxEnergy || noCreeps)) {
      spawnCreep(spawn, 'harvester', room.energyAvailable);
    } else if (!spawnedMiner && tooManyCreeps && extractors.length > 0 && countRoles(room, 'miner') === 0) {
      spawnedMiner = true;
      var minerals = spawn.pos.findClosestByRange(FIND_MINERALS, {
        filter: m => m.mineralAmount > 0
      });
      if (minerals) {
        spawnCreep(spawn, 'miner', room.energyAvailable);
      }
    }
  }
}

module.exports = {
  run: run,
  getBody: getBody,
  getCost: getCost,
  countRoles: countRoles
};
<|endoftext|>


<commit_before>/* @flow */

// The standard runnable actions
export type Runnable<T> = {
	run: () => Promise<?T>
};

export type ParticipantRole = 'HOST' | 'GUEST';

// Defines the options for new participants
export type NewParticipant = {
	+display_name: string,
	+fee?: JSONFee,
	+role: ParticipantRole,
	+picture?: string,
	+state?: string
};

// Defines the options for updating participants
export type UpdateParticipant = {
	+display_name?: string,
	+fee?: JSONFee,
	+role?: ParticipantRole,
	+picture?: string,
	+state?: string
};

// Defines the options for creating a new session
export type SessionCreate = {
	session_name: string,
	start_time: string,
	end_time: string,
	picture?: string,
	participants?: Array<NewParticipant>
};

// Defines the options for when updating an existing session
export type SessionUpdate = {
	session_name: ?string,
	start_time: string,
	end_time: string,
	picture: ?string
};

// Defines the options for when querying the sessions
export type SessionPageQuery = {|
	page?: number,
	page_size?: number,
	start_time?: string,
	end_time?: string,
	included_canceled?: boolean
|};

// The response from a paged query
export type PagedResponse<T> = {|
	content: Array<T>,
	more: boolean,
	page: number,
	page_size: number
|};

// Alias for the fee (this may be replaced at some point as it's currently stored as a JSON string)
export type JSONFee = string;

// The structure for the fee that is stored within the JSONFee string
export type Fee = {
	amount: number,
	description: ?string,
	currency: string
};

// The information for the participant in a call
export type CallParticipant = {|
	client_id: string,
	deleted_at?: string,
	display_name: string,
	entry_url: string,
	fee?: JSONFee,
	participant_id: string,
	picture: ?string,
	role: ParticipantRole,
	session_id: string,
	state: ?string
|};

// The information for a created call session
export type CallSession = {|
	+session_id: string,
	+session_name: ?string,
	+start_time: string,
	+end_time: string,
	+picture: ?string,
	+team_id: string,
	+client_id: string,
	+participants: Array<CallParticipant>
|};

export type CoviuClientSDK = {|
	sessions: {
		addParticipant: (sessionId: string, participant: NewParticipant) => Runnable<CallParticipant>,
		cancelSession: (sessionId: string) => Runnable<any>,
		createSession: (SessionCreate) => Runnable<?CallSession>,
		deleteParticipant: (participantId: string) => Runnable<any>,
		deleteSession: (sessionId: string) => Runnable<?any>,
		getParticipant: (participantId: string) => Runnable<CallParticipant>,
		getSession: (sessionId: string) => Runnable<CallSession>,
		getSessionParticipants: (sessionId: string) => Runnable<Array<CallParticipant>>,
		getSessions: (query: SessionPageQuery) => Runnable<PagedResponse<CallSession>>,
		updateParticipant: (participantId: string, update: UpdateParticipant) => Runnable<CallParticipant>,
		updateSession: (sessionId: string, update: SessionUpdate) => Runnable<CallSession>,
	}
|};<commit_msg>Cleanup indentations<commit_after>/* @flow */

// The standard runnable actions
export type Runnable<T> = {
  run: () => Promise<?T>
};

export type ParticipantRole = 'HOST' | 'GUEST';

// Defines the options for new participants
export type NewParticipant = {
  +display_name: string,
  +fee?: JSONFee,
  +role: ParticipantRole,
  +picture?: string,
  +state?: string
};

// Defines the options for updating participants
export type UpdateParticipant = {
  +display_name?: string,
  +fee?: JSONFee,
  +role?: ParticipantRole,
  +picture?: string,
  +state?: string
};

// Defines the options for creating a new session
export type SessionCreate = {
  session_name: string,
  start_time: string,
  end_time: string,
  picture?: string,
  participants?: Array<NewParticipant>
};

// Defines the options for when updating an existing session
export type SessionUpdate = {
  session_name: ?string,
  start_time: string,
  end_time: string,
  picture: ?string
};

// Defines the options for when querying the sessions
export type SessionPageQuery = {|
  page?: number,
  page_size?: number,
  start_time?: string,
  end_time?: string,
  included_canceled?: boolean
|};

// The response from a paged query
export type PagedResponse<T> = {|
  content: Array<T>,
  more: boolean,
  page: number,
  page_size: number
|};

// Alias for the fee (this may be replaced at some point as it's currently stored as a JSON string)
export type JSONFee = string;

// The structure for the fee that is stored within the JSONFee string
export type Fee = {
  amount: number,
  description: ?string,
  currency: string
};

// The information for the participant in a call
export type CallParticipant = {|
  client_id: string,
  deleted_at?: string,
  display_name: string,
  entry_url: string,
  fee?: JSONFee,
  participant_id: string,
  picture: ?string,
  role: ParticipantRole,
  session_id: string,
  state: ?string
|};

// The information for a created call session
export type CallSession = {|
  +session_id: string,
  +session_name: ?string,
  +start_time: string,
  +end_time: string,
  +picture: ?string,
  +team_id: string,
  +client_id: string,
  +participants: Array<CallParticipant>
|};

export type CoviuClientSDK = {|
  sessions: {
    addParticipant: (sessionId: string, participant: NewParticipant) => Runnable<CallParticipant>,
    cancelSession: (sessionId: string) => Runnable<any>,
    createSession: (SessionCreate) => Runnable<?CallSession>,
    deleteParticipant: (participantId: string) => Runnable<any>,
    deleteSession: (sessionId: string) => Runnable<?any>,
    getParticipant: (participantId: string) => Runnable<CallParticipant>,
    getSession: (sessionId: string) => Runnable<CallSession>,
    getSessionParticipants: (sessionId: string) => Runnable<Array<CallParticipant>>,
    getSessions: (query: SessionPageQuery) => Runnable<PagedResponse<CallSession>>,
    updateParticipant: (participantId: string, update: UpdateParticipant) => Runnable<CallParticipant>,
    updateSession: (sessionId: string, update: SessionUpdate) => Runnable<CallSession>,
  }
|};<|endoftext|>


<commit_before>/*
 * tzmap.js - Library for working with the geography of timezones in JavaScript

 * Written in 2011 by L. David Baron <dbaron@dbaron.org>

 * To the extent possible under law, the author(s) have dedicated all
 * copyright and related and neighboring rights to this software to the
 * public domain worldwide.  This software is distributed without any
 * warranty.
 *
 * You should have received a copy of the CC0 Public Domain Dedication
 * along with this software.  If not, see
 * <http://creativecommons.org/publicdomain/zero/1.0/>.
 */
(function() {
    "use strict";

    var gXHR = null;
    var gLoadSuccessCallbacks = [];
    var gLoadErrorCallbacks = [];
    var gJSON = null;

    var public_loadData = function(path, success_callback, error_callback) {
        if (gJSON) {
            if (success_callback) {
                setTimeout(success_callback, 0);
            }
            return;
        }
        if (success_callback) {
            gLoadSuccessCallbacks.push(success_callback);
        }
        if (error_callback) {
            gLoadErrorCallbacks.push(error_callback);
        }
        if (gXHR) {
            return;
        }

        var protocol_match = path.match(/^([^/?#]+):/)
        var isHTTP;
        if (protocol_match) {
            isHTTP = protocol_match[1] == "http" ||
                     protocol_match[1] == "https";
        } else {
            isHTTP = window.location.protocol == "http:" ||
                     window.location.protocol == "https:";
        }
        path += "world-map.json";
        if (isHTTP) {
            path += ".gz";
        }

        function do_notify(success) {
            var callbacks = success ? gLoadSuccessCallbacks
                                    : gLoadErrorCallbacks;

            gLoadSuccessCallbacks = [];
            gLoadErrorCallbacks = [];
            gXHR = null;

            for (var idx in callbacks) {
                callbacks[idx]();
            }
        }

        function rsc() {
            if (gXHR.readyState != 4) {
                return;
            }

            var success = false;
            if (!isHTTP || (200 <= gXHR.status && gXHR.status < 300)) {
                var json = null;
                try {
                    if ("responseType" in gXHR) {
                        json = gXHR.response;
                    } else {
                        json = JSON.parse(gXHR.responseText);
                    }
                } catch (ex) {
                }
                if (json && json.chains && json.zones) {
                    success = true;
                    gJSON = json;
                }
            }

            do_notify(success);
        }

        try {
            gXHR = new XMLHttpRequest();
            gXHR.onreadystatechange = rsc;
            gXHR.open("GET", path);
            if ("responseType" in gXHR) {
                gXHR.responseType = "json";
            }
            gXHR.send();
        } catch(ex) {
            do_notify(false);
        }
    }

    /**
     * Check if needle is in [rangea, rangeb] or [rangeb, rangea].
     */
    function in_range(needle, rangea, rangeb) {
        if (rangea < rangeb) {
            return rangea <= needle && needle <= rangeb;
        } else {
            return rangeb <= needle && needle <= rangea;
        }
    }

    function zoneContains(tzid, lat, lon) {
        var zones = gJSON.zones;
        var chains = gJSON.chains;

        var zone = zones[tzid];
        for (var polygonIdx in zone) {
            var polygon = zone[polygonIdx];

            // Since we don't need to worry about zones containing the
            // north pole (FIXME: really?), we can just count the number
            // of times that a north-south line from the north pole to
            // our point intersects the zone.
            // Furthermore, the segments are short enough that we don't
            // need to worry about whether they're great circle lines or
            // lines on an easier projection.
            var intersects = 0;
            for (var chainIdx in polygon) {
                var chainobj = polygon[chainIdx];
                var chainID = chainobj[0];
                var chainInv = chainobj[1];
                var chain = chains[chainID];
                var prevlon, prevlat;
                for (var pointIdx in chain) {
                    var pointobj = chain[pointIdx];
                    var ptlon = pointobj[0];
                    var ptlat = pointobj[1];
                    if (pointIdx > 0) {
                        if (ptlon == prevlon) {
                            // vertical line.  All we need to do is
                            // check if our point is *on* it.
                            if (ptlon == lon
                                && in_range(lat, ptlat, prevlat))
                                return true;
                        } else {
                            var alon, ptalon, prevalon;
                            if (Math.abs(ptlon - prevlon) > 180) {
                                // this segment crosses the date line,
                                // so use adjusted numbers instead
                                alon = (lon + 180) % 360;
                                ptalon = (ptlon + 180) % 360;
                                prevalon = (prevlon + 180) % 360;
                            } else {
                                alon = lon;
                                ptalon = ptlon;
                                prevalon = prevlon;
                            }

                            if (ptalon < prevalon) {
                                var tmp = ptalon;
                                ptalon = prevalon;
                                prevalon = tmp;
                            }

                            // Check the endpoint at the west end but
                            // not the east end.  This does the right
                            // thing for the intersects count, since we
                            // need to worry about both what happens
                            // when the segments turn back the opposite
                            // east/west or continue the same east/west
                            // from the boundary.  FIXME: But it's not
                            // quite right for the on-the-line check.
                            if (prevalon <= alon && alon < ptalon) {
                                var xlat = prevlat + (ptlat - prevlat) * ((alon - prevalon) / (ptalon - prevalon));
                                if (xlat == lat)
                                    // on the line
                                    return true;
                                if (xlat > lat) {
                                    ++intersects;
                                }
                            }
                        }
                    }
                    prevlon = ptlon;
                    prevlat = ptlat;
                }
            }
            if (intersects % 2 == 1) {
                return true;
            }
        }
        return false;
    }

    var public_zoneContains = function(zone, lat, lon) {
        if (lat >= 90 || lat <= -90)
            return null;
        lon = ((lon % 360) + 180) % 360 - 180;

        return zoneContains(zone, lat, lon);
    }

    var public_zoneAt = function(lat, lon) {
        if (lat >= 90 || lat <= -90)
            return null;
        lon = ((lon % 360) + 180) % 360 - 180;

        for (var tzid in gJSON.zones) {
            if (zoneContains(tzid, lat, lon)) {
                return tzid;
            }
        }
        return null;
    }

    function firstpt(chainID) {
        return gJSON.chains[chainID][0];
    }

    function lastpt(chainID) {
        var chain = gJSON.chains[chainID];
        return chain[chain.length - 1];
    }

    function pts_equal(a, b) {
        return a[0] == b[0] && a[1] == b[1];
    }

    var public_polygonsFor = function(zone_array) {
        // A set of chain IDs, except there is a useful value on the
        // value side of the hash:  whether the chain is used forwards
        // (false) or in reverse (true).
        var chains = {};

        for (var zoneIdx in zone_array) {
            var tzid = zone_array[zoneIdx];
            var zone = gJSON.zones[tzid];
            for (var polygonIdx in zone) {
                var polygon = zone[polygonIdx];
                for (var chainIdx in polygon) {
                    var chainobj = polygon[chainIdx];
                    var chainID = chainobj[0];
                    var reverse = chainobj[1];
                    if (chainID in chains) {
                        // It's a shared boundary
                        delete chains[chainID];
                    } else {
                        chains[chainID] = reverse;
                    }
                }
            }
        }

        var result = [];

        // Append the polygons that are in one chain, and put the rest
        // of the chains in a hash by their starting longitude.
        var startlons = {};
        for (var chainID in chains) {
            if (pts_equal(firstpt(chainID), lastpt(chainID))) {
                // This chain is a complete polygon.
                var reverse = chains[chainID];
                var chain = gJSON.chains[chainID];
                if (chains[chainID]) {
                    // append in reverse
                    result.push([].concat(chain).reverse());
                } else {
                    // append in forward order (without copy)
                    result.push(chain);
                }
            } else {
                var reverse = chains[chainID];
                var info = { chainID: chainID, reverse: reverse };
                var startlon = (reverse ? lastpt : firstpt)(chainID)[0];
                if (startlon in startlons) {
                    startlons[startlon].push(info);
                } else {
                    startlons[startlon] = [ info ];
                }
            }
        }
        chains = null;

        // Deal with the polygons that we hashed by starting longitude.
        function first_startlon() {
            for (var startlon in startlons) {
                return startlon;
            }
            return null;
        }
        for (;;) {
            var startlon = first_startlon();
            if (startlon === null) {
                break;
            }
            var polygon = [];
            do {
                var arr, info;
                if (polygon.length == 0) {
                    arr = startlons[startlon];
                    info = arr.pop();
                } else {
                    var startpt = polygon[polygon.length - 1];
                    startlon = startpt[0];
                    arr = startlons[startlon];
                    info = null;
                    for (var idx in arr) {
                        var testinfo = arr[idx];
                        var testpt = (testinfo.reverse ? lastpt : firstpt)(testinfo.chainID);
                        if (testpt[1] == startpt[1]) {
                            arr.splice(idx, 1);
                            info = testinfo;
                            break;
                        }
                    }
                }
                if (arr.length == 0) {
                    delete startlons[startlon];
                }
                var chain = gJSON.chains[info.chainID];
                if (info.reverse) {
                    polygon = polygon.concat([].concat(chain).reverse());
                } else {
                    polygon = polygon.concat(chain);
                }
                // Note: minimum of 2 iterations
            } while (!pts_equal(polygon[0], polygon[polygon.length - 1]));
            result.push(polygon);
        }

        return result;
    }

    // Exports:
    window.tzmap = {
        /**
         * loadData(path, success_callback, error_callback)
         *
         * This library has to load a significant amount of timezone
         * boundary data in order to work.  This function triggers the
         * loading of the data.  The path argument given is the path to
         * the directory in which the data are located (usually the same
         * as the script), which must end with a slash, and may be a
         * path relative to the document.  When the loading completes
         * successfully, success_callback is called; if it fails,
         * error_callback is called.
         *
         * Other methods of this library can be used only after
         * success_callback has been called.
         */
        loadData: public_loadData,

        /**
         * zoneContains(zone, lat, lon)
         *
         * Return whether the time zone name (e.g.,
         * "America/Los_Angeles") contains the point at the given
         * latitude and longitude or has that point on its boundary.
         * Supports the "uninhabited" zone, but not null.
         */
        zoneContains: public_zoneContains,

        /**
         * zoneAt(lat, lon)
         *
         * Return the time zone name (e.g., "America/Los_Angeles") at
         * the given latitude and longitude, "uninhabited" for land
         * areas for which no time zone is known for the location (e.g.,
         * Antarctica), or null for water areas.  If the location is
         * exactly on a time zone boundary, which time zone will be
         * returned is undefined, but one of them will be.
         */
        zoneAt: public_zoneAt,

        /**
         * polygonsFor(zone_array)
         *
         * Get the set of polygons for a set of timezones.  Each name in
         * zone_array should be an tz database timezone name.  This API
         * will return an array of non-adjacent polygons, where each
         * polygon is an array of points (the first and last being the
         * same), and each point is an array of [lon, lat] as floats.
         */
        polygonsFor: public_polygonsFor,
    };
})();
<commit_msg>Switching responseType to 'json' breaks Chrome 16 nightly.<commit_after>/*
 * tzmap.js - Library for working with the geography of timezones in JavaScript

 * Written in 2011 by L. David Baron <dbaron@dbaron.org>

 * To the extent possible under law, the author(s) have dedicated all
 * copyright and related and neighboring rights to this software to the
 * public domain worldwide.  This software is distributed without any
 * warranty.
 *
 * You should have received a copy of the CC0 Public Domain Dedication
 * along with this software.  If not, see
 * <http://creativecommons.org/publicdomain/zero/1.0/>.
 */
(function() {
    "use strict";

    var gXHR = null;
    var gLoadSuccessCallbacks = [];
    var gLoadErrorCallbacks = [];
    var gJSON = null;

    var public_loadData = function(path, success_callback, error_callback) {
        if (gJSON) {
            if (success_callback) {
                setTimeout(success_callback, 0);
            }
            return;
        }
        if (success_callback) {
            gLoadSuccessCallbacks.push(success_callback);
        }
        if (error_callback) {
            gLoadErrorCallbacks.push(error_callback);
        }
        if (gXHR) {
            return;
        }

        var protocol_match = path.match(/^([^/?#]+):/)
        var isHTTP;
        if (protocol_match) {
            isHTTP = protocol_match[1] == "http" ||
                     protocol_match[1] == "https";
        } else {
            isHTTP = window.location.protocol == "http:" ||
                     window.location.protocol == "https:";
        }
        path += "world-map.json";
        if (isHTTP) {
            path += ".gz";
        }

        function do_notify(success) {
            var callbacks = success ? gLoadSuccessCallbacks
                                    : gLoadErrorCallbacks;

            gLoadSuccessCallbacks = [];
            gLoadErrorCallbacks = [];
            gXHR = null;

            for (var idx in callbacks) {
                callbacks[idx]();
            }
        }

        function rsc() {
            if (gXHR.readyState != 4) {
                return;
            }

            var success = false;
            if (!isHTTP || (200 <= gXHR.status && gXHR.status < 300)) {
                var json = null;
                try {
                    if ("responseType" in gXHR && gXHR.responseType == "json") {
                        json = gXHR.response;
                    } else {
                        json = JSON.parse(gXHR.responseText);
                    }
                } catch (ex) {
                }
                if (json && json.chains && json.zones) {
                    success = true;
                    gJSON = json;
                }
            }

            do_notify(success);
        }

        try {
            gXHR = new XMLHttpRequest();
            gXHR.onreadystatechange = rsc;
            gXHR.open("GET", path);
            if ("responseType" in gXHR) {
                try {
                    gXHR.responseType = "json";
                } catch(ex) {
                    // Chrome 16 (nightly) supports "text" but not "json"
                    gXHR.responseType = "text";
                }
            }
            gXHR.send();
        } catch(ex) {
            do_notify(false);
        }
    }

    /**
     * Check if needle is in [rangea, rangeb] or [rangeb, rangea].
     */
    function in_range(needle, rangea, rangeb) {
        if (rangea < rangeb) {
            return rangea <= needle && needle <= rangeb;
        } else {
            return rangeb <= needle && needle <= rangea;
        }
    }

    function zoneContains(tzid, lat, lon) {
        var zones = gJSON.zones;
        var chains = gJSON.chains;

        var zone = zones[tzid];
        for (var polygonIdx in zone) {
            var polygon = zone[polygonIdx];

            // Since we don't need to worry about zones containing the
            // north pole (FIXME: really?), we can just count the number
            // of times that a north-south line from the north pole to
            // our point intersects the zone.
            // Furthermore, the segments are short enough that we don't
            // need to worry about whether they're great circle lines or
            // lines on an easier projection.
            var intersects = 0;
            for (var chainIdx in polygon) {
                var chainobj = polygon[chainIdx];
                var chainID = chainobj[0];
                var chainInv = chainobj[1];
                var chain = chains[chainID];
                var prevlon, prevlat;
                for (var pointIdx in chain) {
                    var pointobj = chain[pointIdx];
                    var ptlon = pointobj[0];
                    var ptlat = pointobj[1];
                    if (pointIdx > 0) {
                        if (ptlon == prevlon) {
                            // vertical line.  All we need to do is
                            // check if our point is *on* it.
                            if (ptlon == lon
                                && in_range(lat, ptlat, prevlat))
                                return true;
                        } else {
                            var alon, ptalon, prevalon;
                            if (Math.abs(ptlon - prevlon) > 180) {
                                // this segment crosses the date line,
                                // so use adjusted numbers instead
                                alon = (lon + 180) % 360;
                                ptalon = (ptlon + 180) % 360;
                                prevalon = (prevlon + 180) % 360;
                            } else {
                                alon = lon;
                                ptalon = ptlon;
                                prevalon = prevlon;
                            }

                            if (ptalon < prevalon) {
                                var tmp = ptalon;
                                ptalon = prevalon;
                                prevalon = tmp;
                            }

                            // Check the endpoint at the west end but
                            // not the east end.  This does the right
                            // thing for the intersects count, since we
                            // need to worry about both what happens
                            // when the segments turn back the opposite
                            // east/west or continue the same east/west
                            // from the boundary.  FIXME: But it's not
                            // quite right for the on-the-line check.
                            if (prevalon <= alon && alon < ptalon) {
                                var xlat = prevlat + (ptlat - prevlat) * ((alon - prevalon) / (ptalon - prevalon));
                                if (xlat == lat)
                                    // on the line
                                    return true;
                                if (xlat > lat) {
                                    ++intersects;
                                }
                            }
                        }
                    }
                    prevlon = ptlon;
                    prevlat = ptlat;
                }
            }
            if (intersects % 2 == 1) {
                return true;
            }
        }
        return false;
    }

    var public_zoneContains = function(zone, lat, lon) {
        if (lat >= 90 || lat <= -90)
            return null;
        lon = ((lon % 360) + 180) % 360 - 180;

        return zoneContains(zone, lat, lon);
    }

    var public_zoneAt = function(lat, lon) {
        if (lat >= 90 || lat <= -90)
            return null;
        lon = ((lon % 360) + 180) % 360 - 180;

        for (var tzid in gJSON.zones) {
            if (zoneContains(tzid, lat, lon)) {
                return tzid;
            }
        }
        return null;
    }

    function firstpt(chainID) {
        return gJSON.chains[chainID][0];
    }

    function lastpt(chainID) {
        var chain = gJSON.chains[chainID];
        return chain[chain.length - 1];
    }

    function pts_equal(a, b) {
        return a[0] == b[0] && a[1] == b[1];
    }

    var public_polygonsFor = function(zone_array) {
        // A set of chain IDs, except there is a useful value on the
        // value side of the hash:  whether the chain is used forwards
        // (false) or in reverse (true).
        var chains = {};

        for (var zoneIdx in zone_array) {
            var tzid = zone_array[zoneIdx];
            var zone = gJSON.zones[tzid];
            for (var polygonIdx in zone) {
                var polygon = zone[polygonIdx];
                for (var chainIdx in polygon) {
                    var chainobj = polygon[chainIdx];
                    var chainID = chainobj[0];
                    var reverse = chainobj[1];
                    if (chainID in chains) {
                        // It's a shared boundary
                        delete chains[chainID];
                    } else {
                        chains[chainID] = reverse;
                    }
                }
            }
        }

        var result = [];

        // Append the polygons that are in one chain, and put the rest
        // of the chains in a hash by their starting longitude.
        var startlons = {};
        for (var chainID in chains) {
            if (pts_equal(firstpt(chainID), lastpt(chainID))) {
                // This chain is a complete polygon.
                var reverse = chains[chainID];
                var chain = gJSON.chains[chainID];
                if (chains[chainID]) {
                    // append in reverse
                    result.push([].concat(chain).reverse());
                } else {
                    // append in forward order (without copy)
                    result.push(chain);
                }
            } else {
                var reverse = chains[chainID];
                var info = { chainID: chainID, reverse: reverse };
                var startlon = (reverse ? lastpt : firstpt)(chainID)[0];
                if (startlon in startlons) {
                    startlons[startlon].push(info);
                } else {
                    startlons[startlon] = [ info ];
                }
            }
        }
        chains = null;

        // Deal with the polygons that we hashed by starting longitude.
        function first_startlon() {
            for (var startlon in startlons) {
                return startlon;
            }
            return null;
        }
        for (;;) {
            var startlon = first_startlon();
            if (startlon === null) {
                break;
            }
            var polygon = [];
            do {
                var arr, info;
                if (polygon.length == 0) {
                    arr = startlons[startlon];
                    info = arr.pop();
                } else {
                    var startpt = polygon[polygon.length - 1];
                    startlon = startpt[0];
                    arr = startlons[startlon];
                    info = null;
                    for (var idx in arr) {
                        var testinfo = arr[idx];
                        var testpt = (testinfo.reverse ? lastpt : firstpt)(testinfo.chainID);
                        if (testpt[1] == startpt[1]) {
                            arr.splice(idx, 1);
                            info = testinfo;
                            break;
                        }
                    }
                }
                if (arr.length == 0) {
                    delete startlons[startlon];
                }
                var chain = gJSON.chains[info.chainID];
                if (info.reverse) {
                    polygon = polygon.concat([].concat(chain).reverse());
                } else {
                    polygon = polygon.concat(chain);
                }
                // Note: minimum of 2 iterations
            } while (!pts_equal(polygon[0], polygon[polygon.length - 1]));
            result.push(polygon);
        }

        return result;
    }

    // Exports:
    window.tzmap = {
        /**
         * loadData(path, success_callback, error_callback)
         *
         * This library has to load a significant amount of timezone
         * boundary data in order to work.  This function triggers the
         * loading of the data.  The path argument given is the path to
         * the directory in which the data are located (usually the same
         * as the script), which must end with a slash, and may be a
         * path relative to the document.  When the loading completes
         * successfully, success_callback is called; if it fails,
         * error_callback is called.
         *
         * Other methods of this library can be used only after
         * success_callback has been called.
         */
        loadData: public_loadData,

        /**
         * zoneContains(zone, lat, lon)
         *
         * Return whether the time zone name (e.g.,
         * "America/Los_Angeles") contains the point at the given
         * latitude and longitude or has that point on its boundary.
         * Supports the "uninhabited" zone, but not null.
         */
        zoneContains: public_zoneContains,

        /**
         * zoneAt(lat, lon)
         *
         * Return the time zone name (e.g., "America/Los_Angeles") at
         * the given latitude and longitude, "uninhabited" for land
         * areas for which no time zone is known for the location (e.g.,
         * Antarctica), or null for water areas.  If the location is
         * exactly on a time zone boundary, which time zone will be
         * returned is undefined, but one of them will be.
         */
        zoneAt: public_zoneAt,

        /**
         * polygonsFor(zone_array)
         *
         * Get the set of polygons for a set of timezones.  Each name in
         * zone_array should be an tz database timezone name.  This API
         * will return an array of non-adjacent polygons, where each
         * polygon is an array of points (the first and last being the
         * same), and each point is an array of [lon, lat] as floats.
         */
        polygonsFor: public_polygonsFor,
    };
})();
<|endoftext|>


<commit_before>/**
 * This code is mostly from the old Etherpad. Please help us to comment this code.
 * This helps other people to understand this code better and helps them to improve it.
 * TL;DR COMMENTS ON THIS FILE ARE HIGHLY APPRECIATED
 */

/**
 * Copyright 2009 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// requires: top
// requires: plugins
// requires: undefined

Ace2Editor.registry = {
  nextId: 1
};

var hooks = require('./pluginfw/hooks');
var _ = require('./underscore');

function Ace2Editor()
{
  var ace2 = Ace2Editor;

  var editor = {};
  var info = {
    editor: editor,
    id: (ace2.registry.nextId++)
  };
  var loaded = false;

  var actionsPendingInit = [];

  function pendingInit(func, optDoNow)
  {
    return function()
    {
      var that = this;
      var args = arguments;
      var action = function()
      {
        func.apply(that, args);
      }
      if (optDoNow)
      {
        optDoNow.apply(that, args);
      }
      if (loaded)
      {
        action();
      }
      else
      {
        actionsPendingInit.push(action);
      }
    };
  }

  function doActionsPendingInit()
  {
    _.each(actionsPendingInit, function(fn,i){
      fn()
    });
    actionsPendingInit = [];
  }

  ace2.registry[info.id] = info;

  // The following functions (prefixed by 'ace_')  are exposed by editor, but
  // execution is delayed until init is complete
  var aceFunctionsPendingInit = ['importText', 'importAText', 'focus',
  'setEditable', 'getFormattedCode', 'setOnKeyPress', 'setOnKeyDown',
  'setNotifyDirty', 'setProperty', 'setBaseText', 'setBaseAttributedText',
  'applyChangesToBase', 'applyPreparedChangesetToBase',
  'setUserChangeNotificationCallback', 'setAuthorInfo',
  'setAuthorSelectionRange', 'callWithAce', 'execCommand', 'replaceRange'];

  _.each(aceFunctionsPendingInit, function(fnName,i){
    var prefix = 'ace_';
    var name = prefix + fnName;
    editor[fnName] = pendingInit(function(){
      info[prefix + fnName].apply(this, arguments);
    });
  });

  editor.exportText = function()
  {
    if (!loaded) return "(awaiting init)\n";
    return info.ace_exportText();
  };

  editor.getFrame = function()
  {
    return info.frame || null;
  };

  editor.getDebugProperty = function(prop)
  {
    return info.ace_getDebugProperty(prop);
  };

  // prepareUserChangeset:
  // Returns null if no new changes or ACE not ready.  Otherwise, bundles up all user changes
  // to the latest base text into a Changeset, which is returned (as a string if encodeAsString).
  // If this method returns a truthy value, then applyPreparedChangesetToBase can be called
  // at some later point to consider these changes part of the base, after which prepareUserChangeset
  // must be called again before applyPreparedChangesetToBase.  Multiple consecutive calls
  // to prepareUserChangeset will return an updated changeset that takes into account the
  // latest user changes, and modify the changeset to be applied by applyPreparedChangesetToBase
  // accordingly.
  editor.prepareUserChangeset = function()
  {
    if (!loaded) return null;
    return info.ace_prepareUserChangeset();
  };

  editor.getUnhandledErrors = function()
  {
    if (!loaded) return [];
    // returns array of {error: <browser Error object>, time: +new Date()}
    return info.ace_getUnhandledErrors();
  };

  function sortFilesByEmbeded(files) {
    var embededFiles = [];
    var remoteFiles = [];

    if (Ace2Editor.EMBEDED) {
      for (var i = 0, ii = files.length; i < ii; i++) {
        var file = files[i];
        if (Object.prototype.hasOwnProperty.call(Ace2Editor.EMBEDED, file)) {
          embededFiles.push(file);
        } else {
          remoteFiles.push(file);
        }
      }
    } else {
      remoteFiles = files;
    }

    return {embeded: embededFiles, remote: remoteFiles};
  }
  function pushRequireScriptTo(buffer) {
    var KERNEL_SOURCE = '../static/js/require-kernel.js';
    var KERNEL_BOOT = '\
require.setRootURI("../javascripts/src");\n\
require.setLibraryURI("../javascripts/lib");\n\
require.setGlobalKeyPath("require");\n\
';
    if (Ace2Editor.EMBEDED && Ace2Editor.EMBEDED[KERNEL_SOURCE]) {
      buffer.push('');

      hooks.callAll("aceInitInnerdocbodyHead", {
        iframeHTML: iframeHTML
      });

      // calls to these functions ($$INCLUDE_...)  are replaced when this file is processed
      // and compressed, putting the compressed code from the named file directly into the
      // source here.
      // these lines must conform to a specific format because they are passed by the build script:
      var includedCSS = [];
      var $$INCLUDE_CSS = function(filename) {includedCSS.push(filename)};
      $$INCLUDE_CSS("../static/css/iframe_editor.css");
      $$INCLUDE_CSS("../static/css/pad.css");
      $$INCLUDE_CSS("../static/custom/pad.css");

      var additionalCSS = _(hooks.callAll("aceEditorCSS")).map(function(path){ return '../static/plugins/' + path });
      includedCSS = includedCSS.concat(additionalCSS);

      pushStyleTagsFor(iframeHTML, includedCSS);

      var includedJS = [];
      var $$INCLUDE_JS = function(filename) {includedJS.push(filename)};
      pushRequireScriptTo(iframeHTML);
      // Inject my plugins into my child.
      iframeHTML.push('\
\
');
      pushScriptsTo(iframeHTML);

      iframeHTML.push('');
      iframeHTML.push(' ');

      // Expose myself to global for my child frame.
      var thisFunctionsName = "ChildAccessibleAce2Editor";
      (function () {return this}())[thisFunctionsName] = Ace2Editor;

      var outerScript = 'editorId = "' + info.id + '"; editorInfo = parent.' + thisFunctionsName + '.registry[editorId]; ' + 'window.onload = function() ' + '{ window.onload = null; setTimeout' + '(function() ' + '{ var iframe = document.createElement("IFRAME"); iframe.name = "ace_inner";' + 'iframe.scrolling = "no"; var outerdocbody = document.getElementById("outerdocbody"); ' + 'iframe.frameBorder = 0; iframe.allowTransparency = true; ' + // for IE
      'outerdocbody.insertBefore(iframe, outerdocbody.firstChild); ' + 'iframe.ace_outerWin = window; ' + 'readyFunc = function() { editorInfo.onEditorReady(); readyFunc = null; editorInfo = null; }; ' + 'var doc = iframe.contentWindow.document; doc.open(); var text = (' + JSON.stringify(iframeHTML.join('\n')) + ');doc.write(text); doc.close(); ' + '}, 0); }';

      var outerHTML = [doctype, '']

      var includedCSS = [];
      var $$INCLUDE_CSS = function(filename) {includedCSS.push(filename)};
      $$INCLUDE_CSS("../static/css/iframe_editor.css");
      $$INCLUDE_CSS("../static/css/pad.css");
      $$INCLUDE_CSS("../static/custom/pad.css");

      var additionalCSS = _(hooks.callAll("aceEditorCSS")).map(function(path){ return '../static/plugins/' + path });
      includedCSS = includedCSS.concat(additionalCSS);

      pushStyleTagsFor(outerHTML, includedCSS);

      // bizarrely, in FF2, a file with no "external" dependencies won't finish loading properly
      // (throbs busy while typing)
      outerHTML.push('<link rel="stylesheet" type="text/css" href="data:text/css,"/>', '\x3cscript>\n', outerScript.replace(/<\//g, '<\\/'), '\n\x3c/script>', '

x

');

      var outerFrame = document.createElement("IFRAME");
      outerFrame.name = "ace_outer";
      outerFrame.frameBorder = 0; // for IE
      info.frame = outerFrame;
      document.getElementById(containerId).appendChild(outerFrame);

      var editorDocument = outerFrame.contentWindow.document;

      editorDocument.open();
      editorDocument.write(outerHTML.join(''));
      editorDocument.close();
    })();
  };

  return editor;
}

exports.Ace2Editor = Ace2Editor;
<commit_msg>Remove unused line.<commit_after>/**
 * This code is mostly from the old Etherpad. Please help us to comment this code.
 * This helps other people to understand this code better and helps them to improve it.
 * TL;DR COMMENTS ON THIS FILE ARE HIGHLY APPRECIATED
 */

/**
 * Copyright 2009 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// requires: top
// requires: plugins
// requires: undefined

Ace2Editor.registry = {
  nextId: 1
};

var hooks = require('./pluginfw/hooks');
var _ = require('./underscore');

function Ace2Editor()
{
  var ace2 = Ace2Editor;

  var editor = {};
  var info = {
    editor: editor,
    id: (ace2.registry.nextId++)
  };
  var loaded = false;

  var actionsPendingInit = [];

  function pendingInit(func, optDoNow)
  {
    return function()
    {
      var that = this;
      var args = arguments;
      var action = function()
      {
        func.apply(that, args);
      }
      if (optDoNow)
      {
        optDoNow.apply(that, args);
      }
      if (loaded)
      {
        action();
      }
      else
      {
        actionsPendingInit.push(action);
      }
    };
  }

  function doActionsPendingInit()
  {
    _.each(actionsPendingInit, function(fn,i){
      fn()
    });
    actionsPendingInit = [];
  }

  ace2.registry[info.id] = info;

  // The following functions (prefixed by 'ace_')  are exposed by editor, but
  // execution is delayed until init is complete
  var aceFunctionsPendingInit = ['importText', 'importAText', 'focus',
  'setEditable', 'getFormattedCode', 'setOnKeyPress', 'setOnKeyDown',
  'setNotifyDirty', 'setProperty', 'setBaseText', 'setBaseAttributedText',
  'applyChangesToBase', 'applyPreparedChangesetToBase',
  'setUserChangeNotificationCallback', 'setAuthorInfo',
  'setAuthorSelectionRange', 'callWithAce', 'execCommand', 'replaceRange'];

  _.each(aceFunctionsPendingInit, function(fnName,i){
    var prefix = 'ace_';
    var name = prefix + fnName;
    editor[fnName] = pendingInit(function(){
      info[prefix + fnName].apply(this, arguments);
    });
  });

  editor.exportText = function()
  {
    if (!loaded) return "(awaiting init)\n";
    return info.ace_exportText();
  };

  editor.getFrame = function()
  {
    return info.frame || null;
  };

  editor.getDebugProperty = function(prop)
  {
    return info.ace_getDebugProperty(prop);
  };

  // prepareUserChangeset:
  // Returns null if no new changes or ACE not ready.  Otherwise, bundles up all user changes
  // to the latest base text into a Changeset, which is returned (as a string if encodeAsString).
  // If this method returns a truthy value, then applyPreparedChangesetToBase can be called
  // at some later point to consider these changes part of the base, after which prepareUserChangeset
  // must be called again before applyPreparedChangesetToBase.  Multiple consecutive calls
  // to prepareUserChangeset will return an updated changeset that takes into account the
  // latest user changes, and modify the changeset to be applied by applyPreparedChangesetToBase
  // accordingly.
  editor.prepareUserChangeset = function()
  {
    if (!loaded) return null;
    return info.ace_prepareUserChangeset();
  };

  editor.getUnhandledErrors = function()
  {
    if (!loaded) return [];
    // returns array of {error: <browser Error object>, time: +new Date()}
    return info.ace_getUnhandledErrors();
  };

  function sortFilesByEmbeded(files) {
    var embededFiles = [];
    var remoteFiles = [];

    if (Ace2Editor.EMBEDED) {
      for (var i = 0, ii = files.length; i < ii; i++) {
        var file = files[i];
        if (Object.prototype.hasOwnProperty.call(Ace2Editor.EMBEDED, file)) {
          embededFiles.push(file);
        } else {
          remoteFiles.push(file);
        }
      }
    } else {
      remoteFiles = files;
    }

    return {embeded: embededFiles, remote: remoteFiles};
  }
  function pushRequireScriptTo(buffer) {
    var KERNEL_SOURCE = '../static/js/require-kernel.js';
    var KERNEL_BOOT = '\
require.setRootURI("../javascripts/src");\n\
require.setLibraryURI("../javascripts/lib");\n\
require.setGlobalKeyPath("require");\n\
';
    if (Ace2Editor.EMBEDED && Ace2Editor.EMBEDED[KERNEL_SOURCE]) {
      buffer.push('');

      hooks.callAll("aceInitInnerdocbodyHead", {
        iframeHTML: iframeHTML
      });

      // calls to these functions ($$INCLUDE_...)  are replaced when this file is processed
      // and compressed, putting the compressed code from the named file directly into the
      // source here.
      // these lines must conform to a specific format because they are passed by the build script:
      var includedCSS = [];
      var $$INCLUDE_CSS = function(filename) {includedCSS.push(filename)};
      $$INCLUDE_CSS("../static/css/iframe_editor.css");
      $$INCLUDE_CSS("../static/css/pad.css");
      $$INCLUDE_CSS("../static/custom/pad.css");

      var additionalCSS = _(hooks.callAll("aceEditorCSS")).map(function(path){ return '../static/plugins/' + path });
      includedCSS = includedCSS.concat(additionalCSS);

      pushStyleTagsFor(iframeHTML, includedCSS);

      var includedJS = [];
      var $$INCLUDE_JS = function(filename) {includedJS.push(filename)};
      pushRequireScriptTo(iframeHTML);
      // Inject my plugins into my child.
      iframeHTML.push('\
\
');
      pushScriptsTo(iframeHTML);

      iframeHTML.push('');
      iframeHTML.push(' ');

      // Expose myself to global for my child frame.
      var thisFunctionsName = "ChildAccessibleAce2Editor";
      (function () {return this}())[thisFunctionsName] = Ace2Editor;

      var outerScript = 'editorId = "' + info.id + '"; editorInfo = parent.' + thisFunctionsName + '.registry[editorId]; ' + 'window.onload = function() ' + '{ window.onload = null; setTimeout' + '(function() ' + '{ var iframe = document.createElement("IFRAME"); iframe.name = "ace_inner";' + 'iframe.scrolling = "no"; var outerdocbody = document.getElementById("outerdocbody"); ' + 'iframe.frameBorder = 0; iframe.allowTransparency = true; ' + // for IE
      'outerdocbody.insertBefore(iframe, outerdocbody.firstChild); ' + 'iframe.ace_outerWin = window; ' + 'readyFunc = function() { editorInfo.onEditorReady(); readyFunc = null; editorInfo = null; }; ' + 'var doc = iframe.contentWindow.document; doc.open(); var text = (' + JSON.stringify(iframeHTML.join('\n')) + ');doc.write(text); doc.close(); ' + '}, 0); }';

      var outerHTML = [doctype, '']

      var includedCSS = [];
      var $$INCLUDE_CSS = function(filename) {includedCSS.push(filename)};
      $$INCLUDE_CSS("../static/css/iframe_editor.css");
      $$INCLUDE_CSS("../static/css/pad.css");
      $$INCLUDE_CSS("../static/custom/pad.css");

      var additionalCSS = _(hooks.callAll("aceEditorCSS")).map(function(path){ return '../static/plugins/' + path });
      includedCSS = includedCSS.concat(additionalCSS);

      pushStyleTagsFor(outerHTML, includedCSS);

      // bizarrely, in FF2, a file with no "external" dependencies won't finish loading properly
      // (throbs busy while typing)
      outerHTML.push('<link rel="stylesheet" type="text/css" href="data:text/css,"/>', '\x3cscript>\n', outerScript.replace(/<\//g, '<\\/'), '\n\x3c/script>', '

x

');

      var outerFrame = document.createElement("IFRAME");
      outerFrame.name = "ace_outer";
      outerFrame.frameBorder = 0; // for IE
      info.frame = outerFrame;
      document.getElementById(containerId).appendChild(outerFrame);

      var editorDocument = outerFrame.contentWindow.document;

      editorDocument.open();
      editorDocument.write(outerHTML.join(''));
      editorDocument.close();
    })();
  };

  return editor;
}

exports.Ace2Editor = Ace2Editor;
<|endoftext|>


<commit_before>/*
* http://addyosmani.com/blog/essential-js-namespacing/
*/
(function(app) {
  'use strict';
  /*global FB, Foundation*/

  app.menuActiveFeatureClicked = function(activeFeature) {
    /*
    http://stackoverflow.com/a/6944834
    https://css-tricks.com/snippets/javascript/get-url-and-url-parts-in-javascript/
    */
    var pathArray = window.location.pathname.split('/');
    var lastLevelLocation = pathArray[pathArray.length - 1];
    if (lastLevelLocation !== activeFeature && lastLevelLocation !== '') {
      // We are in a subpage, redirect to main page of the active feature.
      window.location.href = '/' + activeFeature;
    }
    if (typeof Foundation !== undefined) {
      Foundation.libs.topbar.toggle();
    }
  };

  app.facebookShareBlog = function(event, lead, path, title, pictureUrl) {
    event.preventDefault();
    FB.ui(
    {
      method: 'share',
      href: 'https://filosofianakatemia.fi/blogi/' + path,
      picture: pictureUrl,
      title: title,
      description: lead
    },
    function(/*response*/) {
      return null;
    });
  };

  app.twitterShareBlog = function(event, path, title) {
    event.preventDefault();
    // http://gpiot.com/blog/elegant-twitter-share-button-and-dialog-with-jquery/
    var sharelUrl = 'https://filosofianakatemia.fi/blogi/' + path;
    var shareVia = 'filosofianakate';
    var url = 'https://twitter.com/share?via=' + shareVia + '&url=' + sharelUrl + '&text=' + title;
    window.open(url, '_blank', 'height=420, width=550');
  };

  app.linkedInShareBlog = function(event, lead, path, title) {
    event.preventDefault();
    var sharelUrl = 'https://filosofianakatemia.fi/blogi/' + path;
    var url = 'https://www.linkedin.com/shareArticle?mini=true&url=' + sharelUrl + '&title=' + title +
    '&summary=' + lead + '&source=Filosofian%20Akatemia';
    window.open(url, '_blank', 'height=420, width=550');
  };

  function httpGetAsync(theUrl, callback)
  {
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.onreadystatechange = function() {
      if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
        callback(xmlHttp.responseText);
    };
    xmlHttp.open('GET', theUrl, true); // true for asynchronous
    xmlHttp.send(null);
  }

  app.getShareCount = function(path) {
    // http://stackoverflow.com/a/19119580
    var totalCount = 0;
    var totalCountElement = document.getElementById('total-shares_count');
    var sharelUrl = 'https://filosofianakatemia.fi/blogi/' + path;

    var facebookUrl = 'https://api.facebook.com/method/links.getStats?urls=' + sharelUrl + '&format=json';
    httpGetAsync(facebookUrl, facebookCount);
    function facebookCount(response) {
      totalCount += JSON.parse(response)[0].share_count;
      if (totalCountElement) {
        totalCountElement.innerHTML = totalCount;
      }
    }

    var twitterUrl = 'https://cdn.api.twitter.com/1/urls/count.json?url=' + sharelUrl;
    // Remove this for now because of No 'Access-Control-Allow-Origin' header
    //httpGetAsync(twitterUrl, twitterCount);
    function twitterCount(response) {
      totalCount += JSON.parse(response).count;
      if (totalCountElement) {
        totalCountElement.innerHTML = totalCount;
      }
    }

    var linkedInUrl = 'https://www.linkedin.com/countserv/count/share?url=' + sharelUrl + '&format=json';
    // Remove this for now because of No 'Access-Control-Allow-Origin' header
    //httpGetAsync(linkedInUrl, linkedInCount);
    function linkedInCount(response) {
      totalCount += JSON.parse(response).count;
      if (totalCountElement) {
        totalCountElement.innerHTML = totalCount;
      }
    }
  };

})(window.app = window.app || {});
<commit_msg>Added experimental URL encoding to tweet and linkedin buttons.<commit_after>/*
* http://addyosmani.com/blog/essential-js-namespacing/
*/
(function(app) {
  'use strict';
  /*global FB, Foundation*/

  app.menuActiveFeatureClicked = function(activeFeature) {
    /*
    http://stackoverflow.com/a/6944834
    https://css-tricks.com/snippets/javascript/get-url-and-url-parts-in-javascript/
    */
    var pathArray = window.location.pathname.split('/');
    var lastLevelLocation = pathArray[pathArray.length - 1];
    if (lastLevelLocation !== activeFeature && lastLevelLocation !== '') {
      // We are in a subpage, redirect to main page of the active feature.
      window.location.href = '/' + activeFeature;
    }
    if (typeof Foundation !== undefined) {
      Foundation.libs.topbar.toggle();
    }
  };

  app.facebookShareBlog = function(event, lead, path, title, pictureUrl) {
    event.preventDefault();
    FB.ui(
    {
      method: 'share',
      href: 'https://filosofianakatemia.fi/blogi/' + path,
      picture: pictureUrl,
      title: title,
      description: lead
    },
    function(/*response*/) {
      return null;
    });
  };

  app.twitterShareBlog = function(event, path, title) {
    event.preventDefault();
    // http://gpiot.com/blog/elegant-twitter-share-button-and-dialog-with-jquery/
    var sharelUrl = 'https://filosofianakatemia.fi/blogi/' + path;
    var shareVia = 'filosofianakate';
    var url = 'https://twitter.com/share?via=' + shareVia + '&url=' + encodeURIComponent(sharelUrl) + '&text=' + encodeURIComponent(title);
    window.open(url, '_blank', 'height=420, width=550');
  };

  app.linkedInShareBlog = function(event, lead, path, title) {
    event.preventDefault();
    var sharelUrl = 'https://filosofianakatemia.fi/blogi/' + path;
    var url = 'https://www.linkedin.com/shareArticle?mini=true&url=' + encodeURIComponent(sharelUrl) + '&title=' + encodeURIComponent(title) +
    '&summary=' + encodeURIComponent(lead) + '&source=Filosofian%20Akatemia';
    window.open(url, '_blank', 'height=420, width=550');
  };

  function httpGetAsync(theUrl, callback)
  {
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.onreadystatechange = function() {
      if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
        callback(xmlHttp.responseText);
    };
    xmlHttp.open('GET', theUrl, true); // true for asynchronous
    xmlHttp.send(null);
  }

  app.getShareCount = function(path) {
    // http://stackoverflow.com/a/19119580
    var totalCount = 0;
    var totalCountElement = document.getElementById('total-shares_count');
    var sharelUrl = 'https://filosofianakatemia.fi/blogi/' + path;

    var facebookUrl = 'https://api.facebook.com/method/links.getStats?urls=' + sharelUrl + '&format=json';
    httpGetAsync(facebookUrl, facebookCount);
    function facebookCount(response) {
      totalCount += JSON.parse(response)[0].share_count;
      if (totalCountElement) {
        totalCountElement.innerHTML = totalCount;
      }
    }

    var twitterUrl = 'https://cdn.api.twitter.com/1/urls/count.json?url=' + sharelUrl;
    // Remove this for now because of No 'Access-Control-Allow-Origin' header
    //httpGetAsync(twitterUrl, twitterCount);
    function twitterCount(response) {
      totalCount += JSON.parse(response).count;
      if (totalCountElement) {
        totalCountElement.innerHTML = totalCount;
      }
    }

    var linkedInUrl = 'https://www.linkedin.com/countserv/count/share?url=' + sharelUrl + '&format=json';
    // Remove this for now because of No 'Access-Control-Allow-Origin' header
    //httpGetAsync(linkedInUrl, linkedInCount);
    function linkedInCount(response) {
      totalCount += JSON.parse(response).count;
      if (totalCountElement) {
        totalCountElement.innerHTML = totalCount;
      }
    }
  };

})(window.app = window.app || {});
<|endoftext|>


<commit_before>var
    /**
     * Base class used to fully read a stream
     *
     * @class AbstractStreamReader
     * @abstract
     * @private
     */
    AbstractStreamReader = _gpfDefine("AbstractStreamReader", {

        "+": {

            constructor: function (scope, eventsHandler) {
                this._scope = scope;
                this._eventsHandler = eventsHandler;
            },

            read: function (stream) {
                stream.read(this._readSize, this.callback.bind(this));
            }

        },

        "#": {

            _readSize: 0,

            _consolidateBuffer: function () {
                throw gpf.Error.abstract();
            },

            _addBuffer: function (buffer) {
                _gpfIgnore(buffer);
                throw gpf.Error.abstract();
            }
        },

        "-": {

            _scope: null,
            _eventsHandler: null,

            callback: function (event) {
                var
                    type = event.type(),
                    stream = event.scope();
                if (type === _gpfI.IReadableStream.EVENT_END_OF_STREAM) {
                    _gpfEventsFire.call(this._scope, _gpfI.IReadableStream.EVENT_DATA,
                        {
                            buffer: this._consolidateBuffer()
                        },
                        this._eventsHandler
                    );

                } else if (type === _gpfI.IReadableStream.EVENT_ERROR) {
                    // Forward the event
                    _gpfEventsFire.call(this._scope, event, this._eventsHandler);

                } else {
                    this._addBuffer(event.get("buffer"));
                    this.read(stream);
                }
            }

        }

    }),

    StreamReader = _gpfDefine("StreamReader", AbstractStreamReader, {

        "+": {

            constructor: function (scope, eventsHandler, concatMethod) {
                this._super(scope, eventsHandler);
                this._concatMethod = concatMethod;
            }

        },

        "#": {

            _consolidateBuffer: function () {
                return this._concatMethod(this._buffer);
            },

            _addBuffer: function (buffer) {
                this._buffer = this._concatMethod(this._buffer, buffer);
            }
        },

        "-": {

            _buffer: undefined,
            _concatMethod: null

        }

    }),

    B64StreamReader = _gpfDefine("B64StreamReader", AbstractStreamReader, {

        "+": {

            constructor: function (scope, eventsHandler) {
                this._super(scope, eventsHandler);
                this._buffer = [];
            }

        },

        "#": {

            _readSize: 6,

            _consolidateBuffer: function () {
                return this._buffer.join("");
            },

            _addBuffer: function (buffer) {
                this._buffer.push(gpf.bin.toBase64(buffer[0]));
            }

        },

        "-": {

            _buffer: []

        }

    });

/**
 * Read the whole stream and concat the buffers using the provided handler
 *
 * @param {gpf.interfaces.ITextStream} stream
 * @param {Function} concatMethod
 * @param {gpf.events.Handler} eventsHandler
 *
 * @forwardThis
 *
 * @event data finished reading the stream, the buffer is provided
 * @eventParam {Array|String} buffer
 */
gpf.stream.readAll = function (stream, concatMethod, eventsHandler) {
    stream = gpf.interfaces.query(stream, _gpfI.IReadableStream,  true);
    (new StreamReader(this, eventsHandler, concatMethod)).read(stream);
};

/**
 * Read the whole stream and returns a base64 string
 *
 * @param {gpf.interfaces.ITextStream} stream
 * @param {gpf.events.Handler} eventsHandler
 *
 * @forwardThis
 *
 * @event data finished reading the stream, the buffer is provided
 * @eventParam {Array|String} buffer
 */
gpf.stream.readAllAsB64 = function (stream, eventsHandler) {
    stream = new gpf.stream.BitReader(stream);
    (new B64StreamReader(this, eventsHandler)).read(stream);
};
<commit_msg>Prefix jsdoc extensions with gpf<commit_after>var
    /**
     * Base class used to fully read a stream
     *
     * @class AbstractStreamReader
     * @abstract
     * @private
     */
    AbstractStreamReader = _gpfDefine("AbstractStreamReader", {

        "+": {

            constructor: function (scope, eventsHandler) {
                this._scope = scope;
                this._eventsHandler = eventsHandler;
            },

            read: function (stream) {
                stream.read(this._readSize, this.callback.bind(this));
            }

        },

        "#": {

            _readSize: 0,

            _consolidateBuffer: function () {
                throw gpf.Error.abstract();
            },

            _addBuffer: function (buffer) {
                _gpfIgnore(buffer);
                throw gpf.Error.abstract();
            }
        },

        "-": {

            _scope: null,
            _eventsHandler: null,

            callback: function (event) {
                var
                    type = event.type(),
                    stream = event.scope();
                if (type === _gpfI.IReadableStream.EVENT_END_OF_STREAM) {
                    _gpfEventsFire.call(this._scope, _gpfI.IReadableStream.EVENT_DATA,
                        {
                            buffer: this._consolidateBuffer()
                        },
                        this._eventsHandler
                    );

                } else if (type === _gpfI.IReadableStream.EVENT_ERROR) {
                    // Forward the event
                    _gpfEventsFire.call(this._scope, event, this._eventsHandler);

                } else {
                    this._addBuffer(event.get("buffer"));
                    this.read(stream);
                }
            }

        }

    }),

    StreamReader = _gpfDefine("StreamReader", AbstractStreamReader, {

        "+": {

            constructor: function (scope, eventsHandler, concatMethod) {
                this._super(scope, eventsHandler);
                this._concatMethod = concatMethod;
            }

        },

        "#": {

            _consolidateBuffer: function () {
                return this._concatMethod(this._buffer);
            },

            _addBuffer: function (buffer) {
                this._buffer = this._concatMethod(this._buffer, buffer);
            }
        },

        "-": {

            _buffer: undefined,
            _concatMethod: null

        }

    }),

    B64StreamReader = _gpfDefine("B64StreamReader", AbstractStreamReader, {

        "+": {

            constructor: function (scope, eventsHandler) {
                this._super(scope, eventsHandler);
                this._buffer = [];
            }

        },

        "#": {

            _readSize: 6,

            _consolidateBuffer: function () {
                return this._buffer.join("");
            },

            _addBuffer: function (buffer) {
                this._buffer.push(gpf.bin.toBase64(buffer[0]));
            }

        },

        "-": {

            _buffer: []

        }

    });

/**
 * Read the whole stream and concat the buffers using the provided handler
 *
 * @param {gpf.interfaces.ITextStream} stream
 * @param {Function} concatMethod
 * @param {gpf.events.Handler} eventsHandler
 *
 * @gpf:forwardThis
 *
 * @event data finished reading the stream, the buffer is provided
 * @eventParam {Array|String} buffer
 */
gpf.stream.readAll = function (stream, concatMethod, eventsHandler) {
    stream = gpf.interfaces.query(stream, _gpfI.IReadableStream,  true);
    (new StreamReader(this, eventsHandler, concatMethod)).read(stream);
};

/**
 * Read the whole stream and returns a base64 string
 *
 * @param {gpf.interfaces.ITextStream} stream
 * @param {gpf.events.Handler} eventsHandler
 *
 * @gpf:forwardThis
 *
 * @event data finished reading the stream, the buffer is provided
 * @eventParam {Array|String} buffer
 */
gpf.stream.readAllAsB64 = function (stream, eventsHandler) {
    stream = new gpf.stream.BitReader(stream);
    (new B64StreamReader(this, eventsHandler)).read(stream);
};
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { debounce } from 'lodash';
import cuid from 'cuid';
import { Switch, Route } from 'react-router-dom';
import { hasToken } from 'common/utils/auth';

import { breakpoints } from 'common/styles/media';
import { selectLocationPath } from 'common/selectors';

import Aux from 'common/components/Aux';
import Element from 'common/components/Element';
import QuizSummaryHeader from 'features/quiz/QuizSummary/QuizSummaryHeader';
import LogoLink from 'common/components/LogoLink';
import Hamburger from './Hamburger';
import OffCanvasMenu from './OffCanvasMenu';

import { Header, Nav, NavLinks } from './styles';
import NavLink from './NavLink';

const PRIMARY_LINKS = [
  {
    name: 'lessons',
    route: '/lessons',
    hasCount: true,
  },
  {
    name: 'reviews',
    route: '/reviews',
    hasCount: true,
  },
];
const SECONDARY_LINKS = [
  { name: 'vocabulary', route: '/vocabulary' },
  { name: 'settings', route: '/settings' },
  { name: 'about', route: '/about' },
  { name: 'contact', route: '/contact' },
  { name: 'logout', route: '/logout' },
];

export class SiteHeader extends React.Component {
  static propTypes = {
    locationPath: PropTypes.string.isRequired,
  };

  state = {
    offCanvasMenuActive: false,
  };

  componentDidMount() {
    this.handleResize();
    window.addEventListener('resize', this.handleResize);
  }

  componentDidUpdate(prevProps) {
    if (this.props.locationPath !== prevProps.locationPath) {
      this.hideOffCanvasMenu();
    }
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.handleResize);
    this.hideOffCanvasMenu();
  }

  handleResize = debounce(() => {
    this.hideOffCanvasMenu();
    this.setState(() => ({
      isWideViewport: window.innerWidth > breakpoints.md,
    }));
  }, 150);

  hideOffCanvasMenu = () => {
    this.setState({ offCanvasMenuActive: false });
    document.body.classList.remove('offCanvasMenu--isOpen');
  };

  showOffCanvasMenu = () => {
    this.setState({ offCanvasMenuActive: true });
    document.body.classList.add('offCanvasMenu--isOpen');
  };

  renderMenu = (links) => (
    <NavLinks>
      {links.map((link) => <NavLink key={cuid()} isOffCanvas={false} {...link} />)}
    </NavLinks>
  );

  render() {
    const { isWideViewport, offCanvasMenuActive } = this.state;
    if (isWideViewport === undefined) {
      return null;
    }

    return (
      hasToken() && (
        <Header
          innerRef={(node) => {
            this.HeaderRef = node;
          }}
        >
          <Switch>
            <Route exact path="/:category(lessons|reviews)/session" />
            <Route exact path="/maintenance" />
            <Route
              render={() => (
                <Aux>
                  <Nav>
                    <LogoLink />
                    <Switch>
                      <Route path="/:category(lessons|reviews)" component={QuizSummaryHeader} />
                      <Route
                        render={() => (
                          <Aux>
                            <Element flexRow flex="999 1 auto" justifyContent="space-between">
                              {this.renderMenu(PRIMARY_LINKS)}
                              {isWideViewport && this.renderMenu(SECONDARY_LINKS)}
                            </Element>
                            {!isWideViewport && <Hamburger onToggle={this.showOffCanvasMenu} />}
                          </Aux>
                        )}
                      />
                    </Switch>
                  </Nav>
                  <OffCanvasMenu
                    links={SECONDARY_LINKS}
                    isVisible={offCanvasMenuActive}
                    onClose={this.hideOffCanvasMenu}
                  />
                </Aux>
              )}
            />
          </Switch>
        </Header>
      )
    );
  }
}

const mapStateToProps = createStructuredSelector({
  locationPath: selectLocationPath,
});

export default connect(mapStateToProps)(SiteHeader);
<commit_msg>fix: out of sync location in header when using browser back/forward<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { debounce } from 'lodash';
import cuid from 'cuid';
import { Switch, Route } from 'react-router-dom';
import { hasToken } from 'common/utils/auth';

import { breakpoints } from 'common/styles/media';
import { selectLocationPath } from 'common/selectors';

import Aux from 'common/components/Aux';
import Element from 'common/components/Element';
import QuizSummaryHeader from 'features/quiz/QuizSummary/QuizSummaryHeader';
import LogoLink from 'common/components/LogoLink';
import Hamburger from './Hamburger';
import OffCanvasMenu from './OffCanvasMenu';

import { Header, Nav, NavLinks } from './styles';
import NavLink from './NavLink';

const ConnectedSwitch = connect((state) => ({ location: state.router.location }))(Switch);

const PRIMARY_LINKS = [
  {
    name: 'lessons',
    route: '/lessons',
    hasCount: true,
  },
  {
    name: 'reviews',
    route: '/reviews',
    hasCount: true,
  },
];
const SECONDARY_LINKS = [
  { name: 'vocabulary', route: '/vocabulary' },
  { name: 'settings', route: '/settings' },
  { name: 'about', route: '/about' },
  { name: 'contact', route: '/contact' },
  { name: 'logout', route: '/logout' },
];

export class SiteHeader extends React.Component {
  static propTypes = {
    locationPath: PropTypes.string.isRequired,
  };

  state = {
    offCanvasMenuActive: false,
  };

  componentDidMount() {
    this.handleResize();
    window.addEventListener('resize', this.handleResize);
  }

  componentDidUpdate(prevProps) {
    if (this.props.locationPath !== prevProps.locationPath) {
      this.hideOffCanvasMenu();
    }
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.handleResize);
    this.hideOffCanvasMenu();
  }

  handleResize = debounce(() => {
    this.hideOffCanvasMenu();
    this.setState(() => ({
      isWideViewport: window.innerWidth > breakpoints.md,
    }));
  }, 150);

  hideOffCanvasMenu = () => {
    this.setState({ offCanvasMenuActive: false });
    document.body.classList.remove('offCanvasMenu--isOpen');
  };

  showOffCanvasMenu = () => {
    this.setState({ offCanvasMenuActive: true });
    document.body.classList.add('offCanvasMenu--isOpen');
  };

  renderMenu = (links) => (
    <NavLinks>
      {links.map((link) => <NavLink key={cuid()} isOffCanvas={false} {...link} />)}
    </NavLinks>
  );

  render() {
    const { isWideViewport, offCanvasMenuActive } = this.state;
    if (isWideViewport === undefined) {
      return null;
    }

    return (
      hasToken() && (
        <Header
          innerRef={(node) => {
            this.HeaderRef = node;
          }}
        >
          <ConnectedSwitch>
            <Route exact path="/:category(lessons|reviews)/session" />
            <Route exact path="/maintenance" />
            <Route
              render={() => (
                <Aux>
                  <Nav>
                    <LogoLink />
                    <Switch>
                      <Route path="/:category(lessons|reviews)" component={QuizSummaryHeader} />
                      <Route
                        render={() => (
                          <Aux>
                            <Element flexRow flex="999 1 auto" justifyContent="space-between">
                              {this.renderMenu(PRIMARY_LINKS)}
                              {isWideViewport && this.renderMenu(SECONDARY_LINKS)}
                            </Element>
                            {!isWideViewport && <Hamburger onToggle={this.showOffCanvasMenu} />}
                          </Aux>
                        )}
                      />
                    </Switch>
                  </Nav>
                  <OffCanvasMenu
                    links={SECONDARY_LINKS}
                    isVisible={offCanvasMenuActive}
                    onClose={this.hideOffCanvasMenu}
                  />
                </Aux>
              )}
            />
          </ConnectedSwitch>
        </Header>
      )
    );
  }
}

const mapStateToProps = createStructuredSelector({
  locationPath: selectLocationPath,
});

export default connect(mapStateToProps)(SiteHeader);
<|endoftext|>