<commit_before>var partial = require('lodash-node/modern/functions/partial');
var util = require('./util');
var board = require('./board');
var drag = require('./drag');
var anim = require('./anim');

function pieceClass(p) {
  return ['cg-piece', p.role, p.color].join(' ');
}

function renderPiece(ctrl, key, p) {
  var attrs = {
    style: {},
    class: pieceClass(p)
  };
  var draggable = ctrl.data.draggable.current;
  if (draggable.orig === key && (draggable.pos[0] !== 0 || draggable.pos[1] !== 0)) {
    attrs.style[util.transformProp()] = util.translate([
      draggable.pos[0] + draggable.dec[0],
      draggable.pos[1] + draggable.dec[1]
    ]);
    attrs.class += ' dragging';
  } else if (ctrl.data.animation.current.anims) {
    var animation = ctrl.data.animation.current.anims[key];
    if (animation) attrs.style[util.transformProp()] = util.translate(animation[1]);
  }
  return {
    tag: 'div',
    attrs: attrs
  };
}

function renderGhost(p) {
  return {
    tag: 'div',
    attrs: {
      class: pieceClass(p) + ' ghost'
    }
  };
}

function renderSquare(ctrl, pos) {
  var styleX = (pos[0] - 1) * 12.5 + '%';
  var styleY = (pos[1] - 1) * 12.5 + '%';
  var file = util.files[pos[0] - 1];
  var rank = pos[1];
  var key = file + rank;
  var piece = ctrl.data.pieces[key];
  var attrs = {
    class: util.classSet({
      'cg-square': true,
      'selected': ctrl.data.selected === key,
      'check': ctrl.data.check === key,
      'last-move': util.contains2(ctrl.data.lastMove, key),
      'move-dest': util.containsX(ctrl.data.movable.dests[ctrl.data.selected], key),
      'premove-dest': util.containsX(ctrl.data.premovable.dests, key),
      'current-premove': util.contains2(ctrl.data.premovable.current, key),
      'drag-over': ctrl.data.draggable.current.over === key
    }),
    style: ctrl.data.orientation === 'white' ? {
      left: styleX,
      bottom: styleY
    } : {
      right: styleX,
      top: styleY
    }
  };
  if (pos[1] === (ctrl.data.orientation === 'white' ? 1 : 8)) attrs['data-coord-x'] = file;
  if (pos[0] === (ctrl.data.orientation === 'white' ? 8 : 1)) attrs['data-coord-y'] = rank;
  var children = [];
  if (piece) {
    children.push(renderPiece(ctrl, key, piece));
    if (ctrl.data.draggable.current.orig === key && ctrl.data.draggable.showGhost) {
      children.push(renderGhost(piece));
    }
  }
  return {
    tag: 'div',
    attrs: attrs,
    children: children
  };
}

function renderDraggingSquare(cur) {
  var squareSize = cur.bounds.width / 8;
  var size = squareSize * 2;
  var pos = util.key2pos(cur.over);
  return {
    tag: 'div',
    attrs: {
      id: 'cg-square-target',
      style: {
        width: size + 'px',
        height: size + 'px',
        left: (cur.bounds.left + (pos[0] - 1.5) * squareSize) + 'px',
        top: (cur.bounds.top + (7.5 - pos[1]) * squareSize) + 'px',
      }
    }
  };
}

function renderFading(piece) {
  var style = {
        width: piece.size,
        height: piece.size,
        opacity: piece.opacity
  };
  style[util.transformProp()] = util.translate(piece.pos);
  return {
    tag: 'div',
    attrs: {
      class: 'cg-piece fading ' + piece.role + ' ' + piece.color,
      style: style
    }
  };
}

function renderBoard(ctrl) {
  //not using lodash.partial for raw perf, here
  var children = util.allPos.map(function(pos) {
    return renderSquare(ctrl, pos);
  });
  if (ctrl.data.draggable.current.over && ctrl.data.draggable.squareTarget)
    children.push(renderDraggingSquare(ctrl.data.draggable.current));
  if (ctrl.data.animation.current.fadings)
    ctrl.data.animation.current.fadings.forEach(function(p) {
      children.push(renderFading(p));
    });
  return {
    tag: 'div',
    attrs: {
      class: 'cg-board',
      config: function(el, isUpdate, context) {
        if (isUpdate) return;
        ctrl.data.bounds = el.getBoundingClientRect.bind(el);
        ctrl.data.render = m.redraw;
        var isTouch = util.isTouchDevice();
        var onstart = partial(drag.start, ctrl);
        var onmove = partial(drag.move, ctrl);
        var onend = partial(drag.end, ctrl);
        el.addEventListener(isTouch ? 'touchstart' : 'mousedown', onstart);
        document.addEventListener(isTouch ? 'touchmove' : 'mousemove', onmove);
        document.addEventListener(isTouch ? 'touchend' : 'mouseup', onend);
        context.onunload = function() {
          el.removeEventListener(isTouch ? 'touchstart' : 'mousedown', onstart);
          document.removeEventListener(isTouch ? 'touchmove' : 'mousemove', onmove);
          document.removeEventListener(isTouch ? 'touchend' : 'mouseup', onend);
        };
      }
    },
    children: children
  };
}

module.exports = renderBoard;
<commit_msg>add square occupied CSS class<commit_after>var partial = require('lodash-node/modern/functions/partial');
var util = require('./util');
var board = require('./board');
var drag = require('./drag');
var anim = require('./anim');

function pieceClass(p) {
  return ['cg-piece', p.role, p.color].join(' ');
}

function renderPiece(ctrl, key, p) {
  var attrs = {
    style: {},
    class: pieceClass(p)
  };
  var draggable = ctrl.data.draggable.current;
  if (draggable.orig === key && (draggable.pos[0] !== 0 || draggable.pos[1] !== 0)) {
    attrs.style[util.transformProp()] = util.translate([
      draggable.pos[0] + draggable.dec[0],
      draggable.pos[1] + draggable.dec[1]
    ]);
    attrs.class += ' dragging';
  } else if (ctrl.data.animation.current.anims) {
    var animation = ctrl.data.animation.current.anims[key];
    if (animation) attrs.style[util.transformProp()] = util.translate(animation[1]);
  }
  return {
    tag: 'div',
    attrs: attrs
  };
}

function renderGhost(p) {
  return {
    tag: 'div',
    attrs: {
      class: pieceClass(p) + ' ghost'
    }
  };
}

function renderSquare(ctrl, pos) {
  var styleX = (pos[0] - 1) * 12.5 + '%';
  var styleY = (pos[1] - 1) * 12.5 + '%';
  var file = util.files[pos[0] - 1];
  var rank = pos[1];
  var key = file + rank;
  var piece = ctrl.data.pieces[key];
  var attrs = {
    class: util.classSet({
      'cg-square': true,
      'selected': ctrl.data.selected === key,
      'check': ctrl.data.check === key,
      'last-move': util.contains2(ctrl.data.lastMove, key),
      'move-dest': util.containsX(ctrl.data.movable.dests[ctrl.data.selected], key),
      'premove-dest': util.containsX(ctrl.data.premovable.dests, key),
      'current-premove': util.contains2(ctrl.data.premovable.current, key),
      'drag-over': ctrl.data.draggable.current.over === key,
      'occupied': piece
    }),
    style: ctrl.data.orientation === 'white' ? {
      left: styleX,
      bottom: styleY
    } : {
      right: styleX,
      top: styleY
    }
  };
  if (pos[1] === (ctrl.data.orientation === 'white' ? 1 : 8)) attrs['data-coord-x'] = file;
  if (pos[0] === (ctrl.data.orientation === 'white' ? 8 : 1)) attrs['data-coord-y'] = rank;
  var children = [];
  if (piece) {
    children.push(renderPiece(ctrl, key, piece));
    if (ctrl.data.draggable.current.orig === key && ctrl.data.draggable.showGhost) {
      children.push(renderGhost(piece));
    }
  }
  return {
    tag: 'div',
    attrs: attrs,
    children: children
  };
}

function renderDraggingSquare(cur) {
  var squareSize = cur.bounds.width / 8;
  var size = squareSize * 2;
  var pos = util.key2pos(cur.over);
  return {
    tag: 'div',
    attrs: {
      id: 'cg-square-target',
      style: {
        width: size + 'px',
        height: size + 'px',
        left: (cur.bounds.left + (pos[0] - 1.5) * squareSize) + 'px',
        top: (cur.bounds.top + (7.5 - pos[1]) * squareSize) + 'px',
      }
    }
  };
}

function renderFading(piece) {
  var style = {
        width: piece.size,
        height: piece.size,
        opacity: piece.opacity
  };
  style[util.transformProp()] = util.translate(piece.pos);
  return {
    tag: 'div',
    attrs: {
      class: 'cg-piece fading ' + piece.role + ' ' + piece.color,
      style: style
    }
  };
}

function renderBoard(ctrl) {
  //not using lodash.partial for raw perf, here
  var children = util.allPos.map(function(pos) {
    return renderSquare(ctrl, pos);
  });
  if (ctrl.data.draggable.current.over && ctrl.data.draggable.squareTarget)
    children.push(renderDraggingSquare(ctrl.data.draggable.current));
  if (ctrl.data.animation.current.fadings)
    ctrl.data.animation.current.fadings.forEach(function(p) {
      children.push(renderFading(p));
    });
  return {
    tag: 'div',
    attrs: {
      class: 'cg-board',
      config: function(el, isUpdate, context) {
        if (isUpdate) return;
        ctrl.data.bounds = el.getBoundingClientRect.bind(el);
        ctrl.data.render = m.redraw;
        var isTouch = util.isTouchDevice();
        var onstart = partial(drag.start, ctrl);
        var onmove = partial(drag.move, ctrl);
        var onend = partial(drag.end, ctrl);
        el.addEventListener(isTouch ? 'touchstart' : 'mousedown', onstart);
        document.addEventListener(isTouch ? 'touchmove' : 'mousemove', onmove);
        document.addEventListener(isTouch ? 'touchend' : 'mouseup', onend);
        context.onunload = function() {
          el.removeEventListener(isTouch ? 'touchstart' : 'mousedown', onstart);
          document.removeEventListener(isTouch ? 'touchmove' : 'mousemove', onmove);
          document.removeEventListener(isTouch ? 'touchend' : 'mouseup', onend);
        };
      }
    },
    children: children
  };
}

module.exports = renderBoard;
<|endoftext|>


<commit_before>// Given a frame rendered to a framebuffer created with 'gl-fbo', renders a
// frame to the default framebuffer from a viewpoint at a horizontal offset and
// a parallel viewing direction.

'use strict';

var createVAS = require('./lib/view-aligned-square.js');
var glslify = require('glslify');
var glShader = require('gl-shader');

module.exports = function initWarp(gl)
{
  var
    geometry = createVAS(gl, 'aPos', 'aTexCoord'),
    shader = glShader(
      gl,
      glslify('./warp.vert'),
      glslify('./warp.frag')
    );

  return function warp(sourceFbo, offset, near, far, x, y, w, h, targetFbo)
  {
    if (targetFbo)
      targetFbo.bind();
    else
      gl.bindFramebuffer(gl.FRAMEBUFFER, null);

    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.viewport(x, y, w, h);

    geometry.bind(shader);

    shader.uniforms.uColorBuffer = sourceFbo.color[0].bind(0);
    shader.uniforms.uDepthBuffer = sourceFbo.depth.bind(1);
    shader.uniforms.uFar = far;
    shader.uniforms.uNear = near;
    shader.uniforms.uOffset = offset;
    shader.uniforms.uPixLen = 2 / sourceFbo.shape[0];

    geometry.draw();

    geometry.unbind();
  };
};<commit_msg>fixed comment<commit_after>// Given a frame rendered to a framebuffer created with 'gl-fbo', renders a
// frame from a viewpoint at a horizontal offset and a parallel viewing
// direction.

'use strict';

var createVAS = require('./lib/view-aligned-square.js');
var glslify = require('glslify');
var glShader = require('gl-shader');

module.exports = function initWarp(gl)
{
  var
    geometry = createVAS(gl, 'aPos', 'aTexCoord'),
    shader = glShader(
      gl,
      glslify('./warp.vert'),
      glslify('./warp.frag')
    );

  return function warp(sourceFbo, offset, near, far, x, y, w, h, targetFbo)
  {
    if (targetFbo)
      targetFbo.bind();
    else
      gl.bindFramebuffer(gl.FRAMEBUFFER, null);

    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.viewport(x, y, w, h);

    geometry.bind(shader);

    shader.uniforms.uColorBuffer = sourceFbo.color[0].bind(0);
    shader.uniforms.uDepthBuffer = sourceFbo.depth.bind(1);
    shader.uniforms.uFar = far;
    shader.uniforms.uNear = near;
    shader.uniforms.uOffset = offset;
    shader.uniforms.uPixLen = 2 / sourceFbo.shape[0];

    geometry.draw();

    geometry.unbind();
  };
};
<|endoftext|>


<commit_before>import createDebug from 'debug'
import eventToPromise from 'event-to-promise'
import forEach from 'lodash.foreach'
import got from 'got'
import map from 'lodash.map'
import unzip from '@julien-f/unzip'
import {PassThrough} from 'stream'
import {promisify} from 'bluebird'
import {Xapi as XapiBase} from 'xen-api'

import {debounce} from './decorators'
import {ensureArray, noop, parseXml, pFinally} from './utils'
import {JsonRpcError} from './api-errors'

const debug = createDebug('xo:xapi')

// ===================================================================

const gotPromise = promisify(got)

const wrapError = error => {
  const e = new Error(error[0])
  e.code = error[0]
  e.params = error.slice(1)
  return e
}

// ===================================================================

const typeToNamespace = Object.create(null)
forEach([
  'Bond',
  'DR_task',
  'GPU_group',
  'PBD',
  'PCI',
  'PGPU',
  'PIF',
  'PIF_metrics',
  'SM',
  'SR',
  'VBD',
  'VBD_metrics',
  'VDI',
  'VGPU',
  'VGPU_type',
  'VLAN',
  'VM',
  'VM_appliance',
  'VM_guest_metrics',
  'VM_metrics',
  'VMPP',
  'VTPM'
], namespace => {
  typeToNamespace[namespace.toLowerCase()] = namespace
})

// Object types given by `xen-api` are always lowercase but the
// namespaces in the Xen API can have a different casing.
const getNamespaceForType = (type) => typeToNamespace[type] || type

// ===================================================================

const VM_RUNNING_POWER_STATES = {
  Running: true,
  Paused: true
}
const isVmRunning = (vm) => VM_RUNNING_POWER_STATES[vm.power_state]

// ===================================================================

export default class Xapi extends XapiBase {
  constructor (...args) {
    super(...args)

    const objectsWatchers = this._objectWatchers = Object.create(null)
    const taskWatchers = this._taskWatchers = Object.create(null)

    // TODO: This is necessary to get UUIDs for host.patches.
    //
    // It will no longer be useful when using xen-api >= 0.5.
    this._refsToUuids = Object.create(null)

    const onAddOrUpdate = objects => {
      forEach(objects, object => {
        const {
          $id: id,
          $ref: ref,
          uuid
        } = object

        if (ref && uuid) {
          this._refsToUuids[ref] = uuid
        }

        // Watched object.
        if (id in objectsWatchers) {
          objectsWatchers[id].resolve(object)
          delete objectsWatchers[id]
        }
        if (ref in objectsWatchers) {
          objectsWatchers[ref].resolve(object)
          delete objectsWatchers[ref]
        }

        // Watched task.
        if (ref in taskWatchers) {
          const {status} = object

          if (status === 'success') {
            taskWatchers[ref].resolve(object.result)
          } else if (status === 'failure') {
            taskWatchers[ref].reject(wrapError(object.error_info))
          } else {
            return
          }

          delete taskWatchers[ref]
        }
      })
    }
    this.objects.on('add', onAddOrUpdate)
    this.objects.on('update', onAddOrUpdate)
  }

  // FIXME: remove this backported methods when xen-api >= 0.5
  getObject (idOrUuidOrRef, defaultValue) {
    const {_objects: {all: objects}} = this
    const object = (
      // if there is an UUID, it is also the $id.
      objects[idOrUuidOrRef] ||
      objects[this._refsToUuids[idOrUuidOrRef]]
    )

    if (object) return object

    if (arguments.length > 1) return defaultValue

    throw new Error('no object can be matched to ' + idOrUuidOrRef)
  }
  getObjectByRef (ref, defaultValue) {
    const {
      _refsToUuids: refsToUuids,

      // Objects ids are already UUIDs if they have one.
      _objects: {all: objectsByUuids}
    } = this

    if (ref in refsToUuids) {
      return objectsByUuids[refsToUuids[ref]]
    }

    if (arguments.length > 1) {
      return defaultValue
    }

    throw new Error('there is no object with the ref ' + ref)
  }
  getObjectByUuid (uuid, defaultValue) {
    const {
      // Objects ids are already UUIDs if they have one.
      _objects: {all: objectsByUuids}
    } = this

    if (uuid in objectsByUuids) {
      return objectsByUuids[uuid]
    }

    if (arguments.length > 1) {
      return defaultValue
    }

    throw new Error('there is no object with the UUID ' + uuid)
  }

  // =================================================================

  // Wait for an object to appear or to be updated.
  //
  // TODO: implements a timeout.
  _waitObject (idOrUuidOrRef) {
    let watcher = this._objectWatchers[idOrUuidOrRef]
    if (!watcher) {
      let resolve, reject
      const promise = new Promise((resolve_, reject_) => {
        resolve = resolve_
        reject = reject_
      })

      // Register the watcher.
      watcher = this._objectWatchers[idOrUuidOrRef] = {
        promise,
        resolve,
        reject
      }
    }

    return watcher.promise
  }

  // Returns the objects if already presents or waits for it.
  async _getOrWaitObject (idOrUuidOrRef) {
    return (
      this.getObject(idOrUuidOrRef, undefined) ||
      this._waitObject(idOrUuidOrRef)
    )
  }

  // =================================================================

  // Create a task.
  //
  // Returns the task object from the Xapi.
  async _createTask (name, description = '') {
    const ref = await this.call('task.create', name, description)
    debug('task created: %s', name)

    pFinally(this._watchTask(ref), () => {
      this.call('task.destroy', ref).then(() => {
        debug('task destroyed: %s', name)
      })
    })

    return this._getOrWaitObject(ref)
  }

  // Waits for a task to be resolved.
  _watchTask (ref) {
    // If a task object is passed, unpacked the ref.
    if (typeof ref === 'object' && ref.$ref) ref = ref.$ref

    let watcher = this._taskWatchers[ref]
    if (!watcher) {
      let resolve, reject
      const promise = new Promise((resolve_, reject_) => {
        resolve = resolve_
        reject = reject_
      })

      // Register the watcher.
      watcher = this._taskWatchers[ref] = {
        promise,
        resolve,
        reject
      }
    }

    return watcher.promise
  }

  // =================================================================

  async _setObjectProperties (id, props) {
    const {
      $ref: ref,
      $type: type
    } = this.getObject(id)

    const namespace = getNamespaceForType(type)

    // TODO: the thrown error should contain the name of the
    // properties that failed to be set.
    await Promise.all(map(props, (value, name) => {
      if (value != null) {
        return this.call(`${namespace}.set_${name}`, ref, value)
      }
    }))
  }

  async setPoolProperties ({
    name_label,
    name_description
  }) {
    await this._setObjectProperties(this.pool.$id, {
      name_label,
      name_description
    })
  }

  async setSrProperties (id, {
    name_label,
    name_description
  }) {
    await this._setObjectProperties(id, {
      name_label,
      name_description
    })
  }

  // =================================================================

  // FIXME: should be static
  @debounce(24 * 60 * 60 * 1000)
  async _getXenUpdates () {
    const [body, {statusCode}] = await gotPromise(
      'http://updates.xensource.com/XenServer/updates.xml'
    )

    if (statusCode !== 200) {
      throw new JsonRpcError('cannot fetch patches list from Citrix')
    }

    const {patchdata: data} = parseXml(body)

    const patches = Object.create(null)
    forEach(data.patches.patch, patch => {
      patches[patch.uuid] = {
        date: patch.timestamp,
        description: patch['name-description'],
        documentationUrl: patch.url,
        guidance: patch['after-apply-guidance'],
        name: patch['name-label'],
        url: patch['patch-url'],
        conflicts: map(ensureArray(patch.conflictingpatches), patch => {
          return patch.conflictingpatch.uuid
        }),
        requirements: map(ensureArray(patch.requiredpatches), patch => {
          return patch.requiredpatch.uuid
        })

        // TODO: what does it mean, should we handle it?
        // version: patch.version,
      }
    })

    const resolveVersionPatches = function (uuids) {
      const versionPatches = Object.create(null)

      forEach(uuids, ({uuid}) => {
        versionPatches[uuid] = patches[uuid]
      })

      return versionPatches
    }

    const versions = Object.create(null)
    let latestVersion
    forEach(data.serverversions.version, version => {
      versions[version.value] = {
        date: version.timestamp,
        name: version.name,
        id: version.value,
        documentationUrl: version.url,
        patches: resolveVersionPatches(version.patch)
      }

      if (version.latest) {
        latestVersion = versions[version.value]
      }
    })

    return {
      patches,
      latestVersion,
      versions
    }
  }

  // =================================================================

  async listMissingPoolPatchesOnHost (hostId) {
    const host = this.getObject(hostId)
    const {product_version: version} = host.software_version

    const all = (await this._getXenUpdates()).versions[version].patches

    const installed = Object.create(null)
    // TODO: simplify when we start to use xen-api >= 0.5
    forEach(host.patches, ref => {
      const hostPatch = this.objects.all[this._refsToUuids[ref]]
      installed[this._refsToUuids[hostPatch.pool_patch]] = true
    })

    const installable = []
    forEach(all, (patch, uuid) => {
      if (installed[uuid]) {
        return
      }

      for (let uuid of patch.conflicts) {
        if (uuid in installed) {
          return
        }
      }

      installable.push(patch)
    })

    return installable
  }

  // -----------------------------------------------------------------

  async uploadPoolPatch (stream, length) {
    const task = await this._createTask('Patch upload from XO')

    // TODO: Update when xen-api >= 0.5
    const poolMaster = this.objects.all[this._refsToUuids[this.pool.master]]

    const [, patchRef] = await Promise.all([
      gotPromise('http://' + poolMaster.address + '/pool_patch_upload', {
        method: 'put',
        body: stream,
        query: {
          session_id: this.sessionId,
          task_id: task.$ref
        },
        headers: {
          'content-length': length
        }
      }),
      this._watchTask(task)
    ])

    return this._getOrWaitObject(patchRef)
  }

  async _getOrUploadPoolPatch (uuid) {
    try {
      return this.getObjectByUuid(uuid)
    } catch (error) {}

    debug('downloading patch %s', uuid)

    const patchInfo = (await this._getXenUpdates()).patches[uuid]

    const PATCH_RE = /\.xsupdate$/
    const proxy = new PassThrough()
    got(patchInfo.url).on('error', error => {
      // TODO: better error handling
      console.error(error)
    }).pipe(unzip.Parse()).on('entry', entry => {
      if (PATCH_RE.test(entry.path)) {
        proxy.emit('length', entry.size)
        entry.pipe(proxy)
      } else {
        entry.autodrain()
      }
    }).on('error', error => {
      // TODO: better error handling
      console.error(error)
    })

    const length = await eventToPromise(proxy, 'length')
    return this.uploadPoolPatch(proxy, length)
  }

  async installPoolPatchOnHost (patchUuid, hostId) {
    const patch = await this._getOrUploadPoolPatch(patchUuid)
    const host = this.getObject(hostId)

    debug('installing patch %s', patchUuid)

    await this.call('pool_patch.apply', patch.$ref, host.$ref)
  }

  async installPoolPatchOnAllHosts (patchUuid) {
    const patch = await this._getOrUploadPoolPatch(patchUuid)

    await this.call('pool_patch.pool_apply', patch.$ref)
  }

  // =================================================================

  async _deleteVdi (vdiId) {
    const vdi = this.getObject(vdiId)

    await this.call('VDI.destroy', vdi.$ref)
  }

  async deleteVm (vmId, deleteDisks = false) {
    const vm = this.getObject(vmId)

    if (isVmRunning(vm)) {
      throw new Error('running VMs cannot be deleted')
    }

    if (deleteDisks) {
      // TODO: simplify when we start to use xen-api >= 0.5
      await Promise.all(map(vm.VBDs, ref => {
        try {
          return this._deleteVdi(this.getObject(ref).VDI).catch(noop)
        } catch (_) {}
      }))
    }

    await this.call('VM.destroy', vm.$ref)
  }

  // =================================================================

  async _doDockerAction (vmId, action, containerId) {
    const vm = this.getObject(vmId)
    const host = this.getObject(vm.resident_on)

    return await this.call('host.call_plugin', host.$ref, 'xscontainer', action, {
      vmuuid: vm.uuid,
      container: containerId
    })
  }

  async registerDockerContainer (vmId) {
    await this._doDockerAction(vmId, 'register')
  }

  async deregisterDockerContainer (vmId) {
    await this._doDockerAction(vmId, 'deregister')
  }

  async startDockerContainer (vmId, containerId) {
    await this._doDockerAction(vmId, 'start', containerId)
  }

  async stopDockerContainer (vmId, containerId) {
    await this._doDockerAction(vmId, 'stop', containerId)
  }

  async restartDockerContainer (vmId, containerId) {
    await this._doDockerAction(vmId, 'restart', containerId)
  }

  async pauseDockerContainer (vmId, containerId) {
    await this._doDockerAction(vmId, 'pause', containerId)
  }

  async unpauseDockerContainer (vmId, containerId) {
    await this._doDockerAction(vmId, 'unpause', containerId)
  }

  // =================================================================

}
<commit_msg>Check for patch existence in Xapi#_getOrUploadPoolPatch().<commit_after>import createDebug from 'debug'
import eventToPromise from 'event-to-promise'
import forEach from 'lodash.foreach'
import got from 'got'
import map from 'lodash.map'
import unzip from '@julien-f/unzip'
import {PassThrough} from 'stream'
import {promisify} from 'bluebird'
import {Xapi as XapiBase} from 'xen-api'

import {debounce} from './decorators'
import {ensureArray, noop, parseXml, pFinally} from './utils'
import {JsonRpcError} from './api-errors'

const debug = createDebug('xo:xapi')

// ===================================================================

const gotPromise = promisify(got)

const wrapError = error => {
  const e = new Error(error[0])
  e.code = error[0]
  e.params = error.slice(1)
  return e
}

// ===================================================================

const typeToNamespace = Object.create(null)
forEach([
  'Bond',
  'DR_task',
  'GPU_group',
  'PBD',
  'PCI',
  'PGPU',
  'PIF',
  'PIF_metrics',
  'SM',
  'SR',
  'VBD',
  'VBD_metrics',
  'VDI',
  'VGPU',
  'VGPU_type',
  'VLAN',
  'VM',
  'VM_appliance',
  'VM_guest_metrics',
  'VM_metrics',
  'VMPP',
  'VTPM'
], namespace => {
  typeToNamespace[namespace.toLowerCase()] = namespace
})

// Object types given by `xen-api` are always lowercase but the
// namespaces in the Xen API can have a different casing.
const getNamespaceForType = (type) => typeToNamespace[type] || type

// ===================================================================

const VM_RUNNING_POWER_STATES = {
  Running: true,
  Paused: true
}
const isVmRunning = (vm) => VM_RUNNING_POWER_STATES[vm.power_state]

// ===================================================================

export default class Xapi extends XapiBase {
  constructor (...args) {
    super(...args)

    const objectsWatchers = this._objectWatchers = Object.create(null)
    const taskWatchers = this._taskWatchers = Object.create(null)

    // TODO: This is necessary to get UUIDs for host.patches.
    //
    // It will no longer be useful when using xen-api >= 0.5.
    this._refsToUuids = Object.create(null)

    const onAddOrUpdate = objects => {
      forEach(objects, object => {
        const {
          $id: id,
          $ref: ref,
          uuid
        } = object

        if (ref && uuid) {
          this._refsToUuids[ref] = uuid
        }

        // Watched object.
        if (id in objectsWatchers) {
          objectsWatchers[id].resolve(object)
          delete objectsWatchers[id]
        }
        if (ref in objectsWatchers) {
          objectsWatchers[ref].resolve(object)
          delete objectsWatchers[ref]
        }

        // Watched task.
        if (ref in taskWatchers) {
          const {status} = object

          if (status === 'success') {
            taskWatchers[ref].resolve(object.result)
          } else if (status === 'failure') {
            taskWatchers[ref].reject(wrapError(object.error_info))
          } else {
            return
          }

          delete taskWatchers[ref]
        }
      })
    }
    this.objects.on('add', onAddOrUpdate)
    this.objects.on('update', onAddOrUpdate)
  }

  // FIXME: remove this backported methods when xen-api >= 0.5
  getObject (idOrUuidOrRef, defaultValue) {
    const {_objects: {all: objects}} = this
    const object = (
      // if there is an UUID, it is also the $id.
      objects[idOrUuidOrRef] ||
      objects[this._refsToUuids[idOrUuidOrRef]]
    )

    if (object) return object

    if (arguments.length > 1) return defaultValue

    throw new Error('no object can be matched to ' + idOrUuidOrRef)
  }
  getObjectByRef (ref, defaultValue) {
    const {
      _refsToUuids: refsToUuids,

      // Objects ids are already UUIDs if they have one.
      _objects: {all: objectsByUuids}
    } = this

    if (ref in refsToUuids) {
      return objectsByUuids[refsToUuids[ref]]
    }

    if (arguments.length > 1) {
      return defaultValue
    }

    throw new Error('there is no object with the ref ' + ref)
  }
  getObjectByUuid (uuid, defaultValue) {
    const {
      // Objects ids are already UUIDs if they have one.
      _objects: {all: objectsByUuids}
    } = this

    if (uuid in objectsByUuids) {
      return objectsByUuids[uuid]
    }

    if (arguments.length > 1) {
      return defaultValue
    }

    throw new Error('there is no object with the UUID ' + uuid)
  }

  // =================================================================

  // Wait for an object to appear or to be updated.
  //
  // TODO: implements a timeout.
  _waitObject (idOrUuidOrRef) {
    let watcher = this._objectWatchers[idOrUuidOrRef]
    if (!watcher) {
      let resolve, reject
      const promise = new Promise((resolve_, reject_) => {
        resolve = resolve_
        reject = reject_
      })

      // Register the watcher.
      watcher = this._objectWatchers[idOrUuidOrRef] = {
        promise,
        resolve,
        reject
      }
    }

    return watcher.promise
  }

  // Returns the objects if already presents or waits for it.
  async _getOrWaitObject (idOrUuidOrRef) {
    return (
      this.getObject(idOrUuidOrRef, undefined) ||
      this._waitObject(idOrUuidOrRef)
    )
  }

  // =================================================================

  // Create a task.
  //
  // Returns the task object from the Xapi.
  async _createTask (name, description = '') {
    const ref = await this.call('task.create', name, description)
    debug('task created: %s', name)

    pFinally(this._watchTask(ref), () => {
      this.call('task.destroy', ref).then(() => {
        debug('task destroyed: %s', name)
      })
    })

    return this._getOrWaitObject(ref)
  }

  // Waits for a task to be resolved.
  _watchTask (ref) {
    // If a task object is passed, unpacked the ref.
    if (typeof ref === 'object' && ref.$ref) ref = ref.$ref

    let watcher = this._taskWatchers[ref]
    if (!watcher) {
      let resolve, reject
      const promise = new Promise((resolve_, reject_) => {
        resolve = resolve_
        reject = reject_
      })

      // Register the watcher.
      watcher = this._taskWatchers[ref] = {
        promise,
        resolve,
        reject
      }
    }

    return watcher.promise
  }

  // =================================================================

  async _setObjectProperties (id, props) {
    const {
      $ref: ref,
      $type: type
    } = this.getObject(id)

    const namespace = getNamespaceForType(type)

    // TODO: the thrown error should contain the name of the
    // properties that failed to be set.
    await Promise.all(map(props, (value, name) => {
      if (value != null) {
        return this.call(`${namespace}.set_${name}`, ref, value)
      }
    }))
  }

  async setPoolProperties ({
    name_label,
    name_description
  }) {
    await this._setObjectProperties(this.pool.$id, {
      name_label,
      name_description
    })
  }

  async setSrProperties (id, {
    name_label,
    name_description
  }) {
    await this._setObjectProperties(id, {
      name_label,
      name_description
    })
  }

  // =================================================================

  // FIXME: should be static
  @debounce(24 * 60 * 60 * 1000)
  async _getXenUpdates () {
    const [body, {statusCode}] = await gotPromise(
      'http://updates.xensource.com/XenServer/updates.xml'
    )

    if (statusCode !== 200) {
      throw new JsonRpcError('cannot fetch patches list from Citrix')
    }

    const {patchdata: data} = parseXml(body)

    const patches = Object.create(null)
    forEach(data.patches.patch, patch => {
      patches[patch.uuid] = {
        date: patch.timestamp,
        description: patch['name-description'],
        documentationUrl: patch.url,
        guidance: patch['after-apply-guidance'],
        name: patch['name-label'],
        url: patch['patch-url'],
        conflicts: map(ensureArray(patch.conflictingpatches), patch => {
          return patch.conflictingpatch.uuid
        }),
        requirements: map(ensureArray(patch.requiredpatches), patch => {
          return patch.requiredpatch.uuid
        })

        // TODO: what does it mean, should we handle it?
        // version: patch.version,
      }
    })

    const resolveVersionPatches = function (uuids) {
      const versionPatches = Object.create(null)

      forEach(uuids, ({uuid}) => {
        versionPatches[uuid] = patches[uuid]
      })

      return versionPatches
    }

    const versions = Object.create(null)
    let latestVersion
    forEach(data.serverversions.version, version => {
      versions[version.value] = {
        date: version.timestamp,
        name: version.name,
        id: version.value,
        documentationUrl: version.url,
        patches: resolveVersionPatches(version.patch)
      }

      if (version.latest) {
        latestVersion = versions[version.value]
      }
    })

    return {
      patches,
      latestVersion,
      versions
    }
  }

  // =================================================================

  async listMissingPoolPatchesOnHost (hostId) {
    const host = this.getObject(hostId)
    const {product_version: version} = host.software_version

    const all = (await this._getXenUpdates()).versions[version].patches

    const installed = Object.create(null)
    // TODO: simplify when we start to use xen-api >= 0.5
    forEach(host.patches, ref => {
      const hostPatch = this.objects.all[this._refsToUuids[ref]]
      installed[this._refsToUuids[hostPatch.pool_patch]] = true
    })

    const installable = []
    forEach(all, (patch, uuid) => {
      if (installed[uuid]) {
        return
      }

      for (let uuid of patch.conflicts) {
        if (uuid in installed) {
          return
        }
      }

      installable.push(patch)
    })

    return installable
  }

  // -----------------------------------------------------------------

  async uploadPoolPatch (stream, length) {
    const task = await this._createTask('Patch upload from XO')

    // TODO: Update when xen-api >= 0.5
    const poolMaster = this.objects.all[this._refsToUuids[this.pool.master]]

    const [, patchRef] = await Promise.all([
      gotPromise('http://' + poolMaster.address + '/pool_patch_upload', {
        method: 'put',
        body: stream,
        query: {
          session_id: this.sessionId,
          task_id: task.$ref
        },
        headers: {
          'content-length': length
        }
      }),
      this._watchTask(task)
    ])

    return this._getOrWaitObject(patchRef)
  }

  async _getOrUploadPoolPatch (uuid) {
    try {
      return this.getObjectByUuid(uuid)
    } catch (error) {}

    debug('downloading patch %s', uuid)

    const patchInfo = (await this._getXenUpdates()).patches[uuid]
    if (!patchInfo) {
      throw new Error('no such patch ' + uuid)
    }

    const PATCH_RE = /\.xsupdate$/
    const proxy = new PassThrough()
    got(patchInfo.url).on('error', error => {
      // TODO: better error handling
      console.error(error)
    }).pipe(unzip.Parse()).on('entry', entry => {
      if (PATCH_RE.test(entry.path)) {
        proxy.emit('length', entry.size)
        entry.pipe(proxy)
      } else {
        entry.autodrain()
      }
    }).on('error', error => {
      // TODO: better error handling
      console.error(error)
    })

    const length = await eventToPromise(proxy, 'length')
    return this.uploadPoolPatch(proxy, length)
  }

  async installPoolPatchOnHost (patchUuid, hostId) {
    const patch = await this._getOrUploadPoolPatch(patchUuid)
    const host = this.getObject(hostId)

    debug('installing patch %s', patchUuid)

    await this.call('pool_patch.apply', patch.$ref, host.$ref)
  }

  async installPoolPatchOnAllHosts (patchUuid) {
    const patch = await this._getOrUploadPoolPatch(patchUuid)

    await this.call('pool_patch.pool_apply', patch.$ref)
  }

  // =================================================================

  async _deleteVdi (vdiId) {
    const vdi = this.getObject(vdiId)

    await this.call('VDI.destroy', vdi.$ref)
  }

  async deleteVm (vmId, deleteDisks = false) {
    const vm = this.getObject(vmId)

    if (isVmRunning(vm)) {
      throw new Error('running VMs cannot be deleted')
    }

    if (deleteDisks) {
      // TODO: simplify when we start to use xen-api >= 0.5
      await Promise.all(map(vm.VBDs, ref => {
        try {
          return this._deleteVdi(this.getObject(ref).VDI).catch(noop)
        } catch (_) {}
      }))
    }

    await this.call('VM.destroy', vm.$ref)
  }

  // =================================================================

  async _doDockerAction (vmId, action, containerId) {
    const vm = this.getObject(vmId)
    const host = this.getObject(vm.resident_on)

    return await this.call('host.call_plugin', host.$ref, 'xscontainer', action, {
      vmuuid: vm.uuid,
      container: containerId
    })
  }

  async registerDockerContainer (vmId) {
    await this._doDockerAction(vmId, 'register')
  }

  async deregisterDockerContainer (vmId) {
    await this._doDockerAction(vmId, 'deregister')
  }

  async startDockerContainer (vmId, containerId) {
    await this._doDockerAction(vmId, 'start', containerId)
  }

  async stopDockerContainer (vmId, containerId) {
    await this._doDockerAction(vmId, 'stop', containerId)
  }

  async restartDockerContainer (vmId, containerId) {
    await this._doDockerAction(vmId, 'restart', containerId)
  }

  async pauseDockerContainer (vmId, containerId) {
    await this._doDockerAction(vmId, 'pause', containerId)
  }

  async unpauseDockerContainer (vmId, containerId) {
    await this._doDockerAction(vmId, 'unpause', containerId)
  }

  // =================================================================

}
<|endoftext|>


<commit_before>/* jshint unused: false */

window.Platform = {};
var logFlags = {
    //dom: true,
    //data: true
};

(function() {
    var attrModifiedWorks = false;
    var listener = function() {
        attrModifiedWorks = true;
    };

    var doc = document.documentElement;
    doc.addEventListener('DOMAttrModified', listener, false);
    doc.setAttribute('___TEST___', true);
    doc.removeAttribute('___TEST___', true);
    doc.removeEventListener('DOMAttrModified', listener, false);

    if (attrModifiedWorks) {
        return;
    }

    HTMLElement.prototype.__setAttribute = HTMLElement.prototype.setAttribute;
    HTMLElement.prototype.setAttribute = function(attrName, newVal) {
        var prevVal = this.getAttribute(attrName);
        this.__setAttribute(attrName, newVal);
        newVal = this.getAttribute(attrName);
        if (newVal != prevVal) {
            var evt = document.createEvent('MutationEvent');
            evt.initMutationEvent(
                'DOMAttrModified',
                true,
                false,
                this,
                prevVal || '',
                newVal || '',
                attrName,
                (prevVal == null) ? evt.ADDITION : evt.MODIFICATION
            );
            this.dispatchEvent(evt);
        }
    };

    HTMLElement.prototype.__removeAttribute = HTMLElement.prototype.removeAttribute;
    HTMLElement.prototype.removeAttribute = function(attrName) {
        var prevVal = this.getAttribute(attrName);
        this.__removeAttribute(attrName);
        var evt = document.createEvent('MutationEvent');
        evt.initMutationEvent(
            'DOMAttrModified',
            true,
            false,
            this,
            prevVal,
            '',
            attrName,
            evt.REMOVAL
        );
        this.dispatchEvent(evt);
    };
}());

/*! borschik:include:../node_modules/dom-token-list-polyfill/src/token-list.js */
/*! borschik:include:../node_modules/WeakMap/weakmap.js */
/*! borschik:include:../node_modules/MutationObservers/MutationObserver.js */

window.Platform.endOfMicrotask = (function() {
    var iterations = 0;
    var callbacks = [];
    var twiddle = document.createTextNode('');
    var Mutation = window.MutationObserver || window.JsMutationObserver;

    (new Mutation(function() {
        while (callbacks.length) {
            callbacks.shift()();
        }

    })).observe(twiddle, {
        characterData: true
    });

    return function(callback) {
        twiddle.textContent = iterations++;
        callbacks.push(callback);
    };
}());

(function() {
    /*! borschik:include:../node_modules/CustomElements/src/scope.js */
    /*! borschik:include:../node_modules/CustomElements/src/Observer.js */
    /*! borschik:include:../node_modules/CustomElements/src/CustomElements.js */
    /*! borschik:include:../node_modules/CustomElements/src/Parser.js */
    /*! borschik:include:../node_modules/CustomElements/src/boot.js */
}());

(function() {
    /*! borschik:include:../node_modules/HTMLImports/src/scope.js */
    /*! borschik:include:../node_modules/HTMLImports/src/Loader.js */
    /*! borschik:include:../node_modules/HTMLImports/src/Parser.js */
    /*! borschik:include:../node_modules/HTMLImports/src/HTMLImports.js */
    /*! borschik:include:../node_modules/HTMLImports/src/Observer.js */
    /*! borschik:include:../node_modules/HTMLImports/src/boot.js */
}());

/*! borschik:include:../node_modules/x-tag-core/src/core.js */
<commit_msg>DOMAttrModified<commit_after>/* jshint unused: false */

window.Platform = {};
var logFlags = {
    //dom: true,
    //data: true
};

/**
 * @see http://engineering.silk.co/post/31921750832/mutation-events-what-happens
 */
(function() {
    var attrModifiedWorks = false;
    var listener = function() {
        attrModifiedWorks = true;
    };

    var doc = document.documentElement;
    doc.addEventListener('DOMAttrModified', listener, false);
    doc.setAttribute('___TEST___', true);
    doc.removeAttribute('___TEST___', true);
    doc.removeEventListener('DOMAttrModified', listener, false);

    if (attrModifiedWorks) {
        return;
    }

    HTMLElement.prototype.__setAttribute = HTMLElement.prototype.setAttribute;
    HTMLElement.prototype.setAttribute = function(attrName, newVal) {
        var prevVal = this.getAttribute(attrName);
        this.__setAttribute(attrName, newVal);
        newVal = this.getAttribute(attrName);
        if (newVal != prevVal) {
            var evt = document.createEvent('MutationEvent');
            evt.initMutationEvent(
                'DOMAttrModified',
                true,
                false,
                this,
                prevVal || '',
                newVal || '',
                attrName,
                (prevVal == null) ? evt.ADDITION : evt.MODIFICATION
            );
            this.dispatchEvent(evt);
        }
    };

    HTMLElement.prototype.__removeAttribute = HTMLElement.prototype.removeAttribute;
    HTMLElement.prototype.removeAttribute = function(attrName) {
        var prevVal = this.getAttribute(attrName);
        this.__removeAttribute(attrName);
        var evt = document.createEvent('MutationEvent');
        evt.initMutationEvent(
            'DOMAttrModified',
            true,
            false,
            this,
            prevVal,
            '',
            attrName,
            evt.REMOVAL
        );
        this.dispatchEvent(evt);
    };
}());

/*! borschik:include:../node_modules/dom-token-list-polyfill/src/token-list.js */
/*! borschik:include:../node_modules/WeakMap/weakmap.js */
/*! borschik:include:../node_modules/MutationObservers/MutationObserver.js */

window.Platform.endOfMicrotask = (function() {
    var iterations = 0;
    var callbacks = [];
    var twiddle = document.createTextNode('');
    var Mutation = window.MutationObserver || window.JsMutationObserver;

    (new Mutation(function() {
        while (callbacks.length) {
            callbacks.shift()();
        }

    })).observe(twiddle, {
        characterData: true
    });

    return function(callback) {
        twiddle.textContent = iterations++;
        callbacks.push(callback);
    };
}());

(function() {
    /*! borschik:include:../node_modules/CustomElements/src/scope.js */
    /*! borschik:include:../node_modules/CustomElements/src/Observer.js */
    /*! borschik:include:../node_modules/CustomElements/src/CustomElements.js */
    /*! borschik:include:../node_modules/CustomElements/src/Parser.js */
    /*! borschik:include:../node_modules/CustomElements/src/boot.js */
}());

(function() {
    /*! borschik:include:../node_modules/HTMLImports/src/scope.js */
    /*! borschik:include:../node_modules/HTMLImports/src/Loader.js */
    /*! borschik:include:../node_modules/HTMLImports/src/Parser.js */
    /*! borschik:include:../node_modules/HTMLImports/src/HTMLImports.js */
    /*! borschik:include:../node_modules/HTMLImports/src/Observer.js */
    /*! borschik:include:../node_modules/HTMLImports/src/boot.js */
}());

/*! borschik:include:../node_modules/x-tag-core/src/core.js */
<|endoftext|>


<commit_before>/*
Copyright 2018 New Vector Ltd

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

import React from 'react';
import ResizeHandle from '../views/elements/ResizeHandle';
import {Resizer, FixedDistributor} from '../../resizer';

export default class MainSplit extends React.Component {
    constructor(props) {
        super(props);
        this._setResizeContainerRef = this._setResizeContainerRef.bind(this);
        this._onResized = this._onResized.bind(this);
    }

    _onResized(size) {
        window.localStorage.setItem("mx_rhs_size", size);
    }

    _createResizer() {
        const classNames = {
            handle: "mx_ResizeHandle",
            vertical: "mx_ResizeHandle_vertical",
            reverse: "mx_ResizeHandle_reverse",
        };
        const resizer = new Resizer(
            this.resizeContainer,
            FixedDistributor,
            {onResized: this._onResized},
        );
        resizer.setClassNames(classNames);
        const rhsSize = window.localStorage.getItem("mx_rhs_size");
        if (rhsSize !== null) {
            resizer.forHandleAt(0).resize(parseInt(rhsSize, 10));
        }

        resizer.attach();
        this.resizer = resizer;
    }

    _setResizeContainerRef(div) {
        this.resizeContainer = div;
    }

    componentDidMount() {
        if (this.props.panel && !this.props.collapsedRhs) {
            this._createResizer();
        }
    }

    componentWillUnmount() {
        if (this.resizer) {
            this.resizer.detach();
            this.resizer = null;
        }
    }

    componentDidUpdate(prevProps) {
        const wasExpanded = !this.props.collapsedRhs && prevProps.collapsedRhs;
        const wasCollapsed = this.props.collapsedRhs && !prevProps.collapsedRhs;
        const wasPanelSet = this.props.panel && !prevProps.panel;
        const wasPanelCleared = !this.props.panel && prevProps.panel;

        if (wasExpanded || wasPanelSet) {
            this._createResizer();
        } else if (wasCollapsed || wasPanelCleared) {
            this.resizer.detach();
            this.resizer = null;
        }
    }

    render() {
        const bodyView = React.Children.only(this.props.children);
        const panelView = this.props.panel;

        if (this.props.collapsedRhs || !panelView) {
            return bodyView;
        } else {
            return

                { bodyView }
                <ResizeHandle reverse={true} />
                { panelView }

;
        }
    }
}
<commit_msg>give right panel default width of 350px<commit_after>/*
Copyright 2018 New Vector Ltd

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

import React from 'react';
import ResizeHandle from '../views/elements/ResizeHandle';
import {Resizer, FixedDistributor} from '../../resizer';

export default class MainSplit extends React.Component {
    constructor(props) {
        super(props);
        this._setResizeContainerRef = this._setResizeContainerRef.bind(this);
        this._onResized = this._onResized.bind(this);
    }

    _onResized(size) {
        window.localStorage.setItem("mx_rhs_size", size);
    }

    _createResizer() {
        const classNames = {
            handle: "mx_ResizeHandle",
            vertical: "mx_ResizeHandle_vertical",
            reverse: "mx_ResizeHandle_reverse",
        };
        const resizer = new Resizer(
            this.resizeContainer,
            FixedDistributor,
            {onResized: this._onResized},
        );
        resizer.setClassNames(classNames);
        let rhsSize = window.localStorage.getItem("mx_rhs_size");
        if (rhsSize !== null) {
            rhsSize = parseInt(rhsSize, 10);
        } else {
            rhsSize = 350;
        }
        resizer.forHandleAt(0).resize(rhsSize);

        resizer.attach();
        this.resizer = resizer;
    }

    _setResizeContainerRef(div) {
        this.resizeContainer = div;
    }

    componentDidMount() {
        if (this.props.panel && !this.props.collapsedRhs) {
            this._createResizer();
        }
    }

    componentWillUnmount() {
        if (this.resizer) {
            this.resizer.detach();
            this.resizer = null;
        }
    }

    componentDidUpdate(prevProps) {
        const wasExpanded = !this.props.collapsedRhs && prevProps.collapsedRhs;
        const wasCollapsed = this.props.collapsedRhs && !prevProps.collapsedRhs;
        const wasPanelSet = this.props.panel && !prevProps.panel;
        const wasPanelCleared = !this.props.panel && prevProps.panel;

        if (wasExpanded || wasPanelSet) {
            this._createResizer();
        } else if (wasCollapsed || wasPanelCleared) {
            this.resizer.detach();
            this.resizer = null;
        }
    }

    render() {
        const bodyView = React.Children.only(this.props.children);
        const panelView = this.props.panel;

        if (this.props.collapsedRhs || !panelView) {
            return bodyView;
        } else {
            return

                { bodyView }
                <ResizeHandle reverse={true} />
                { panelView }

;
        }
    }
}
<|endoftext|>


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

function findConfig() {
  let foundConfig;
  const configFileName = 'wallet.config.json';
  let walletConfigPaths = [
    `${os.homedir()}/${configFileName}`,
    `../${configFileName}`,
    `../../${configFileName}`
  ];

  for (let path of walletConfigPaths) {
    if (!foundConfig) {
      try {
        const walletConfig = require(path);
        console.log((walletConfig));
        foundConfig = walletConfig.wallets;
        console.log(foundConfig);
      } catch (e) {
        foundConfig = undefined;
      }
    }
  }
  return foundConfig;
}

const Config = () => {
  let config = {
    baseURL: 'http://127.0.0.1:3000/api'
  }
  let foundConfig = findConfig();
  const mergedConfig = Object.assign({}, config, foundConfig);
  return mergedConfig;
};

module.exports = Config();
<commit_msg>WIP: update the config.js file<commit_after>'use strict';
const os = require('os');

function findConfig() {
  let foundConfig;
  const configFileName = 'wallet.config.json';
  let walletConfigPaths = [
    `${os.homedir()}/${configFileName}`,
    `../${configFileName}`,
    `../../${configFileName}`
  ];

  for (let path of walletConfigPaths) {
    if (!foundConfig) {
      try {
        const walletConfig = require(path);
        foundConfig = walletConfig;
      } catch (e) {
        foundConfig = undefined;
      }
    }
  }
  return foundConfig;
}

const Config = () => {
  let config = {
    baseURL: 'http://127.0.0.1:3000/api'
  }
  let foundConfig = findConfig();
  const mergedConfig = Object.assign({}, config, foundConfig);
  return mergedConfig;
};

module.exports = Config();
<|endoftext|>


<commit_before>const debug = require('debug')('sql')
const chalk = require('chalk')
const Sequelize = require('sequelize')
const pkg = require('../package.json')

const name = (process.env.DATABASE_NAME || pkg.name);

const url = `${process.env.DATABASE_URL}` || `postgres://localhost:5432/`;

console.log(chalk.yellow(`Opening database connection to ${url}${name}`));

// create the database instance
const db = module.exports = new Sequelize(url+name, {
  logging: debug, // export DEBUG=sql in the environment to get SQL queries
  define: {
    underscored: true,       // use snake_case rather than camelCase column names
    freezeTableName: true,   // don't change table names from the one specified
    timestamps: true,        // automatically include timestamp columns
  }
})

// pull in our models
require('./models')

// sync the db, creating it if necessary
function sync(retries=0, maxRetries=5) {
  return db.sync({force:false})
    .then(ok => console.log(`Synced models to db ${url}`))
    .catch(fail => {
      console.log(fail)
    })
}

db.didSync = sync()
<commit_msg>Update index.js<commit_after>const debug = require('debug')('sql')
const chalk = require('chalk')
const Sequelize = require('sequelize')
const pkg = require('../package.json')

const name = process.env.DATABASE_NAME || pkg.name;

const url = process.env.DATABASE_URL || `postgres://localhost:5432/`;

console.log(chalk.yellow(`Opening database connection to ${url}${name}`));

// create the database instance
const db = module.exports = new Sequelize(url+name, {
  logging: debug, // export DEBUG=sql in the environment to get SQL queries
  define: {
    underscored: true,       // use snake_case rather than camelCase column names
    freezeTableName: true,   // don't change table names from the one specified
    timestamps: true,        // automatically include timestamp columns
  }
})

// pull in our models
require('./models')

// sync the db, creating it if necessary
function sync(retries=0, maxRetries=5) {
  return db.sync({force:false})
    .then(ok => console.log(`Synced models to db ${url}`))
    .catch(fail => {
      console.log(fail)
    })
}

db.didSync = sync()
<|endoftext|>


<commit_before>/*
Copyright 2015, 2016 OpenMarket Ltd

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

'use strict';

import React from 'react';
import { _t } from '../../languageHandler';
import { KeyCode } from '../../Keyboard';
import sdk from '../../index';
import dis from '../../dispatcher';
import rate_limited_func from '../../ratelimitedfunc';
import AccessibleButton from '../../components/views/elements/AccessibleButton';

module.exports = React.createClass({
    displayName: 'SearchBox',

    propTypes: {
        onSearch: React.PropTypes.func,
        onCleared: React.PropTypes.func,
    },

    getInitialState: function() {
        return {
            searchTerm: "",
        };
    },

    componentDidMount: function() {
        this.dispatcherRef = dis.register(this.onAction);
    },

    componentWillUnmount: function() {
        dis.unregister(this.dispatcherRef);
    },

    onAction: function(payload) {
        switch (payload.action) {
            case 'view_room':
                if (this.refs.search && payload.clear_search) {
                    this._clearSearch();
                }
                break;
            case 'focus_room_filter':
                if (this.refs.search) {
                    this.refs.search.focus();
                }
                break;
        }
    },

    onChange: function() {
        if (!this.refs.search) return;
        this.setState({ searchTerm: this.refs.search.value });
        this.onSearch();
    },

    onSearch: new rate_limited_func(
        function() {
            this.props.onSearch(this.refs.search.value);
        },
        100,
    ),

    _onKeyDown: function(ev) {
        switch (ev.keyCode) {
            case KeyCode.ESCAPE:
                this._clearSearch("keyboard");
                break;
        }
    },

    _onFocus: function(ev) {
        ev.target.select();
    },

    _clearSearch: function(source) {
        this.refs.search.value = "";
        this.onChange();
        if (this.props.onCleared) {
            this.props.onCleared(source);
        }
    },

    render: function() {
        // check for collapsed here and
        // not at parent so we keep
        // searchTerm in our state
        // when collapsing and expanding
        if (this.props.collapsed) {
            return null;
        }
        const clearButton = this.state.searchTerm.length > 0 ?
            (<AccessibleButton key="button"
                    className="mx_SearchBox_closeButton"
                    onClick={ () => {this._clearSearch("button")} }>
            </AccessibleButton>) :  undefined;

        return (

                <input
                    key="searchfield"
                    type="text"
                    ref="search"
                    className="mx_textinput_icon mx_textinput_search"
                    value={ this.state.searchTerm }
                    onFocus={ this._onFocus }
                    onChange={ this.onChange }
                    onKeyDown={ this._onKeyDown }
                    placeholder={ _t('Filter room names') }
                />
                { clearButton }

        );
    },
});
<commit_msg>increase debouncing of filtering because its quite laggy atm<commit_after>/*
Copyright 2015, 2016 OpenMarket Ltd

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

'use strict';

import React from 'react';
import { _t } from '../../languageHandler';
import { KeyCode } from '../../Keyboard';
import sdk from '../../index';
import dis from '../../dispatcher';
import rate_limited_func from '../../ratelimitedfunc';
import AccessibleButton from '../../components/views/elements/AccessibleButton';

module.exports = React.createClass({
    displayName: 'SearchBox',

    propTypes: {
        onSearch: React.PropTypes.func,
        onCleared: React.PropTypes.func,
    },

    getInitialState: function() {
        return {
            searchTerm: "",
        };
    },

    componentDidMount: function() {
        this.dispatcherRef = dis.register(this.onAction);
    },

    componentWillUnmount: function() {
        dis.unregister(this.dispatcherRef);
    },

    onAction: function(payload) {
        switch (payload.action) {
            case 'view_room':
                if (this.refs.search && payload.clear_search) {
                    this._clearSearch();
                }
                break;
            case 'focus_room_filter':
                if (this.refs.search) {
                    this.refs.search.focus();
                }
                break;
        }
    },

    onChange: function() {
        if (!this.refs.search) return;
        this.setState({ searchTerm: this.refs.search.value });
        this.onSearch();
    },

    onSearch: new rate_limited_func(
        function() {
            this.props.onSearch(this.refs.search.value);
        },
        500,
    ),

    _onKeyDown: function(ev) {
        switch (ev.keyCode) {
            case KeyCode.ESCAPE:
                this._clearSearch("keyboard");
                break;
        }
    },

    _onFocus: function(ev) {
        ev.target.select();
    },

    _clearSearch: function(source) {
        this.refs.search.value = "";
        this.onChange();
        if (this.props.onCleared) {
            this.props.onCleared(source);
        }
    },

    render: function() {
        // check for collapsed here and
        // not at parent so we keep
        // searchTerm in our state
        // when collapsing and expanding
        if (this.props.collapsed) {
            return null;
        }
        const clearButton = this.state.searchTerm.length > 0 ?
            (<AccessibleButton key="button"
                    className="mx_SearchBox_closeButton"
                    onClick={ () => {this._clearSearch("button")} }>
            </AccessibleButton>) :  undefined;

        return (

                <input
                    key="searchfield"
                    type="text"
                    ref="search"
                    className="mx_textinput_icon mx_textinput_search"
                    value={ this.state.searchTerm }
                    onFocus={ this._onFocus }
                    onChange={ this.onChange }
                    onKeyDown={ this._onKeyDown }
                    placeholder={ _t('Filter room names') }
                />
                { clearButton }

        );
    },
});
<|endoftext|>


<commit_before>// Gulp plugins:
var gulp = require("gulp"),
    jade = require("gulp-jade"),
    stylus = require("gulp-stylus"),
    nib = require("nib"),
    changed = require("gulp-changed"),
    prefix = require("gulp-autoprefixer"),
    browserSync = require("browser-sync");

// Useful globs in handy variables:
var markupSrc = ["source/markup/*.jade", "!source/markup/_layout.jade", "!source/markup/partials{,/**}"],
    stylesSrc = ["source/stylesheets/*.styl", "!source/stylesheets/partials{,/**}", "!source/stylesheets/modules{,/**}"],
    jsSrc     = ["source/javascript/*.js", "!source/javascript/vendor{,/**}"],
    imagesSrc = "source/images/**/*.*",
    auxSrc    = ["source/**/*.json"]; // This glob is for dummy data files and such

// Aaaand we start taskin’
// By default, we build, serve, and watch for changes:
gulp.task("default", ["build", "browser-sync"], function () {
  gulp.watch(markupSrc[0], ["markup"]);
  gulp.watch(stylesSrc[0], ["styles"]);
  gulp.watch(jsSrc[0], ["javascript"]);
  gulp.watch(imagesSrc, ["images"]);
  gulp.watch(auxSrc, ["auxiliary"]);
});

// Build the site:
gulp.task("build", ["markup", "styles", "javascript", "images", "auxiliary"], function () {});

// Generate markup:
gulp.task("markup", function () {
  gulp.src(markupSrc)
  .pipe(jade({
    pretty: true
  }))
  .pipe(gulp.dest("build/"));
});

// Generate styles, add prefixes:
gulp.task("styles", function () {
  gulp.src(stylesSrc)
  .pipe(stylus({
    use: [nib()]
  }))
  .pipe(prefix("last 2 versions", "> 1%"))
  .pipe(gulp.dest("build/stylesheets"));
});

// Copy javascript:
gulp.task("javascript", function () {
  gulp.src(jsSrc)
  .pipe(gulp.dest("build/javascript"));
});
// TO-DO: Implement hinting & collation.

// Copy images to build dir:
gulp.task("images", function () {
  gulp.src(imagesSrc)
  .pipe(gulp.dest("build/images"));
});

// Copy additional files:
// (useful for .json and other dummy data files)
gulp.task("auxiliary", function () {
  gulp.src(auxSrc)
  .pipe(gulp.dest("build/"));
});

// Init browser-sync & watch generated files:
gulp.task("browser-sync", function () {
  browserSync.init(null, {
    server: {
      baseDir: "./build"
    },
    files: [
      "build/**/*.html",
      "build/**/*.css",
      "build/**/*.js"
    ]
  });
});
<commit_msg>Use build variable in gulpfile<commit_after>// Gulp plugins:
var gulp = require("gulp"),
    jade = require("gulp-jade"),
    stylus = require("gulp-stylus"),
    nib = require("nib"),
    changed = require("gulp-changed"),
    prefix = require("gulp-autoprefixer"),
    browserSync = require("browser-sync");

// Useful globs in handy variables:
var markupSrc = ["source/markup/*.jade", "!source/markup/_layout.jade", "!source/markup/partials{,/**}"],
    stylesSrc = ["source/stylesheets/*.styl", "!source/stylesheets/partials{,/**}", "!source/stylesheets/modules{,/**}"],
    jsSrc     = ["source/javascript/*.js", "!source/javascript/vendor{,/**}"],
    imagesSrc = "source/images/**/*.*",
    auxSrc    = ["source/**/*.json"]; // This glob is for dummy data files and such

var buildDir = "./build"

// Aaaand we start taskin’
// By default, we build, serve, and watch for changes:
gulp.task("default", ["build", "browser-sync"], function () {
  gulp.watch(markupSrc[0], ["markup"]);
  gulp.watch(stylesSrc[0], ["styles"]);
  gulp.watch(jsSrc[0], ["javascript"]);
  gulp.watch(imagesSrc, ["images"]);
  gulp.watch(auxSrc, ["auxiliary"]);
});

// Build the site:
gulp.task("build", ["markup", "styles", "javascript", "images", "auxiliary"], function () {});

// Generate markup:
gulp.task("markup", function () {
  gulp.src(markupSrc)
  .pipe(jade({
    pretty: true
  }))
  .pipe(gulp.dest(buildDir));
});

// Generate styles, add prefixes:
gulp.task("styles", function () {
  gulp.src(stylesSrc)
  .pipe(stylus({
    use: [nib()]
  }))
  .pipe(prefix("last 2 versions", "> 1%"))
  .pipe(gulp.dest(buildDir + "/stylesheets"));
});

// Copy javascript:
gulp.task("javascript", function () {
  gulp.src(jsSrc)
  .pipe(gulp.dest(buildDir + "/javascript"));
});
// TO-DO: Implement hinting & collation.

// Copy images to build dir:
gulp.task("images", function () {
  gulp.src(imagesSrc)
  .pipe(gulp.dest(buildDir + "/images"));
});

// Copy additional files:
// (useful for .json and other dummy data files)
gulp.task("auxiliary", function () {
  gulp.src(auxSrc)
  .pipe(gulp.dest(buildDir));
});

// Init browser-sync & watch generated files:
gulp.task("browser-sync", function () {
  browserSync.init(null, {
    server: {
      baseDir: buildDir
    },
    files: [
      "build/**/*.html",
      "build/**/*.css",
      "build/**/*.js"
    ]
  });
});
<|endoftext|>


<commit_before>/*
Copyright (c) 2011, Ideyatech, Inc. All rights reserved.
Code licensed under the BSD License
 */

/**
 * The global namespace.
 */
var IDEYATECH = {};

/**
 * for our widget class
 */
IDEYATECH.widgets = {};

/**
 * Safe javascript logging to Firebug. Copied from:
 * http://www.mario.net.au/blog/better-firebug-and-jquery-logging.html
 *
 */
jQuery.fn.log = function() {
	if (window.console && window.console.log) {
		if (arguments.length) {
			console.log("%o args: %o", this, arguments);
		} else {
			console.log(this);
		}
	}
	return this;
};

/**
 * Provides common utility functions.
 *
 * @class util
 * @namespace IDEYATECH
 */

IDEYATECH.util = function() {

	/**
	 * Private method that replaces response text. This is generally used for
	 * multipart form.
	 *
	 * @param str -
	 *            string response Text
	 * @return newResponseText string
	 */
	var __hackResponse = function(str) {
		/*
		 * hack tags, we use [] instead of <> because of its limitation (the
		 * response text automatically append a closing tag when seeing a tag
		 * inside it
		 */
		str = str.replace(/\[multipart_tr(.*?)\]/gi, "
");
		str = str.replace(/\[\/multipart_tr\]/gi, "
");
		str = str.replace(/\[multipart_td(.*?)\]/gi, "");
		str = str.replace(/\[\/multipart_td\]/gi, "	");
		/* you may need to add another tag replacement here */
		return str;
	};

	/**
	 * Private helper to replace the div with the HTML response args[0] {String}
	 * element to replace args[1] {function} callback function args[2] {boolean}
	 * should javascript be executed
	 */
	var __replace = function(response, args) {
		/*
		 * Notice that when using yConnect.setForm(formObject, true); the
		 * responseText returned by a callback strips improper tags (e.g)
Hello

		 * will become Hello This method will hack the response text, replacing
		 * your customize tags with proper HTML tags Prerequisite: you need to
		 * map your customize tags to our str replace... {o} object response
		 */
		var str = __hackResponse(response);
		var userCallback = args[1];
		IDEYATECH.util.updateInnerHTML(args[0], str);
		if (typeof userCallback == 'function') {
			try {
				userCallback.call();
			} catch (err) {
			}
		}
		if (args[2])
		  	__evaluateJS(str);

	};

	/**
	 * Private helper to append the response as sibling of the div o.argument[0]
	 * {String} element to append o.argument[1] {function} callback function
	 * o.argument[2] {boolean} should javascript be executed
	 */
	var __append = function(response, args) {
		var str = __hackResponse(response);

		var rootId = __getFirstElementId(str, "tr");
		if (!IDEYATECH.util.isEmpty(rootId) && $('#' + rootId).length == 0) {
			var parent = document.getElementById(args[0]);
			var userCallback = args[1];
			IDEYATECH.util.updateInnerHTML(parent.id, parent.innerHTML + str);
			if (typeof userCallback == 'function') {
				try {
					userCallback.call();
				} catch (err) {
				}
			}
			if (args[2])
	  			__evaluateJS(response);
		} else {
			if (!IDEYATECH.util.isEmpty(rootId))
				args[0] = rootId;
			__replace(response, args);
		}
	};

	/**
	 * Private helper to retrieve the first element id in the string
	 */
	var __getFirstElementId = function(str, tag) {
		var matchExp = new RegExp('<' + tag + '[^>]+id="(.\*?)"[^>]*>', 'img');
		var matches = matchExp.exec(str) || [];
		return matches[1];
	};

	/**
	 * Private helper that will evaluate the ajax response
	 */
	var __evaluateJS = function(response) {
		var script = IDEYATECH.util.extractScripts(response);
		eval(script || '');
	};

	var __failure = function(o) {
		IDEYATECH.util.log('Connection failed :: ' + o.statusText);
	};

	return {

		/**
		 * Failsafe logging of messages to firebug console.
		 * @message - message to log
		 */
		log : function(message) {
		    if (window.console && window.console.log) {
		        console.log(message);
		    }
		},

		/**
		 * Work around for innerHTML - replace value of an element
		 *
		 * @id - id of the element
		 * @replacement - new value that will be placed in the element of the
		 *              given id
		 */
		updateInnerHTML : function(id, replacement) {
			// TODO: Verify if this works in IE when replacing tr element
			$('#' + id).html(replacement);
		},

		/**
		 * Checks if a given variable is empty
		 *
		 * @method isEmpty
		 * @param {object}
		 *            variable to check
		 *
		 */
		isEmpty : function(obj) {
			if (obj == null || typeof (obj) == "undefined" || obj.length == 0
					|| obj == "") {
				return true;
			} else
				return false;
		},
		/**
		 * Any spaces entered by the user will be removed
		 *
		 * @method removeSpaces
		 * @param str -
		 *            string to evaluate
		 */
		removeSpaces : function(str) {
			return str.split(' ').join('');
		},
		/**
		 * Extracts the script from a set of result
		 *
		 * @method extractScripts
		 * @param {String}
		 *            string to extract for script
		 */
		extractScripts : function(result) {
			var matchAll = new RegExp('


<commit_before>const {CompositeDisposable, Emitter} = require('event-kit')
const {compare: comparePoints} = require('./point-helpers')
const Point = require('./point')

module.exports = class CompositeTextDecorationLayer {
  constructor (nextScopeId) {
    this.nextScopeId = nextScopeId
    this.layersByCompositeScopeId = new Map()
    this.layerScopeIdsByCompositeScopeId = new Map()
    this.compositeScopeIdsByLayerAndScopeId = new Map()
    this.layers = new Set()
    this.emitter = new Emitter()
    this.disposables = new CompositeDisposable()
    this.didInvalidateRangeDisposablesByLayer = new Map()
  }

  dispose () {
    this.disposables.dispose()
    this.didInvalidateRangeDisposablesByLayer.clear()
    this.layersByCompositeScopeId.clear()
    this.layerScopeIdsByCompositeScopeId.clear()
    this.compositeScopeIdsByLayerAndScopeId.clear()
    this.layers.clear()
  }

  buildIterator () {
    return new CompositeTextDecorationIterator(this)
  }

  addLayer (layer) {
    this.layers.add(layer)
    if (typeof layer.onDidInvalidateRange === 'function') {
      const disposable = layer.onDidInvalidateRange((range) => {
        this.emitter.emit('did-invalidate-range', range)
      })
      this.disposables.add(disposable)
      this.didInvalidateRangeDisposablesByLayer.set(layer, disposable)
    }
  }

  removeLayer (layer) {
    const didInvalidateRangeDisposable = this.didInvalidateRangeDisposablesByLayer.get(layer)
    if (didInvalidateRangeDisposable) {
      didInvalidateRangeDisposable.dispose()
      this.didInvalidateRangeDisposablesByLayer.delete(layer)
    }

    const compositeScopeIdsByLayerScopeId = this.compositeScopeIdsByLayerAndScopeId.get(layer)
    if (compositeScopeIdsByLayerScopeId) {
      compositeScopeIdsByLayerScopeId.forEach((compositeScopeId) => {
        this.layerScopeIdsByCompositeScopeId.delete(compositeScopeId)
      })
      this.layersByCompositeScopeId.delete(layer)
      this.compositeScopeIdsByLayerAndScopeId.delete(layer)
    }

    this.layers.delete(layer)
  }

  getLayers () {
    return Array.from(this.layers)
  }

  getInvalidatedRanges () {
    let invalidatedRanges = []
    this.layers.forEach((layer) => {
      invalidatedRanges = invalidatedRanges.concat(layer.getInvalidatedRanges())
    })
    return invalidatedRanges
  }

  onDidInvalidateRange (callback) {
    return this.emitter.on('did-invalidate-range', callback)
  }

  classNameForScopeId (scopeId) {
    const layer = this.layersByCompositeScopeId.get(scopeId)
    const layerScopeId = this.layerScopeIdsByCompositeScopeId.get(scopeId)
    return layer.classNameForScopeId(layerScopeId)
  }

  compositeScopeIdForLayerScopeId (layer, scopeId) {
    let compositeScopeIdsByLayerScopeId = this.compositeScopeIdsByLayerAndScopeId.get(layer)
    if (compositeScopeIdsByLayerScopeId == null) {
      compositeScopeIdsByLayerScopeId = new Map()
      this.compositeScopeIdsByLayerAndScopeId.set(layer, compositeScopeIdsByLayerScopeId)
    }

    let compositeScopeId = compositeScopeIdsByLayerScopeId.get(scopeId)
    if (compositeScopeId == null) {
      compositeScopeId = this.nextScopeId
      compositeScopeIdsByLayerScopeId.set(scopeId, compositeScopeId)
      this.layersByCompositeScopeId.set(compositeScopeId, layer)
      this.layerScopeIdsByCompositeScopeId.set(compositeScopeId, scopeId)
      this.nextScopeId += 2
    }

    return compositeScopeId
  }
}

class CompositeTextDecorationIterator {
  constructor (compositeDecorationLayer) {
    this.compositeDecorationLayer = compositeDecorationLayer
    this.iterators = []
    this.iteratorsWithMinimumPosition = []
    this.layersByIterator = new WeakMap()
    this.compositeDecorationLayer.layers.forEach((layer) => {
      const iterator = layer.buildIterator()
      this.iterators.push(iterator)
      this.layersByIterator.set(iterator, layer)
    })
  }

  seek (position) {
    let containingScopeIds = []
    for (let i = 0; i < this.iterators.length; i++) {
      const iterator = this.iterators[i]
      const layer = this.layersByIterator.get(iterator)
      const iteratorScopeIds = iterator.seek(position)
      for (let j = 0; j < iteratorScopeIds.length; j++) {
        const compositeScopeId = this.compositeDecorationLayer.compositeScopeIdForLayerScopeId(layer, iteratorScopeIds[j])
        containingScopeIds.push(compositeScopeId)
      }
    }

    this.iteratorsWithMinimumPosition.length = 0
    return containingScopeIds
  }

  moveToSuccessor () {
    const iteratorsWithMinimumPosition = this.getIteratorsWithMinimumPosition()
    for (let i = 0; i < iteratorsWithMinimumPosition.length; i++) {
      const iterator = iteratorsWithMinimumPosition[i]
      iterator.moveToSuccessor()
    }

    this.iteratorsWithMinimumPosition.length = 0
  }

  getPosition () {
    const iteratorsWithMinimumPosition = this.getIteratorsWithMinimumPosition()
    if (iteratorsWithMinimumPosition.length > 0) {
      return iteratorsWithMinimumPosition[0].getPosition()
    } else {
      return Point.INFINITY
    }
  }

  getCloseScopeIds () {
    const iteratorsWithMinimumPosition = this.getIteratorsWithMinimumPosition()
    let scopeIds = []
    for (let i = 0; i < iteratorsWithMinimumPosition.length; i++) {
      const iterator = iteratorsWithMinimumPosition[i]
      const layer = this.layersByIterator.get(iterator)
      const iteratorScopeIds = iterator.getCloseScopeIds()
      for (let j = 0; j < iteratorScopeIds.length; j++) {
        const compositeScopeId = this.compositeDecorationLayer.compositeScopeIdForLayerScopeId(layer, iteratorScopeIds[j])
        scopeIds.push(compositeScopeId)
      }
    }
    return scopeIds
  }

  getOpenScopeIds () {
    const iteratorsWithMinimumPosition = this.getIteratorsWithMinimumPosition()
    let scopeIds = []
    for (let i = 0; i < iteratorsWithMinimumPosition.length; i++) {
      const iterator = iteratorsWithMinimumPosition[i]
      const layer = this.layersByIterator.get(iterator)
      const iteratorScopeIds = iterator.getOpenScopeIds()
      for (let j = 0; j < iteratorScopeIds.length; j++) {
        const compositeScopeId = this.compositeDecorationLayer.compositeScopeIdForLayerScopeId(layer, iteratorScopeIds[j])
        scopeIds.push(compositeScopeId)
      }
    }
    return scopeIds
  }

  getIteratorsWithMinimumPosition () {
    if (this.iteratorsWithMinimumPosition.length === 0 && this.iterators.length > 0) {
      this.iteratorsWithMinimumPosition.push(this.iterators[0])
      for (let i = 1; i < this.iterators.length; i++) {
        const iterator = this.iterators[i]
        const minimumPosition = this.iteratorsWithMinimumPosition[0].getPosition()
        const comparison = comparePoints(iterator.getPosition(), minimumPosition)
        if (comparison < 0) {
          this.iteratorsWithMinimumPosition.length = 1
          this.iteratorsWithMinimumPosition[0] = iterator
        } else if (comparison === 0) {
          this.iteratorsWithMinimumPosition.push(iterator)
        }
      }
    }

    return this.iteratorsWithMinimumPosition
  }
}
<commit_msg>Store iterator and layer in the same object to avoid map lookups<commit_after>const {CompositeDisposable, Emitter} = require('event-kit')
const {compare: comparePoints} = require('./point-helpers')
const Point = require('./point')

module.exports = class CompositeTextDecorationLayer {
  constructor (nextScopeId) {
    this.nextScopeId = nextScopeId
    this.layersByCompositeScopeId = new Map()
    this.layerScopeIdsByCompositeScopeId = new Map()
    this.compositeScopeIdsByLayerAndScopeId = new Map()
    this.layers = new Set()
    this.emitter = new Emitter()
    this.disposables = new CompositeDisposable()
    this.didInvalidateRangeDisposablesByLayer = new Map()
  }

  dispose () {
    this.disposables.dispose()
    this.didInvalidateRangeDisposablesByLayer.clear()
    this.layersByCompositeScopeId.clear()
    this.layerScopeIdsByCompositeScopeId.clear()
    this.compositeScopeIdsByLayerAndScopeId.clear()
    this.layers.clear()
  }

  buildIterator () {
    return new CompositeTextDecorationIterator(this)
  }

  addLayer (layer) {
    this.layers.add(layer)
    if (typeof layer.onDidInvalidateRange === 'function') {
      const disposable = layer.onDidInvalidateRange((range) => {
        this.emitter.emit('did-invalidate-range', range)
      })
      this.disposables.add(disposable)
      this.didInvalidateRangeDisposablesByLayer.set(layer, disposable)
    }
  }

  removeLayer (layer) {
    const didInvalidateRangeDisposable = this.didInvalidateRangeDisposablesByLayer.get(layer)
    if (didInvalidateRangeDisposable) {
      didInvalidateRangeDisposable.dispose()
      this.didInvalidateRangeDisposablesByLayer.delete(layer)
    }

    const compositeScopeIdsByLayerScopeId = this.compositeScopeIdsByLayerAndScopeId.get(layer)
    if (compositeScopeIdsByLayerScopeId) {
      compositeScopeIdsByLayerScopeId.forEach((compositeScopeId) => {
        this.layerScopeIdsByCompositeScopeId.delete(compositeScopeId)
      })
      this.layersByCompositeScopeId.delete(layer)
      this.compositeScopeIdsByLayerAndScopeId.delete(layer)
    }

    this.layers.delete(layer)
  }

  getLayers () {
    return Array.from(this.layers)
  }

  getInvalidatedRanges () {
    let invalidatedRanges = []
    this.layers.forEach((layer) => {
      invalidatedRanges = invalidatedRanges.concat(layer.getInvalidatedRanges())
    })
    return invalidatedRanges
  }

  onDidInvalidateRange (callback) {
    return this.emitter.on('did-invalidate-range', callback)
  }

  classNameForScopeId (scopeId) {
    const layer = this.layersByCompositeScopeId.get(scopeId)
    const layerScopeId = this.layerScopeIdsByCompositeScopeId.get(scopeId)
    return layer.classNameForScopeId(layerScopeId)
  }

  compositeScopeIdForLayerScopeId (layer, scopeId) {
    let compositeScopeIdsByLayerScopeId = this.compositeScopeIdsByLayerAndScopeId.get(layer)
    if (compositeScopeIdsByLayerScopeId == null) {
      compositeScopeIdsByLayerScopeId = new Map()
      this.compositeScopeIdsByLayerAndScopeId.set(layer, compositeScopeIdsByLayerScopeId)
    }

    let compositeScopeId = compositeScopeIdsByLayerScopeId.get(scopeId)
    if (compositeScopeId == null) {
      compositeScopeId = this.nextScopeId
      compositeScopeIdsByLayerScopeId.set(scopeId, compositeScopeId)
      this.layersByCompositeScopeId.set(compositeScopeId, layer)
      this.layerScopeIdsByCompositeScopeId.set(compositeScopeId, scopeId)
      this.nextScopeId += 2
    }

    return compositeScopeId
  }
}

class CompositeTextDecorationIterator {
  constructor (compositeDecorationLayer) {
    this.compositeDecorationLayer = compositeDecorationLayer
    this.iterators = []
    this.iteratorsWithMinimumPosition = []
    this.compositeDecorationLayer.layers.forEach((layer) => {
      const iterator = layer.buildIterator()
      this.iterators.push({iterator, layer})
    })
  }

  seek (position) {
    let containingScopeIds = []
    for (let i = 0; i < this.iterators.length; i++) {
      const {iterator, layer} = this.iterators[i]
      const iteratorScopeIds = iterator.seek(position)
      for (let j = 0; j < iteratorScopeIds.length; j++) {
        const compositeScopeId = this.compositeDecorationLayer.compositeScopeIdForLayerScopeId(layer, iteratorScopeIds[j])
        containingScopeIds.push(compositeScopeId)
      }
    }

    this.iteratorsWithMinimumPosition.length = 0
    return containingScopeIds
  }

  moveToSuccessor () {
    const iteratorsWithMinimumPosition = this.getIteratorsWithMinimumPosition()
    for (let i = 0; i < iteratorsWithMinimumPosition.length; i++) {
      const {iterator} = iteratorsWithMinimumPosition[i]
      iterator.moveToSuccessor()
    }

    this.iteratorsWithMinimumPosition.length = 0
  }

  getPosition () {
    const iteratorsWithMinimumPosition = this.getIteratorsWithMinimumPosition()
    if (iteratorsWithMinimumPosition.length > 0) {
      const {iterator} = iteratorsWithMinimumPosition[0]
      return iterator.getPosition()
    } else {
      return Point.INFINITY
    }
  }

  getCloseScopeIds () {
    const iteratorsWithMinimumPosition = this.getIteratorsWithMinimumPosition()
    let scopeIds = []
    for (let i = 0; i < iteratorsWithMinimumPosition.length; i++) {
      const {iterator, layer} = iteratorsWithMinimumPosition[i]
      const iteratorScopeIds = iterator.getCloseScopeIds()
      for (let j = 0; j < iteratorScopeIds.length; j++) {
        const compositeScopeId = this.compositeDecorationLayer.compositeScopeIdForLayerScopeId(layer, iteratorScopeIds[j])
        scopeIds.push(compositeScopeId)
      }
    }
    return scopeIds
  }

  getOpenScopeIds () {
    const iteratorsWithMinimumPosition = this.getIteratorsWithMinimumPosition()
    let scopeIds = []
    for (let i = 0; i < iteratorsWithMinimumPosition.length; i++) {
      const {iterator, layer} = iteratorsWithMinimumPosition[i]
      const iteratorScopeIds = iterator.getOpenScopeIds()
      for (let j = 0; j < iteratorScopeIds.length; j++) {
        const compositeScopeId = this.compositeDecorationLayer.compositeScopeIdForLayerScopeId(layer, iteratorScopeIds[j])
        scopeIds.push(compositeScopeId)
      }
    }
    return scopeIds
  }

  getIteratorsWithMinimumPosition () {
    if (this.iterators.length <= 1) {
      return this.iterators
    } else if (this.iteratorsWithMinimumPosition.length === 0) {
      this.iteratorsWithMinimumPosition.push(this.iterators[0])
      for (let i = 1; i < this.iterators.length; i++) {
        const {iterator} = this.iterators[i]
        const minimumPosition = this.iteratorsWithMinimumPosition[0].iterator.getPosition()
        const comparison = comparePoints(iterator.getPosition(), minimumPosition)
        if (comparison < 0) {
          this.iteratorsWithMinimumPosition.length = 1
          this.iteratorsWithMinimumPosition[0] = this.iterators[i]
        } else if (comparison === 0) {
          this.iteratorsWithMinimumPosition.push(this.iterators[i])
        }
      }
    }

    return this.iteratorsWithMinimumPosition
  }
}
<|endoftext|>


<commit_before>function restoreLogin() {
    $('.u').hide();
    $('#login').slideDown(500);
}

$('#login').submit(function(ev) {
    $('#login').slideUp(100);

    var ws = new WebSocket("ws://" + document.location.host + "/u", "prittorrent-ui-1");
    var send = function(obj) {
	var data = JSON.stringify(obj);
	ws.send(data);
    };

    ws.onopen = function() {
	send({ user: $('#user').val(),
	       password: $('#password').val()
	     });
	var app = new Application(send);
	ws.onmessage = function(message) {
	    var msg = JSON.parse(message.data);
	    app.recv(msg);
	};
    };
    ws.onclose = restoreLogin;
    ws.onerror = restoreLogin;

    return false;
});

function Application(send) {
    this.send = send;
    this.userFeeds = new UserFeedsView(send);
    $('.u').fadeIn(500);
}

Application.prototype = {};
Application.prototype.recv = function(msg) {
    if (msg.feeds)
	this.userFeeds.setFeeds(msg.feeds);
};

function UserFeedsView(send) {
    this.send = send;
    this.feeds = [];
    this.currentFeed = null;
    this.feedView = null;
    this.ul = $('#feedlist');
    this.render();

    var that = this;
    $('#addfeed').click(function() {
	that.currentFeed = null;
	delete that.feedView;
	/* Cause AddFeedView to be created */
	that.render();
    });
}

UserFeedsView.prototype = {};
UserFeedsView.prototype.render = function() {
    var that = this;
    this.ul.empty();
    this.feeds.forEach(function(feed) {
	var li = $('

');
	li.text(feed);
	if (that.currentFeed === feed)
	    li.addClass('selected');
	li.click(function() {
	    that.setCurrentFeed(feed);
	});
	that.ul.append(li);
    });

    /* Do we need to create a feedView? */
    if (!this.feedView) {
	if (this.currentFeed) {
	} else {
	    /* No currentFeed, display addfeed dialog */
	    this.feedView = new AddFeedView(this, this.send);
	}
    }
};
UserFeedsView.prototype.setFeeds = function(feeds) {
    this.feeds = feeds;
    this.render();
};

function AddFeedView(userfeeds, send) {
    $('#addfeed').show();
    $('#feeddetails').hide();

    $('#addfeedform').submit(function(e) {
	e.preventDefault();

	var input = $('#addfeedurl');
	console.log("#addfeedurl", input, input.val())
	send({ addFeed: input.val() });
	setTimeout(function() {
	    input.val("");
	}, 10);
    });
}
<commit_msg>rm obsolete u.js<commit_after><|endoftext|>