<commit_before>import Vector from './vector'
import events1 from './centralized-events-1'
import events2 from './centralized-events-2'

import animationControlsMixin from './animation-controls-mixin'

const $ = window.$
const anime = window.anime
const events3 = window.events3

const colors = ['#3f51b5', '#ffc107', '#ff5722', '#795548', '#00BCD4', '#ff9800']

class TwoDViz {

  constructor({container,
               width, height,
               minX, maxX,
               minY, maxY,
               initialCoords, stagedInitialCoords,
               events, eventsSampleFactor,
               showForcesAndArrows, showForceStep, showStage}) {
    this.el = container;
    this.width = width
    this.height = height
    this.minX = minX
    this.maxX = maxX
    this.minY = minY
    this.maxY = maxY
    this.showForcesAndArrows = showForcesAndArrows

    this.stagedInitialCoords = stagedInitialCoords
                               .map(coords => coords.map(c => this.toSVGCoord(c)))
    this.circles = new Array(initialCoords.length)

    this.events = events.map(e => {

      let forces = {}
      let totalForce = []
      let coords = []
      if (this.showForcesAndArrows) {
        forces = e.forces.map(f => {
          return {from: f.from, vector: this.toSVGCoord(f.vector)}
        })
        totalForce = this.toSVGCoord(Vector.add(e.x_i, e.totalForce))
        coords = e.coords.map(c => this.toSVGCoord(c))
      }

      return {
        i: e.i,
        x_i: this.toSVGCoord(e.x_i),
        x_i_next: this.toSVGCoord(e.x_i_next),
        totalForce,
        forces,
        coords,
        stage: e.stage
      }
    })

    this.eventsSampleFactor = eventsSampleFactor
    this.nextEventIndex = 0
    this.currentStage = -1
    this.coordsPerStage = stagedInitialCoords[0].length
    this.length = this.events.length

    for (let key of Object.keys(animationControlsMixin)) {
      this[key] = animationControlsMixin[key]
    }

    this.initControls(container)

    this.showForceStep = showForceStep
    this.showStage = showStage
    if (showStage) {
      this.renderStage()
    }
    if (showForcesAndArrows) {
      this.renderLegend()
    }

  }

  renderLegend() {
    let parent = $(this.el).find('.anim-control')

    let items = [
      ['Individual Forces', '#F44336'],
      ['Total Force', '#FFEB3B'],
      ['Force Step', '#3f51b5']
    ]

    items.forEach(([label, color]) => {
      let item = $("<div>").addClass('legend-item')
                           .append($("<div>").addClass('legend-color').css('background', color))
                           .append($("<div>").html(label))
      parent.append(item)
    })
  }

  renderStage() {
    this.stageView = $("<div>").addClass('anim-stage').html("Stage 1")
    let parent = $(this.el).find('.anim-control')
    parent.append(this.stageView)
  }

  updateStageView(stage) {
    this.stageView.html("Stage " + (stage + 1))
  }

  reset() {
    this.nextEventIndex = 0
    this.currentStage = -1
    this.empty()
    this.render()
    return this
  }

  getNextEvent() {
    const event = this.events[this.nextEventIndex]
    this.nextEventIndex += this.eventsSampleFactor
    return event
  }

  async play() {

    while (this.nextEventIndex < (this.length - 4)) {
      if (this.isPaused) {
        return
      }
      const event = this.getNextEvent()
      if (event.stage !== this.currentStage) {
        this.currentStage = event.stage
        if (this.showStage) {
          this.updateStageView(this.currentStage)
        }
        await this.moveCoordsToInitialPositions(this.currentStage)
      }
      await this.next(event)
    }
    this.showReplayButton()
  }

  pause() {
    this.isPaused = true
  }

  async next(event) {
    if (this.nextEventIndex % 100 === 0) {
      console.info('Event: ', this.nextEventIndex)
    }
    if (this.showForcesAndArrows) {
      const endPoints = event.forces.map(({from, vector}) => {
        return [event.x_i, event.coords[from]]
      })
      await this.drawLines(endPoints, {cls: 'force', stroke: '#F44336', showArrow: true})
      await this.drawLines([[event.x_i, event.totalForce]], {cls: 'force', stroke: '#FFEB3B', showArrow: true})
    }
    if (this.showForceStep) {
      await this.drawLines([[event.x_i, event.x_i_next]], {cls: 'force-step', stroke: colors[event.i % 4], showArrow: this.showForcesAndArrows})
    }
    await this.movePoint(event.i, event.x_i_next)

    return new Promise((resolve, _reject) => {
      setTimeout(() => {
        if (this.showForcesAndArrows) {
          this.removeForces()
        }
        resolve(true)
      }, 10)
    })
  }

  removeForces() {
    $(this.el).find('.force').remove()
  }

  render() {
    this.initializeSvg()
    return this
  }

  empty() {
    this.svg.remove()
    if (this.showStage) {
      this.updateStageView(0)
    }
  }

  async moveCoordsToInitialPositions(stage) {
    let coords = this.stagedInitialCoords[stage]
    let promises = []
    let startIndex = stage * this.coordsPerStage
    for (let j = 0; j < this.coordsPerStage; j++) {
      let i = startIndex + j
      this.circles[i] = this.drawPointAt([0, 0], i)
      let p = this.movePoint(i, coords[j])
      promises.push(p)
      await this.delay(40)
    }
    return Promise.all(promises)
  }

  delay(t) {
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve(), t)
    })
  }

  movePoint(index, [cx, cy]) {

    return new Promise((resolve, reject) => {
      let circle = this.circles[index]
      $(circle).animate(
        {cx, cy},
        {
          duration: 40,
          step: function(v1) {$(this).attr('cx', v1)},
          complete: function() {
            resolve(circle)
          }
        }
      )
    })
  }

  toSVGCoord(coord) {
    const [x, y] = coord

    const rangeX = (this.maxX - this.minX)
    const svgX = 5 + 0.97*(x-this.minX)*this.width/rangeX

    const rangeY = (this.maxY - this.minY)
    const svgY = 5 + 0.97*(this.maxY - y)*this.height/rangeY

    return [svgX, svgY]
  }

  drawPointAt([cx, cy], index) {
    const circle = this.createSvgEl('circle', {
      cx,
      cy,
      r: 3,
      fill: colors[index % 6]
    })
    this.svg.appendChild(circle)
    return circle
  }

  drawLines(endPoints, options) {
    let {cls, stroke, showArrow} = options
    return new Promise((resolve, _reject) => {
      let lines = []
      let targetProps = {}
      let currentProps = {}
      endPoints.forEach(([[x1, y1], [x2, y2]], i) => {
        let line = this.createSvgEl('line', {
            x1,
            y1,
            x2: x1,
            y2: y1,
            stroke,
            'class': cls,
            'stroke-width': 1,

        })
        if (showArrow) {
          line.setAttribute('marker-end', 'url(#Triangle)')
        }
        this.svg.appendChild(line)
        lines.push(line)

        currentProps[i * 2] = x1
        currentProps[i * 2 + 1] = y1
        targetProps[i * 2] = x2
        targetProps[i * 2 + 1] = y2
      })

      const lineCount = endPoints.length

      let animationProps = {
        duration: 20 * (this.length - this.nextEventIndex) / this.length,
        easing: 'easeOutQuad',
        update: function() {
          for (let i = 0; i < lineCount; i++) {
            let line = lines[i]
            line.setAttribute('x2', currentProps[i * 2])
            line.setAttribute('y2', currentProps[i * 2 + 1])
          }
        },
        complete: function() {
          resolve(true)
        }
      }

      anime(Object.assign({targets: currentProps},
                          targetProps,
                          animationProps))
    })
  }

  // svg stuff

  initializeSvg() {
    this.svg = this.createSvgEl('svg', {
        height: this.height,
        width: this.width
    });
    var defs = this.getTriangleMarkerDefinition();
    this.svg.appendChild(defs);
    this.el.appendChild(this.svg);
  }

  createSvgEl(type, attrs) {
    var el = document.createElementNS('http://www.w3.org/2000/svg', type);
    attrs = attrs || {};
    for (let key of Object.keys(attrs)) {
      el.setAttribute(key, attrs[key]);
    }
    return el;
  }

  getTriangleMarkerDefinition() {
    let marker = document.createElementNS('http://www.w3.org/2000/svg', 'marker')
    const markerAttrs = {
        'id': 'Triangle',
        'viewBox': '0 0 10 10',
        'refX': '0',
        'refY': '5',
        'markerWidth': '6',
        'markerHeight': '6',
        'orient': 'auto'
    }
    for (let key of Object.keys(markerAttrs)) {
      marker.setAttribute(key, markerAttrs[key])
    }

    let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    path.setAttribute('d', 'M0,0 L10,5 L0,10 z');
    marker.appendChild(path);

    let defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs')
    defs.appendChild(marker);
    return defs
  }

}

// Configure visualization objects

let width = window.innerWidth * 0.7
let height = window.innerHeight * 0.8

let initialCoords1 = [
  [0, 0],
  [4, 0],
  [10, 0],
  [7, 9]
]

let twoD1 = new TwoDViz({
  container: document.getElementById('two-d-viz-1'),
  width,
  height,
  minX: -0.2,
  maxX: 10.2,
  minY: -0.2,
  maxY: 9.2,
  initialCoords: initialCoords1,
  stagedInitialCoords: [initialCoords1],
  events: events1.events,
  eventsSampleFactor: 1,
  showForcesAndArrows: true,
  showForceStep: true,
  showStage: false,
})

twoD1.render()

let initialCoords2 = [
  [0, 0],
  [0, 0],
  [0, 0],
  [0, 0]
]

let twoD2 = new TwoDViz({
  container: document.getElementById('two-d-viz-2'),
  width,
  height,
  minX: -4.3,
  maxX: 5.2,
  minY: -4,
  maxY: 4.8,
  initialCoords: initialCoords2,
  stagedInitialCoords: [initialCoords2],
  events: events2.events,
  eventsSampleFactor: 1,
  showForcesAndArrows: false,
  showForceStep: true,
  showStage: false,
})

twoD2.render()

events3.initial_coords = events3.initial_coords.map(c => c.slice(0, 2))
events3.staged_initial_coords = events3.staged_initial_coords.map(coords => coords.map(c => c.slice(0, 2)))
events3.events = events3.events.map(e => {
  e.forces = []
  e.totalForce = [0, 0]
  e.x_i = e.x_i.slice(0, 2)
  e.x_i_next = e.x_i_next.slice(0, 2)
  e.coords = []
  return e
})

let twoD3 = new TwoDViz({
  container: document.getElementById('two-d-viz-3'),
  width,
  height,
  minX: events3.min_x,
  maxX: events3.max_x,
  minY: events3.min_y,
  maxY: events3.max_y,
  initialCoords: events3.initial_coords,
  stagedInitialCoords: events3.staged_initial_coords,
  events: events3.events,
  eventsSampleFactor: 3,
  showForcesAndArrows: false,
  showForceStep: false,
  showStage: true
})

twoD3.render()
window.t = twoD3

window.events1 = events1
window.events2 = events2
<commit_msg>Visualization: Customize speed for each case<commit_after>import Vector from './vector'
import events1 from './centralized-events-1'
import events2 from './centralized-events-2'

import animationControlsMixin from './animation-controls-mixin'

const $ = window.$
const anime = window.anime
const events3 = window.events3

const colors = ['#3f51b5', '#ffc107', '#ff5722', '#795548', '#00BCD4', '#ff9800']

class TwoDViz {

  constructor({container,
               width, height,
               minX, maxX,
               minY, maxY,
               initialCoords, stagedInitialCoords,
               events, eventsSampleFactor,
               showForcesAndArrows, showForceStep, showStage,
               eventAnimationDuration, gapBetweenEventAnimations}) {
    this.el = container;
    this.width = width
    this.height = height
    this.minX = minX
    this.maxX = maxX
    this.minY = minY
    this.maxY = maxY
    this.showForcesAndArrows = showForcesAndArrows
    this.showForceStep = showForceStep
    this.showStage = showStage
    this.eventAnimationDuration = eventAnimationDuration
    this.gapBetweenEventAnimations = gapBetweenEventAnimations

    this.stagedInitialCoords = stagedInitialCoords
                               .map(coords => coords.map(c => this.toSVGCoord(c)))
    this.circles = new Array(initialCoords.length)

    this.events = events.map(e => {

      let forces = {}
      let totalForce = []
      let coords = []
      if (this.showForcesAndArrows) {
        forces = e.forces.map(f => {
          return {from: f.from, vector: this.toSVGCoord(f.vector)}
        })
        totalForce = this.toSVGCoord(Vector.add(e.x_i, e.totalForce))
        coords = e.coords.map(c => this.toSVGCoord(c))
      }

      return {
        i: e.i,
        x_i: this.toSVGCoord(e.x_i),
        x_i_next: this.toSVGCoord(e.x_i_next),
        totalForce,
        forces,
        coords,
        stage: e.stage
      }
    })

    this.eventsSampleFactor = eventsSampleFactor
    this.nextEventIndex = 0
    this.currentStage = -1
    this.coordsPerStage = stagedInitialCoords[0].length
    this.length = this.events.length

    for (let key of Object.keys(animationControlsMixin)) {
      this[key] = animationControlsMixin[key]
    }

    this.initControls(container)

    if (showStage) {
      this.renderStage()
    }
    if (showForcesAndArrows) {
      this.renderLegend()
    }

  }

  renderLegend() {
    let parent = $(this.el).find('.anim-control')

    let items = [
      ['Individual Forces', '#F44336'],
      ['Total Force', '#FFEB3B'],
      ['Force Step', '#3f51b5']
    ]

    items.forEach(([label, color]) => {
      let item = $("<div>").addClass('legend-item')
                           .append($("<div>").addClass('legend-color').css('background', color))
                           .append($("<div>").html(label))
      parent.append(item)
    })
  }

  renderStage() {
    this.stageView = $("<div>").addClass('anim-stage').html("Stage 1")
    let parent = $(this.el).find('.anim-control')
    parent.append(this.stageView)
  }

  updateStageView(stage) {
    this.stageView.html("Stage " + (stage + 1))
  }

  reset() {
    this.nextEventIndex = 0
    this.currentStage = -1
    this.empty()
    this.render()
    return this
  }

  getNextEvent() {
    const event = this.events[this.nextEventIndex]
    this.nextEventIndex += this.eventsSampleFactor
    return event
  }

  async play() {

    while (this.nextEventIndex < (this.length - 4)) {
      if (this.isPaused) {
        return
      }
      const event = this.getNextEvent()
      if (event.stage !== this.currentStage) {
        this.currentStage = event.stage
        if (this.showStage) {
          this.updateStageView(this.currentStage)
        }
        await this.moveCoordsToInitialPositions(this.currentStage)
      }
      await this.next(event)
    }
    this.showReplayButton()
  }

  pause() {
    this.isPaused = true
  }

  async next(event) {
    if (this.nextEventIndex % 100 === 0) {
      console.info('Event: ', this.nextEventIndex)
    }
    if (this.showForcesAndArrows) {
      const endPoints = event.forces.map(({from, vector}) => {
        return [event.x_i, event.coords[from]]
      })
      await this.drawLines(endPoints, {cls: 'force', stroke: '#F44336', showArrow: true})
      await this.drawLines([[event.x_i, event.totalForce]], {cls: 'force', stroke: '#FFEB3B', showArrow: true})
    }
    if (this.showForceStep) {
      await this.drawLines([[event.x_i, event.x_i_next]], {cls: 'force-step', stroke: colors[event.i % 4], showArrow: this.showForcesAndArrows})
    }
    await this.movePoint(event.i, event.x_i_next)

    return new Promise((resolve, _reject) => {
      setTimeout(() => {
        if (this.showForcesAndArrows) {
          this.removeForces()
        }
        resolve(true)
      }, 10)
    })
  }

  removeForces() {
    $(this.el).find('.force').remove()
  }

  render() {
    this.initializeSvg()
    return this
  }

  empty() {
    this.svg.remove()
    if (this.showStage) {
      this.updateStageView(0)
    }
  }

  async moveCoordsToInitialPositions(stage) {
    let coords = this.stagedInitialCoords[stage]
    let promises = []
    let startIndex = stage * this.coordsPerStage
    for (let j = 0; j < this.coordsPerStage; j++) {
      let i = startIndex + j
      this.circles[i] = this.drawPointAt([0, 0], i)
      let p = this.movePoint(i, coords[j], 300)
      await this.delay(150)
      promises.push(p)
    }
    await this.delay(500)
    return Promise.all(promises)
  }

  delay(t) {
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve(), t)
    })
  }

  movePoint(index, [cx, cy], duration) {
    duration = duration || this.eventAnimationDuration
    return new Promise((resolve, reject) => {
      let circle = this.circles[index]
      $(circle).animate(
        {cx, cy},
        {
          duration: duration,
          step: function(v1) {$(this).attr('cx', v1)},
          complete: function() {
            resolve(circle)
          }
        }
      )
    })
  }

  toSVGCoord(coord) {
    const [x, y] = coord

    const rangeX = (this.maxX - this.minX)
    const svgX = 5 + 0.97*(x-this.minX)*this.width/rangeX

    const rangeY = (this.maxY - this.minY)
    const svgY = 5 + 0.97*(this.maxY - y)*this.height/rangeY

    return [svgX, svgY]
  }

  drawPointAt([cx, cy], index) {
    const circle = this.createSvgEl('circle', {
      cx,
      cy,
      r: 3,
      fill: colors[index % 6]
    })
    this.svg.appendChild(circle)
    return circle
  }

  drawLines(endPoints, options) {
    let {cls, stroke, showArrow} = options
    return new Promise((resolve, _reject) => {
      let lines = []
      let targetProps = {}
      let currentProps = {}
      endPoints.forEach(([[x1, y1], [x2, y2]], i) => {
        let line = this.createSvgEl('line', {
            x1,
            y1,
            x2: x1,
            y2: y1,
            stroke,
            'class': cls,
            'stroke-width': 1,

        })
        if (showArrow) {
          line.setAttribute('marker-end', 'url(#Triangle)')
        }
        this.svg.appendChild(line)
        lines.push(line)

        currentProps[i * 2] = x1
        currentProps[i * 2 + 1] = y1
        targetProps[i * 2] = x2
        targetProps[i * 2 + 1] = y2
      })

      const lineCount = endPoints.length

      let animationProps = {
        duration: 20 * (this.length - this.nextEventIndex) / this.length,
        easing: 'easeOutQuad',
        update: function() {
          for (let i = 0; i < lineCount; i++) {
            let line = lines[i]
            line.setAttribute('x2', currentProps[i * 2])
            line.setAttribute('y2', currentProps[i * 2 + 1])
          }
        },
        complete: function() {
          resolve(true)
        }
      }

      anime(Object.assign({targets: currentProps},
                          targetProps,
                          animationProps))
    })
  }

  // svg stuff

  initializeSvg() {
    this.svg = this.createSvgEl('svg', {
        height: this.height,
        width: this.width
    });
    var defs = this.getTriangleMarkerDefinition();
    this.svg.appendChild(defs);
    this.el.appendChild(this.svg);
  }

  createSvgEl(type, attrs) {
    var el = document.createElementNS('http://www.w3.org/2000/svg', type);
    attrs = attrs || {};
    for (let key of Object.keys(attrs)) {
      el.setAttribute(key, attrs[key]);
    }
    return el;
  }

  getTriangleMarkerDefinition() {
    let marker = document.createElementNS('http://www.w3.org/2000/svg', 'marker')
    const markerAttrs = {
        'id': 'Triangle',
        'viewBox': '0 0 10 10',
        'refX': '0',
        'refY': '5',
        'markerWidth': '6',
        'markerHeight': '6',
        'orient': 'auto'
    }
    for (let key of Object.keys(markerAttrs)) {
      marker.setAttribute(key, markerAttrs[key])
    }

    let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    path.setAttribute('d', 'M0,0 L10,5 L0,10 z');
    marker.appendChild(path);

    let defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs')
    defs.appendChild(marker);
    return defs
  }

}

// Configure visualization objects

let width = window.innerWidth * 0.7
let height = window.innerHeight * 0.8

let initialCoords1 = [
  [0, 0],
  [4, 0],
  [10, 0],
  [7, 9]
]

let twoD1 = new TwoDViz({
  container: document.getElementById('two-d-viz-1'),
  width,
  height,
  minX: -0.2,
  maxX: 10.2,
  minY: -0.2,
  maxY: 9.2,
  initialCoords: initialCoords1,
  stagedInitialCoords: [initialCoords1],
  events: events1.events,
  eventsSampleFactor: 1,
  showForcesAndArrows: true,
  showForceStep: true,
  showStage: false,
  eventAnimationDuration: 600,
  gapBetweenEventAnimations: 60,
})

twoD1.render()

let initialCoords2 = [
  [0, 0],
  [0, 0],
  [0, 0],
  [0, 0]
]

let twoD2 = new TwoDViz({
  container: document.getElementById('two-d-viz-2'),
  width,
  height,
  minX: -4.3,
  maxX: 5.2,
  minY: -4,
  maxY: 4.8,
  initialCoords: initialCoords2,
  stagedInitialCoords: [initialCoords2],
  events: events2.events,
  eventsSampleFactor: 1,
  showForcesAndArrows: false,
  showForceStep: true,
  showStage: false,
  eventAnimationDuration: 300,
  gapBetweenEventAnimations: 30,
})

twoD2.render()

events3.initial_coords = events3.initial_coords.map(c => c.slice(0, 2))
events3.staged_initial_coords = events3.staged_initial_coords.map(coords => coords.map(c => c.slice(0, 2)))
events3.events = events3.events.map(e => {
  e.forces = []
  e.totalForce = [0, 0]
  e.x_i = e.x_i.slice(0, 2)
  e.x_i_next = e.x_i_next.slice(0, 2)
  e.coords = []
  return e
})

let twoD3 = new TwoDViz({
  container: document.getElementById('two-d-viz-3'),
  width,
  height,
  minX: events3.min_x,
  maxX: events3.max_x,
  minY: events3.min_y,
  maxY: events3.max_y,
  initialCoords: events3.initial_coords,
  stagedInitialCoords: events3.staged_initial_coords,
  events: events3.events,
  eventsSampleFactor: 3,
  showForcesAndArrows: false,
  showForceStep: false,
  showStage: true,
  eventAnimationDuration: 60,
  gapBetweenEventAnimations: 10,
})

twoD3.render()
window.t = twoD3

window.events1 = events1
window.events2 = events2
<|endoftext|>


<commit_before>const roles = require('../../config/roles'),
    table = require('text-table'),
    Discord = require('discord.js'),
    moment = require('moment');

moment.locale('de');

exports.run = (bot, message, args) => {
    let text = '**Nutzer ohne Rollen:**';

    let tableContent = ['Tag', 'ID', 'Joined', '-----', '------------------', '------------------'];

    bot.server.fetchMembers().then(guild => {
        guild.members.filter(member => {
            return member.roles.size <= 1;
        }).sort((a, b) => {
            return moment(a.joinedAt) - moment(b.joinedAt);
        }).forEach(member => {
            tableContent.push(member.user.tag, member.id, `${moment(member.joinedAt).format('L LT')} (${moment(member.joinedAt).fromNow()})`);
        });

        let commandsTable = [],
            columns = 3;
        for (let ix = 0; ix < tableContent.length; ix += columns)
            commandsTable.push(tableContent.slice(ix, ix + columns));

        text += '```' + table(commandsTable, {hsep: '    '}) + '```';

        console.log(text);
        message.channel.send(text);
    });
};

exports.config = {
    aliases: ['nr'],
    server: true,
    role: roles.moderator
};

exports.help = {
    name: 'noroles',
    description: 'Zeigt alle Mitglieder des Servers ohne Rolle an.',
    usage: ['!noroles']
};<commit_msg>split messages after 15 rows<commit_after>const roles = require('../../config/roles'),
    table = require('text-table'),
    Discord = require('discord.js'),
    moment = require('moment');

moment.locale('de');

exports.run = (bot, message, args) => {
    let text = '**Nutzer ohne Rollen:**';

    let tableContent = ['Tag', 'ID', 'Joined', '-----', '------------------', '------------------'];

    bot.server.fetchMembers().then(guild => {
        guild.members.filter(member => {
            return member.roles.size <= 1;
        }).sort((a, b) => {
            return moment(a.joinedAt) - moment(b.joinedAt);
        }).forEach(member => {
            tableContent.push(member.user.tag, member.id, `${moment(member.joinedAt).format('L LT')} (${moment(member.joinedAt).fromNow()})`);
        });

        let commandsTable = [],
            columns = 3;
        for (let ix = 0; ix < tableContent.length; ix += columns)
            commandsTable.push(tableContent.slice(ix, ix + columns));

        text += '```' + table(commandsTable, {hsep: '    '}) + '```';

        let rows = text.split(/\r?\n/);

        let messages = [];

        let curMessage = [];

        for(let i = 1; i < rows.length + 1; i++) {
            curMessage.push(rows[i - 1]);

            if((i % 15) === 0) {
                messages.push(curMessage);
                curMessage = [];
            }
        }

        messages.push(curMessage);

        messages.forEach(msg => message.channel.send(msg));
    });
};

exports.config = {
    aliases: ['nr'],
    server: true,
    role: roles.moderator
};

exports.help = {
    name: 'noroles',
    description: 'Zeigt alle Mitglieder des Servers ohne Rolle an.',
    usage: ['!noroles']
};<|endoftext|>


<commit_before>const Command = require("../base/Command");
const nodeFetch = require("node-fetch");
const {promisify, inspect} = require("util");      // eslint-disable-line no-unused-vars

class MyCharacter extends Command {
    constructor(Bot) {
        super(Bot, {
            name: "mycharacter",
            category: "SWGoH",
            enabled: true,
            aliases: ["mc", "mychar"],
            permissions: ["EMBED_LINKS"],
            permLevel: 0,
            flags: {
                ships: {
                    aliases: ["s", "ship"]
                }
            }
        });
    }

    async run(Bot, message, args, options) {
        const {allyCode, searchChar, err} = await super.getUserAndChar(message, args);

        if (err) {
            return super.error(message, err);
        }

        let chars = [];
        if (!options.flags.ships) {
            chars = Bot.findChar(searchChar, Bot.characters);
        }
        if (!chars.length) {
            chars = Bot.findChar(searchChar, Bot.ships, true);
        }
        let character;
        if (!searchChar) {
            return super.error(message, message.language.get("BASE_SWGOH_MISSING_CHAR"));
        }

        if (chars.length === 0) {
            return super.error(message, message.language.get("BASE_SWGOH_NO_CHAR_FOUND", searchChar));
        } else if (chars.length > 1) {
            const charL = [];
            const charS = chars.sort((p, c) => p.name > c.name ? 1 : -1);
            charS.forEach(c => {
                charL.push(c.name);
            });
            return super.error(message, message.language.get("BASE_SWGOH_CHAR_LIST", charL.join("\n")));
        } else {
            character = chars[0];
        }

        const msg = await message.channel.send("Please wait while I look up your profile.");

        const cooldown = await Bot.getPlayerCooldown(message.author.id);
        let pName;
        let player = null;
        try {
            player = await Bot.swgohAPI.unitStats(allyCode, cooldown);
            if (Array.isArray(player)) player = player[0];
        } catch (e) {
            console.error(e);
            return super.error(message, Bot.codeBlock(e.message), {
                title: message.language.get("BASE_SOMETHING_BROKE"),
                footer: "Please try again in a bit."
            });
        }

        if (player && player.stats) {
            pName = player.name;
        }
        const footer = Bot.updatedFooter(player.updated, message, "player", cooldown);

        let thisChar = player.stats.filter(c => c.unit.defId === character.uniqueName);
        if (thisChar.length && Array.isArray(thisChar)) thisChar = thisChar[0];

        if (thisChar && !Array.isArray(thisChar)) {
            thisChar.unit = await Bot.swgohAPI.langChar(thisChar.unit, message.guildSettings.swgohLanguage);

            const stats = thisChar.stats;
            thisChar = thisChar.unit;
            const isShip = thisChar.crew.length ? true : false;

            let charImg;
            const pat = Bot.getPatronUser(message.author.id);
            if (pat && pat.amount_cents >= 100) {
                // For now, limit it to Patrons
                const charArr = [thisChar.defId];
                charArr.push(thisChar.rarity);
                charArr.push(thisChar.level);
                charArr.push(thisChar.gear);
                charArr.push(thisChar.skills.filter(s => s.isZeta && s.tier == s.tiers).length);  // Zeta count
                charArr.push(thisChar.relic.currentTier);  // Relic count
                charArr.push(character.side);

                try {
                    await nodeFetch(Bot.config.imageServIP_Port + "/char/" + charArr.join("/"))
                        .then(response => response.buffer())
                        .then(image => {
                            charImg = image;
                        });
                } catch (e) {
                    console.log("ImageFetch in myCharacter broke: " + e);
                }
            }
            const abilities = {
                basic: [],
                special: [],
                leader: [],
                unique: [],
                contract: [],
                crew: [],
                hardware: []
            };

            let gearStr;
            if (!isShip) {
                gearStr = ["   [0]  [3]", "[1]       [4]", "   [2]  [5]"].join("\n");
                thisChar.equipped.forEach(e => {
                    gearStr = gearStr.replace(e.slot, "X");
                });
                gearStr = gearStr.replace(/[0-9]/g, "  ");
                gearStr = Bot.expandSpaces(gearStr);
            }
            thisChar.skills.forEach(a => {
                a.type = a.id.split("_")[0].replace("skill", "").toProperCase();
                if (a.tier === 8 || (a.tier === 3 && (a.type === "Contract" || a.type === "Hardware"))) {
                    if (a.isZeta) {
                        // Maxed Zeta ability
                        a.tier = "Max ✦";
                    } else if (isShip) {
                        a.tier = "Max";
                    } else {
                        // Maxed Omega ability
                        a.tier = "Max ⭓";
                    }
                } else {
                    // Unmaxed ability
                    a.tier = "Lvl " + a.tier;
                }
                try {
                    abilities[`${a.type ? a.type.toLowerCase() : a.defId.toLowerCase()}`].push(`\`${a.tier} [${a.type ? a.type.charAt(0) : a.defId.charAt(0)}]\` ${a.nameKey}`);
                } catch (e) {
                    console.log("ERROR[MC]: bad ability type: " + inspect(a));
                }
            });
            const abilitiesOut = abilities.basic
                .concat(abilities.special)
                .concat(abilities.leader)
                .concat(abilities.unique)
                .concat(abilities.crew)
                .concat(abilities.contract)
                .concat(abilities.hardware);

            const statNames = {
                "Primary Attributes" : [ "Strength", "Agility", "Intelligence" ],
                "General": [ "Health", "Protection", "Speed", "Critical Damage", "Potency", "Tenacity", "Health Steal", ],
                "Physical Offense": [ "Physical Damage", "Physical Critical Chance", "Armor Penetration", "Accuracy" ],
                "Physical Survivability": [ "Armor", "Dodge Chance", "Critical Avoidance" ],
                "Special Offense": [ "Special Damage", "Special Critical Chance", "Resistance Penetration", "Accuracy" ],
                "Special Survivability": [ "Resistance", "Deflection Chance", "Critical Avoidance" ]
            };

            const langStr = message.language.get("BASE_STAT_NAMES");
            const langMap = {
                "Primary Attributes":       "PRIMARY",
                "Strength":                 "STRENGTH",
                "Agility":                  "AGILITY",
                "Intelligence":             "TACTICS",
                "General":                  "GENERAL",
                "Health":                   "HEALTH",
                "Protection":               "PROTECTION",
                "Speed":                    "SPEED",
                "Critical Damage":          "CRITDMG",
                "Potency":                  "POTENCY",
                "Tenacity":                 "TENACITY",
                "Health Steal":             "HPSTEAL",
                "Defense Penetration":      "DEFENSEPEN",
                "Physical Offense":         "PHYSOFF",
                "Physical Damage":          "PHYSDMG",
                "Physical Critical Chance": "PHYSCRIT",
                "Armor Penetration":        "ARMORPEN",
                "Accuracy":                 "ACCURACY",
                "Physical Survivability":   "PHYSSURV",
                "Armor":                    "ARMOR",
                "Dodge Chance":             "DODGECHANCE",
                "Critical Avoidance":       "CRITAVOID",
                "Special Offense":          "SPECOFF",
                "Special Damage":           "SPECDMG",
                "Special Critical Chance":  "SPECCRIT",
                "Resistance Penetration":   "RESPEN",
                "Special Survivability":    "SPECSURV",
                "Resistance":               "RESISTANCE",
                "Deflection Chance":        "DEFLECTION"
            };

            if (!stats) return super.error(message, "Something went wrong. Please make sure you have that character unlocked");

            let keys = Object.keys(stats);
            if (keys.indexOf("undefined") >= 0) keys = keys.slice(0, keys.indexOf("undefined"));
            let maxLen;
            try {
                maxLen = keys.reduce((long, str) => Math.max(long, langStr[langMap[str]] ? langStr[langMap[str]].length : 0), 0);
            } catch (e) {
                console.log("[MC] Getting maxLen broke: " + e);
            }
            const statArr = [];
            Object.keys(statNames).forEach(sn => {
                let statStr = "== " + sn + " ==\n";
                statNames[sn].forEach(s => {
                    if (!stats[s]) stats[s] = {base: 0, final: 0, mods: 0, pct: false};
                    if (s === "Dodge Chance" || s === "Deflection Chance") {
                        statStr += `${langStr[langMap[s]]}${" ".repeat(maxLen - langStr[langMap[s]].length)} :: 2.00%\n`;
                    } else {
                        statStr += `${langStr[langMap[s]]}${" ".repeat(maxLen - langStr[langMap[s]].length)} :: `;
                        const str = !stats[s].pct ? parseInt(stats[s].final) : (stats[s].final * 100).toFixed(2)+"%";
                        const modStr = stats[s].mods > 0 ? (!stats[s].pct ? `(${parseInt(stats[s].mods)})` : `(${(stats[s].mods * 100).toFixed(2)}%)`) : "";
                        statStr += str + " ".repeat(8 - str.toString().length) + modStr + "\n";
                    }
                });
                statArr.push(Bot.expandSpaces(statStr));
            });

            const fields = [];
            Bot.msgArray(statArr, "\n", 1000).forEach((m, ix) => {
                fields.push({
                    name: ix === 0 ? "Stats" : "-",
                    value: Bot.codeBlock(m, "asciidoc")
                });
            });

            if (player.warnings) {
                fields.push({
                    name: "Warnings",
                    value: player.warnings.join("\n")
                });
            }
            let gearOut = "";
            if (!isShip) {
                // If it's a character, go ahead and work out the gear
                gearOut = "\n" + [
                    `${message.language.get("BASE_GEAR_SHORT")}: ${thisChar.gear}`,
                    `${gearStr}`
                ].join("\n");
            }

            if (!charImg) {
                // If it couldn't get an image for the character
                return msg.edit({embed: {
                    author: {
                        name: (thisChar.player ? thisChar.player : player.name) + "'s " + character.name,
                        url: character.url,
                        icon_url: character.avatarURL
                    },
                    description: `\`${message.language.get("BASE_LEVEL_SHORT")} ${thisChar.level} | ${thisChar.rarity}* | ${parseInt(thisChar.gp)} gp\`${gearOut}`,
                    fields: [
                        {
                            name: message.language.get("COMMAND_MYCHARACTER_ABILITIES"),
                            value: abilitiesOut.length ? abilitiesOut.join("\n") : "Couldn't find abilities"
                        }
                    ].concat(fields),
                    footer: footer
                }});
            } else {
                // But if it could, go ahead and send it
                return message.channel.send({embed: {
                    author: {
                        name: (thisChar.player ? thisChar.player : player.name) + "'s " + character.name,
                        url: character.url,
                        icon_url: character.avatarURL
                    },
                    thumbnail: { url: "attachment://image.png" },
                    description: `\`${message.language.get("BASE_LEVEL_SHORT")} ${thisChar.level} | ${thisChar.rarity}* | ${parseInt(thisChar.gp)} gp\`${gearOut}`,
                    fields: [
                        {
                            name: message.language.get("COMMAND_MYCHARACTER_ABILITIES"),
                            value: abilitiesOut.length ? abilitiesOut.join("\n") : "Couldn't find abilities"
                        }
                    ].concat(fields),
                    footer: footer,
                    files: [{
                        attachment: charImg,
                        name: "image.png"
                    }]
                }});
            }
        } else {
            // You don't have the character
            msg.edit({embed: {
                author: {
                    name: pName + "'s " + character.name
                },
                description: message.language.get("BASE_SWGOH_LOCKED_CHAR"),
                footer: footer
            }});
        }
    }
}

module.exports = MyCharacter;

<commit_msg>Update mycharacter.js<commit_after>const Command = require("../base/Command");
const nodeFetch = require("node-fetch");
const {promisify, inspect} = require("util");      // eslint-disable-line no-unused-vars

class MyCharacter extends Command {
    constructor(Bot) {
        super(Bot, {
            name: "mycharacter",
            category: "SWGoH",
            enabled: true,
            aliases: ["mc", "mychar"],
            permissions: ["EMBED_LINKS"],
            permLevel: 0,
            flags: {
                ships: {
                    aliases: ["s", "ship"]
                }
            }
        });
    }

    async run(Bot, message, args, options) {
        const {allyCode, searchChar, err} = await super.getUserAndChar(message, args);

        if (err) {
            return super.error(message, err);
        }

        let chars = [];
        if (!options.flags.ships) {
            chars = Bot.findChar(searchChar, Bot.characters);
        }
        if (!chars.length) {
            chars = Bot.findChar(searchChar, Bot.ships, true);
        }
        let character;
        if (!searchChar) {
            return super.error(message, message.language.get("BASE_SWGOH_MISSING_CHAR"));
        }

        if (chars.length === 0) {
            return super.error(message, message.language.get("BASE_SWGOH_NO_CHAR_FOUND", searchChar));
        } else if (chars.length > 1) {
            const charL = [];
            const charS = chars.sort((p, c) => p.name > c.name ? 1 : -1);
            charS.forEach(c => {
                charL.push(c.name);
            });
            return super.error(message, message.language.get("BASE_SWGOH_CHAR_LIST", charL.join("\n")));
        } else {
            character = chars[0];
        }

        const msg = await message.channel.send("Please wait while I look up your profile.");

        const cooldown = await Bot.getPlayerCooldown(message.author.id);
        let pName;
        let player = null;
        try {
            player = await Bot.swgohAPI.unitStats(allyCode, cooldown);
            if (Array.isArray(player)) player = player[0];
        } catch (e) {
            console.error(e);
            return super.error(message, Bot.codeBlock(e.message), {
                title: message.language.get("BASE_SOMETHING_BROKE"),
                footer: "Please try again in a bit."
            });
        }

        if (player && player.stats) {
            pName = player.name;
        }
        const footer = Bot.updatedFooter(player.updated, message, "player", cooldown);

        let thisChar = player.stats.filter(c => c.unit.defId === character.uniqueName);
        if (thisChar.length && Array.isArray(thisChar)) thisChar = thisChar[0];

        if (thisChar && !Array.isArray(thisChar)) {
            thisChar.unit = await Bot.swgohAPI.langChar(thisChar.unit, message.guildSettings.swgohLanguage);

            const stats = thisChar.stats;
            thisChar = thisChar.unit;
            const isShip = thisChar.crew.length ? true : false;

            let charImg;
            const pat = await Bot.getPatronUser(message.author.id);
            if (pat && pat.amount_cents >= 100) {
                // For now, limit it to Patrons
                const charArr = [thisChar.defId];
                charArr.push(thisChar.rarity);
                charArr.push(thisChar.level);
                charArr.push(thisChar.gear);
                charArr.push(thisChar.skills.filter(s => s.isZeta && s.tier == s.tiers).length);  // Zeta count
                charArr.push(thisChar.relic.currentTier);  // Relic count
                charArr.push(character.side);

                try {
                    await nodeFetch(Bot.config.imageServIP_Port + "/char/" + charArr.join("/"))
                        .then(response => response.buffer())
                        .then(image => {
                            charImg = image;
                        });
                } catch (e) {
                    console.log("ImageFetch in myCharacter broke: " + e);
                }
            }
            const abilities = {
                basic: [],
                special: [],
                leader: [],
                unique: [],
                contract: [],
                crew: [],
                hardware: []
            };

            let gearStr;
            if (!isShip) {
                gearStr = ["   [0]  [3]", "[1]       [4]", "   [2]  [5]"].join("\n");
                thisChar.equipped.forEach(e => {
                    gearStr = gearStr.replace(e.slot, "X");
                });
                gearStr = gearStr.replace(/[0-9]/g, "  ");
                gearStr = Bot.expandSpaces(gearStr);
            }
            thisChar.skills.forEach(a => {
                a.type = a.id.split("_")[0].replace("skill", "").toProperCase();
                if (a.tier === 8 || (a.tier === 3 && (a.type === "Contract" || a.type === "Hardware"))) {
                    if (a.isZeta) {
                        // Maxed Zeta ability
                        a.tier = "Max ✦";
                    } else if (isShip) {
                        a.tier = "Max";
                    } else {
                        // Maxed Omega ability
                        a.tier = "Max ⭓";
                    }
                } else {
                    // Unmaxed ability
                    a.tier = "Lvl " + a.tier;
                }
                try {
                    abilities[`${a.type ? a.type.toLowerCase() : a.defId.toLowerCase()}`].push(`\`${a.tier} [${a.type ? a.type.charAt(0) : a.defId.charAt(0)}]\` ${a.nameKey}`);
                } catch (e) {
                    console.log("ERROR[MC]: bad ability type: " + inspect(a));
                }
            });
            const abilitiesOut = abilities.basic
                .concat(abilities.special)
                .concat(abilities.leader)
                .concat(abilities.unique)
                .concat(abilities.crew)
                .concat(abilities.contract)
                .concat(abilities.hardware);

            const statNames = {
                "Primary Attributes" : [ "Strength", "Agility", "Intelligence" ],
                "General": [ "Health", "Protection", "Speed", "Critical Damage", "Potency", "Tenacity", "Health Steal", ],
                "Physical Offense": [ "Physical Damage", "Physical Critical Chance", "Armor Penetration", "Accuracy" ],
                "Physical Survivability": [ "Armor", "Dodge Chance", "Critical Avoidance" ],
                "Special Offense": [ "Special Damage", "Special Critical Chance", "Resistance Penetration", "Accuracy" ],
                "Special Survivability": [ "Resistance", "Deflection Chance", "Critical Avoidance" ]
            };

            const langStr = message.language.get("BASE_STAT_NAMES");
            const langMap = {
                "Primary Attributes":       "PRIMARY",
                "Strength":                 "STRENGTH",
                "Agility":                  "AGILITY",
                "Intelligence":             "TACTICS",
                "General":                  "GENERAL",
                "Health":                   "HEALTH",
                "Protection":               "PROTECTION",
                "Speed":                    "SPEED",
                "Critical Damage":          "CRITDMG",
                "Potency":                  "POTENCY",
                "Tenacity":                 "TENACITY",
                "Health Steal":             "HPSTEAL",
                "Defense Penetration":      "DEFENSEPEN",
                "Physical Offense":         "PHYSOFF",
                "Physical Damage":          "PHYSDMG",
                "Physical Critical Chance": "PHYSCRIT",
                "Armor Penetration":        "ARMORPEN",
                "Accuracy":                 "ACCURACY",
                "Physical Survivability":   "PHYSSURV",
                "Armor":                    "ARMOR",
                "Dodge Chance":             "DODGECHANCE",
                "Critical Avoidance":       "CRITAVOID",
                "Special Offense":          "SPECOFF",
                "Special Damage":           "SPECDMG",
                "Special Critical Chance":  "SPECCRIT",
                "Resistance Penetration":   "RESPEN",
                "Special Survivability":    "SPECSURV",
                "Resistance":               "RESISTANCE",
                "Deflection Chance":        "DEFLECTION"
            };

            if (!stats) return super.error(message, "Something went wrong. Please make sure you have that character unlocked");

            let keys = Object.keys(stats);
            if (keys.indexOf("undefined") >= 0) keys = keys.slice(0, keys.indexOf("undefined"));
            let maxLen;
            try {
                maxLen = keys.reduce((long, str) => Math.max(long, langStr[langMap[str]] ? langStr[langMap[str]].length : 0), 0);
            } catch (e) {
                console.log("[MC] Getting maxLen broke: " + e);
            }
            const statArr = [];
            Object.keys(statNames).forEach(sn => {
                let statStr = "== " + sn + " ==\n";
                statNames[sn].forEach(s => {
                    if (!stats[s]) stats[s] = {base: 0, final: 0, mods: 0, pct: false};
                    if (s === "Dodge Chance" || s === "Deflection Chance") {
                        statStr += `${langStr[langMap[s]]}${" ".repeat(maxLen - langStr[langMap[s]].length)} :: 2.00%\n`;
                    } else {
                        statStr += `${langStr[langMap[s]]}${" ".repeat(maxLen - langStr[langMap[s]].length)} :: `;
                        const str = !stats[s].pct ? parseInt(stats[s].final) : (stats[s].final * 100).toFixed(2)+"%";
                        const modStr = stats[s].mods > 0 ? (!stats[s].pct ? `(${parseInt(stats[s].mods)})` : `(${(stats[s].mods * 100).toFixed(2)}%)`) : "";
                        statStr += str + " ".repeat(8 - str.toString().length) + modStr + "\n";
                    }
                });
                statArr.push(Bot.expandSpaces(statStr));
            });

            const fields = [];
            Bot.msgArray(statArr, "\n", 1000).forEach((m, ix) => {
                fields.push({
                    name: ix === 0 ? "Stats" : "-",
                    value: Bot.codeBlock(m, "asciidoc")
                });
            });

            if (player.warnings) {
                fields.push({
                    name: "Warnings",
                    value: player.warnings.join("\n")
                });
            }
            let gearOut = "";
            if (!isShip) {
                // If it's a character, go ahead and work out the gear
                gearOut = "\n" + [
                    `${message.language.get("BASE_GEAR_SHORT")}: ${thisChar.gear}`,
                    `${gearStr}`
                ].join("\n");
            }

            if (!charImg) {
                // If it couldn't get an image for the character
                return msg.edit({embed: {
                    author: {
                        name: (thisChar.player ? thisChar.player : player.name) + "'s " + character.name,
                        url: character.url,
                        icon_url: character.avatarURL
                    },
                    description: `\`${message.language.get("BASE_LEVEL_SHORT")} ${thisChar.level} | ${thisChar.rarity}* | ${parseInt(thisChar.gp)} gp\`${gearOut}`,
                    fields: [
                        {
                            name: message.language.get("COMMAND_MYCHARACTER_ABILITIES"),
                            value: abilitiesOut.length ? abilitiesOut.join("\n") : "Couldn't find abilities"
                        }
                    ].concat(fields),
                    footer: footer
                }});
            } else {
                // But if it could, go ahead and send it
                return message.channel.send({embed: {
                    author: {
                        name: (thisChar.player ? thisChar.player : player.name) + "'s " + character.name,
                        url: character.url,
                        icon_url: character.avatarURL
                    },
                    thumbnail: { url: "attachment://image.png" },
                    description: `\`${message.language.get("BASE_LEVEL_SHORT")} ${thisChar.level} | ${thisChar.rarity}* | ${parseInt(thisChar.gp)} gp\`${gearOut}`,
                    fields: [
                        {
                            name: message.language.get("COMMAND_MYCHARACTER_ABILITIES"),
                            value: abilitiesOut.length ? abilitiesOut.join("\n") : "Couldn't find abilities"
                        }
                    ].concat(fields),
                    footer: footer,
                    files: [{
                        attachment: charImg,
                        name: "image.png"
                    }]
                }});
            }
        } else {
            // You don't have the character
            msg.edit({embed: {
                author: {
                    name: pName + "'s " + character.name
                },
                description: message.language.get("BASE_SWGOH_LOCKED_CHAR"),
                footer: footer
            }});
        }
    }
}

module.exports = MyCharacter;
<|endoftext|>


<commit_before>'use strict';

//const CLICK_LEFT   = 1;
//const CLICK_MIDDLE = 2;
//const CLICK_RIGHT  = 3;

const EVENT_MOUSE_DOWN = 'mousedown';
const EVENT_MOUSE_UP   = 'mouseup';
const EVENT_KEY_DOWN   = 'keydown';
const EVENT_KEY_UP     = 'keyup';
const EVENT_MOUSE_MOVE = 'mousemove';
const EVENT_PASTE      = 'paste';
const EVENT_WHEEL_V0   = 'wheel';
const EVENT_WHEEL_V1   = 'mousewheel';
const EVENT_WHEEL_V2   = 'DOMMouseScroll';

function InputManager() {
    this.__init__();
}

InputManager.prototype = {

    __init__: function() {
        this.click_down_left   = false;
        this.click_down_right  = false;
        this.click_down_middle = false;
        this.up 			   = false;
        this.down   		   = false;
        this.left 			   = false;
        this.right 			   = false;
        this.space  		   = false;
        this.shift  		   = false;

        this.CLICK_LEFT   = 1;
        this.CLICK_MIDDLE = 2;
        this.CLICK_RIGHT  = 3;

        document.addEventListener(EVENT_MOUSE_DOWN, this.on_mouse_down.bind(this));
        document.addEventListener(EVENT_MOUSE_UP  , this.on_mouse_up.bind(this));
        document.addEventListener(EVENT_KEY_DOWN  , this.on_key_down.bind(this));
        document.addEventListener(EVENT_KEY_UP    , this.on_key_up.bind(this));
        document.addEventListener(EVENT_PASTE     , this.on_paste.bind(this));

        document.addEventListener(EVENT_MOUSE_MOVE, this.on_mouse_move.bind(this));

        // Cross browser support for wheel events.
        // Base code from : https://stackoverflow.com/questions/25204282/mousewheel-wheel-and-dommousescroll-in-javascript

        // TODO : Double check to only add one of them and not all 3 if all 3 are supported.
        document.addEventListener(EVENT_WHEEL_V0  , this.on_wheel_event.bind(this));
        document.addEventListener(EVENT_WHEEL_V1  , this.on_wheel_event.bind(this));
        document.addEventListener(EVENT_WHEEL_V2  , this.on_wheel_event.bind(this));

        this._left_click_buffer = [];

        /* The flag that determines whether the wheel event is supported. */
        this.supports_wheel = false;
    },

    // TODO : CREATE AN INPUT RESET METHOD!!!
    reset: function() {
        this.click_down_left   = false;
        this.click_down_right  = false;
        this.click_down_middle = false;
        this.up 			   = false;
        this.down   		   = false;
        this.left 			   = false;
        this.right 			   = false;
        this.space  		   = false;
        this.shift  		   = false;
        this._left_click_buffer.length = 0;
    },

    on_paste: function(e) {
        if (CURRENT_PLAYER.has_paste_event()) {
            // Code help from : https://stackoverflow.com/questions/6902455/how-do-i-capture-the-input-value-on-a-paste-event
            var clipboard_data = e.clipboardData || e.originalEvent.clipboardData || window.clipboardData;
            var pasted_data = clipboard_data.getData('text');
            MANAGER_WORLD.current_world.currently_looked_at_object.parse_text(pasted_data);
        }
    },

    on_mouse_move: function(event) {
        if (CURRENT_PLAYER.has_mouse_movement()) {
            var movement_x = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
            var movement_y = event.movementY || event.mozMovementY || event.webkitMovementY || 0;
            CURRENT_PLAYER.fps_controls.on_mouse_move(movement_x, movement_y);

            // TODO : Not currently used for now.
            /*
            // Only left click dragging will be supported for now.
            if (this.click_down_left) {
                MANAGER_WORLD.current_world.parse_mouse_drag(movement_x, movement_y);
            } else {
                MANAGER_WORLD.current_world.parse_mouse_movement(movement_x, movement_y);
            }
            */
        }
    },

    on_key_down: function(event) {
        if (CURRENT_PLAYER.in_typing_state()) {
            l('CURRENT PLAYER is in typing state.');
            if (event.keyCode === KEY_CODE_ENTER) {
                l('NEED TO EXIT TYPING STATE!');
                CURRENT_PLAYER.add_text_and_leave_typing_state();
            } else {
                GUI_TYPING_INTERFACE.key_down_event(event);
            }
        } else if (CURRENT_PLAYER.has_input()) {
            if (event.keyCode === KEY_CODE_ENTER) {
                if (!CURRENT_PLAYER.engaged_with_object()) {
                    CURRENT_PLAYER.set_state(PLAYER_STATE_TYPING);
                } else {
                    MANAGER_WORLD.key_down_event(event);
                }
            } else {
                if (CURRENT_PLAYER.has_movement()) {
                    switch (event.keyCode) {
                    case KEY_CODE_UP:
                    case KEY_CODE_W:
                        this.up = true;
                        break;
                    case KEY_CODE_LEFT:
                    case KEY_CODE_A:
                        this.left = true;
                        break;
                    case KEY_CODE_DOWN:
                    case KEY_CODE_S:
                        this.down = true;
                        break;
                    case KEY_CODE_RIGHT:
                    case KEY_CODE_D:
                        this.right = true;
                        break;
                    case KEY_CODE_SPACE:
                        this.space = true;
                        break;
                    case KEY_CODE_SHIFT:
                        this.shift = true;
                        break;
                    }
                }
                MANAGER_WORLD.key_down_event(event);
            }
        }
    },

    // Base code from : https://stackoverflow.com/questions/25204282/mousewheel-wheel-and-dommousescroll-in-javascript
    on_wheel_event: function(e) {
        if (CURRENT_PLAYER.has_input()) {
            /* Check whether the wheel event is supported. */
            if (e.type == 'wheel') this.supports_wheel = true;
            else if (this.supports_wheel) return;

            /* Determine the direction of the scroll (< 0 → up, > 0 → down). */
            MANAGER_WORLD.current_world.wheel_event(((e.deltaY || -e.wheelDelta || e.detail) >> 10) || 1);
        }
    },

    on_key_up: function(event) {
        if (CURRENT_PLAYER.has_movement()) {
            switch (event.keyCode) {
            case KEY_CODE_UP:
            case KEY_CODE_W:
                this.up = false;
                break;
            case KEY_CODE_LEFT:
            case KEY_CODE_A:
                this.left = false;
                break;
            case KEY_CODE_DOWN:
            case KEY_CODE_S:
                this.down = false;
                break;
            case KEY_CODE_RIGHT:
            case KEY_CODE_D:
                this.right = false;
                break;
            case KEY_CODE_SPACE:
                this.space = false;
                break;
            case KEY_CODE_SHIFT:
                this.shift = false;
                break;
            }
        }
    },

    on_mouse_up: function(e) {
        e = e || window.event;

        if (CURRENT_PLAYER.has_input()) {
            switch (e.which) {
            case this.CLICK_LEFT:
                this.click_down_left = false;

                if (MANAGER_WORLD.current_world.floating_cursor._currently_engaged) {
                    MANAGER_WORLD.current_world.floating_cursor.disengage();
                } else if (this._left_click_buffer.length === 1) {
                    MANAGER_WORLD.current_world.single_left_click();
                } else if (this._left_click_buffer.length !== 0) {
                    MANAGER_WORLD.current_world.multi_left_click();
                }

                break;
            case this.CLICK_MIDDLE:

                if (MANAGER_POINTER_LOCK.pointer_is_locked) {
                    MANAGER_POINTER_LOCK.release_pointer_lock();
                } else {
                    MANAGER_POINTER_LOCK.request_pointer_lock();
                }

                //MANAGER_WORLD.current_world.single_middle_click();
                this.click_down_middle = false;
                break;
            case this.CLICK_RIGHT:
                if (MANAGER_WORLD.current_player_menu.is_visible()) {
                    MANAGER_WORLD.current_player_menu.set_to_invisible();
                } else {
                    MANAGER_WORLD.current_world.single_right_click();
                }
                this.click_down_right = false;
                break;
            }
        } else if (e.which === CLICK_LEFT && CURRENT_PLAYER.is_paused() && this._left_click_buffer.length > 1) {
            CURRENT_PLAYER.set_state(PLAYER_STATE_FULL_CONTROL);
        }
    },

    // Code base from : https://stackoverflow.com/questions/9521519/how-can-i-detect-a-rightmouse-button-event-on-mousedown
    on_mouse_down: function(e) {
        e = e || window.event;
        switch (e.which) {
        case this.CLICK_LEFT:

            var current_milliseconds = new Date().getTime();

            for (var i = this._left_click_buffer.length; i--;) {
                if (current_milliseconds - this._left_click_buffer[i] >= 300) {
                    this._left_click_buffer.splice(i, 1);
                }
            }

            this._left_click_buffer.push(current_milliseconds);

            if (CURRENT_PLAYER.has_input()) {
                // Cursor engage.
                if (is_defined(MANAGER_WORLD.current_world.floating_cursor.currently_attached_to)) {
                    if (MANAGER_WORLD.current_world.floating_cursor.currently_attached_to.scalable) {
                        MANAGER_WORLD.current_world.floating_cursor.engage();
                    }
                }
            }

            this.click_down_left = true;
            break;
        case this.CLICK_MIDDLE:
            this.click_down_middle = true;
            break;
        case this.CLICK_RIGHT:
            if (CURRENT_PLAYER.has_input()) {
                if (!this.click_down_right) {

                    // If the player has input and is NOT engaged AND the player menu is not visible then right clicking will make the PlayerMenu show up.

                    var currently_looked_at_object = CURRENT_PLAYER.get_currently_looked_at_object();
                    if (is_defined(currently_looked_at_object)) {
                        if (!currently_looked_at_object.is_engaged()) {
                            if (!MANAGER_WORLD.current_player_menu.is_visible()) {
                                MANAGER_WORLD.current_player_menu.set_to_visible();
                            }
                        } else {
                            currently_looked_at_object.disengage();
                        }
                    } else {
                        if (!MANAGER_WORLD.current_player_menu.is_visible()) {
                            MANAGER_WORLD.current_player_menu.set_to_visible();
                        }
                    }
                }
            }
            this.click_down_right = true;
            break;
        }
    }

};<commit_msg>general updates 00<commit_after>'use strict';

//const CLICK_LEFT   = 1;
//const CLICK_MIDDLE = 2;
//const CLICK_RIGHT  = 3;

const EVENT_MOUSE_DOWN = 'mousedown';
const EVENT_MOUSE_UP   = 'mouseup';
const EVENT_KEY_DOWN   = 'keydown';
const EVENT_KEY_UP     = 'keyup';
const EVENT_MOUSE_MOVE = 'mousemove';
const EVENT_PASTE      = 'paste';
const EVENT_WHEEL_V0   = 'wheel';
const EVENT_WHEEL_V1   = 'mousewheel';
const EVENT_WHEEL_V2   = 'DOMMouseScroll';

function InputManager() {
    this.__init__();
}

InputManager.prototype = {

    __init__: function() {
        this.click_down_left   = false;
        this.click_down_right  = false;
        this.click_down_middle = false;
        this.up 			   = false;
        this.down   		   = false;
        this.left 			   = false;
        this.right 			   = false;
        this.space  		   = false;
        this.shift  		   = false;

        this.CLICK_LEFT   = 1;
        this.CLICK_MIDDLE = 2;
        this.CLICK_RIGHT  = 3;

        document.addEventListener(EVENT_MOUSE_DOWN, this.on_mouse_down.bind(this));
        document.addEventListener(EVENT_MOUSE_UP  , this.on_mouse_up.bind(this));
        document.addEventListener(EVENT_KEY_DOWN  , this.on_key_down.bind(this));
        document.addEventListener(EVENT_KEY_UP    , this.on_key_up.bind(this));
        document.addEventListener(EVENT_PASTE     , this.on_paste.bind(this));

        document.addEventListener(EVENT_MOUSE_MOVE, this.on_mouse_move.bind(this));

        // Cross browser support for wheel events.
        // Base code from : https://stackoverflow.com/questions/25204282/mousewheel-wheel-and-dommousescroll-in-javascript

        // TODO : Double check to only add one of them and not all 3 if all 3 are supported.
        document.addEventListener(EVENT_WHEEL_V0  , this.on_wheel_event.bind(this));
        document.addEventListener(EVENT_WHEEL_V1  , this.on_wheel_event.bind(this));
        document.addEventListener(EVENT_WHEEL_V2  , this.on_wheel_event.bind(this));

        this._left_click_buffer = [];

        /* The flag that determines whether the wheel event is supported. */
        this.supports_wheel = false;
    },

    // TODO : CREATE AN INPUT RESET METHOD!!!
    reset: function() {
        this.click_down_left   = false;
        this.click_down_right  = false;
        this.click_down_middle = false;
        this.up 			   = false;
        this.down   		   = false;
        this.left 			   = false;
        this.right 			   = false;
        this.space  		   = false;
        this.shift  		   = false;
        this._left_click_buffer.length = 0;
    },

    on_paste: function(e) {
        if (CURRENT_PLAYER.has_paste_event()) {
            // Code help from : https://stackoverflow.com/questions/6902455/how-do-i-capture-the-input-value-on-a-paste-event
            var clipboard_data = e.clipboardData || e.originalEvent.clipboardData || window.clipboardData;
            var pasted_data = clipboard_data.getData('text');
            MANAGER_WORLD.current_world.currently_looked_at_object.parse_text(pasted_data);
        }
    },

    on_mouse_move: function(event) {
        if (CURRENT_PLAYER.has_mouse_movement()) {
            var movement_x = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
            var movement_y = event.movementY || event.mozMovementY || event.webkitMovementY || 0;
            CURRENT_PLAYER.fps_controls.on_mouse_move(movement_x, movement_y);

            // TODO : Not currently used for now.
            /*
            // Only left click dragging will be supported for now.
            if (this.click_down_left) {
                MANAGER_WORLD.current_world.parse_mouse_drag(movement_x, movement_y);
            } else {
                MANAGER_WORLD.current_world.parse_mouse_movement(movement_x, movement_y);
            }
            */
        }
    },

    on_key_down: function(event) {
        if (CURRENT_PLAYER.in_typing_state()) {
            l('CURRENT PLAYER is in typing state.');
            if (event.keyCode === KEY_CODE_ENTER) {
                l('NEED TO EXIT TYPING STATE!');
                CURRENT_PLAYER.add_text_and_leave_typing_state();
            } else {
                GUI_TYPING_INTERFACE.key_down_event(event);
            }
        } else if (CURRENT_PLAYER.has_input()) {
            if (event.keyCode === KEY_CODE_ENTER) {
                if (!CURRENT_PLAYER.engaged_with_object()) {
                    CURRENT_PLAYER.set_state(PLAYER_STATE_TYPING);
                } else {
                    MANAGER_WORLD.key_down_event(event);
                }
            } else {
                if (CURRENT_PLAYER.has_movement()) {
                    switch (event.keyCode) {
                    case KEY_CODE_UP:
                    case KEY_CODE_W:
                        this.up = true;
                        break;
                    case KEY_CODE_LEFT:
                    case KEY_CODE_A:
                        this.left = true;
                        break;
                    case KEY_CODE_DOWN:
                    case KEY_CODE_S:
                        this.down = true;
                        break;
                    case KEY_CODE_RIGHT:
                    case KEY_CODE_D:
                        this.right = true;
                        break;
                    case KEY_CODE_SPACE:
                        this.space = true;
                        break;
                    case KEY_CODE_SHIFT:
                        this.shift = true;
                        break;
                    }
                }
                MANAGER_WORLD.key_down_event(event);
            }
        }
    },

    // Base code from : https://stackoverflow.com/questions/25204282/mousewheel-wheel-and-dommousescroll-in-javascript
    on_wheel_event: function(e) {
        if (CURRENT_PLAYER.has_input()) {
            /* Check whether the wheel event is supported. */
            if (e.type == 'wheel') this.supports_wheel = true;
            else if (this.supports_wheel) return;

            /* Determine the direction of the scroll (< 0 → up, > 0 → down). */
            MANAGER_WORLD.current_world.wheel_event(((e.deltaY || -e.wheelDelta || e.detail) >> 10) || 1);
        }
    },

    on_key_up: function(event) {
        if (CURRENT_PLAYER.has_movement()) {
            switch (event.keyCode) {
            case KEY_CODE_UP:
            case KEY_CODE_W:
                this.up = false;
                break;
            case KEY_CODE_LEFT:
            case KEY_CODE_A:
                this.left = false;
                break;
            case KEY_CODE_DOWN:
            case KEY_CODE_S:
                this.down = false;
                break;
            case KEY_CODE_RIGHT:
            case KEY_CODE_D:
                this.right = false;
                break;
            case KEY_CODE_SPACE:
                this.space = false;
                break;
            case KEY_CODE_SHIFT:
                this.shift = false;
                break;
            }
        }
    },

    on_mouse_up: function(e) {
        e = e || window.event;

        if (CURRENT_PLAYER.has_input()) {
            switch (e.which) {
            case this.CLICK_LEFT:
                this.click_down_left = false;

                if (MANAGER_WORLD.current_world.floating_cursor._currently_engaged) {
                    MANAGER_WORLD.current_world.floating_cursor.disengage();
                } else if (this._left_click_buffer.length === 1) {
                    MANAGER_WORLD.current_world.single_left_click();
                } else if (this._left_click_buffer.length !== 0) {
                    MANAGER_WORLD.current_world.multi_left_click();
                }

                break;
            case this.CLICK_MIDDLE:

                if (MANAGER_POINTER_LOCK.pointer_is_locked) {
                    MANAGER_POINTER_LOCK.release_pointer_lock();
                } else {
                    MANAGER_POINTER_LOCK.request_pointer_lock();
                }

                //MANAGER_WORLD.current_world.single_middle_click();
                this.click_down_middle = false;
                break;
            case this.CLICK_RIGHT:
                if (MANAGER_WORLD.current_player_menu.is_visible()) {
                    MANAGER_WORLD.current_player_menu.set_to_invisible();
                } else {
                    MANAGER_WORLD.current_world.single_right_click();
                }
                this.click_down_right = false;
                break;
            }
        } else if (e.which === this.CLICK_LEFT && CURRENT_PLAYER.is_paused() && this._left_click_buffer.length > 1) {
            CURRENT_PLAYER.set_state(PLAYER_STATE_FULL_CONTROL);
        }
    },

    // Code base from : https://stackoverflow.com/questions/9521519/how-can-i-detect-a-rightmouse-button-event-on-mousedown
    on_mouse_down: function(e) {
        e = e || window.event;
        switch (e.which) {
        case this.CLICK_LEFT:

            var current_milliseconds = new Date().getTime();

            for (var i = this._left_click_buffer.length; i--;) {
                if (current_milliseconds - this._left_click_buffer[i] >= 300) {
                    this._left_click_buffer.splice(i, 1);
                }
            }

            this._left_click_buffer.push(current_milliseconds);

            if (CURRENT_PLAYER.has_input()) {
                // Cursor engage.
                if (is_defined(MANAGER_WORLD.current_world.floating_cursor.currently_attached_to)) {
                    if (MANAGER_WORLD.current_world.floating_cursor.currently_attached_to.scalable) {
                        MANAGER_WORLD.current_world.floating_cursor.engage();
                    }
                }
            }

            this.click_down_left = true;
            break;
        case this.CLICK_MIDDLE:
            this.click_down_middle = true;
            break;
        case this.CLICK_RIGHT:
            if (CURRENT_PLAYER.has_input()) {
                if (!this.click_down_right) {

                    // If the player has input and is NOT engaged AND the player menu is not visible then right clicking will make the PlayerMenu show up.

                    var currently_looked_at_object = CURRENT_PLAYER.get_currently_looked_at_object();
                    if (is_defined(currently_looked_at_object)) {
                        if (!currently_looked_at_object.is_engaged()) {
                            if (!MANAGER_WORLD.current_player_menu.is_visible()) {
                                MANAGER_WORLD.current_player_menu.set_to_visible();
                            }
                        } else {
                            currently_looked_at_object.disengage();
                        }
                    } else {
                        if (!MANAGER_WORLD.current_player_menu.is_visible()) {
                            MANAGER_WORLD.current_player_menu.set_to_visible();
                        }
                    }
                }
            }
            this.click_down_right = true;
            break;
        }
    }

};<|endoftext|>


<commit_before>/*globals define, requirejs */
define([
    'module',
    './backends/StorageBackend',
    'text!deepforge/storage/backends/sciserver-files/metadata.json',
    'text!deepforge/storage/backends/gme/metadata.json',
],function(
    module,
    StorageBackend,
    sciserverFiles,
    gme,
) {
    const Storage = {};
    const StorageMetadata = {};
    StorageMetadata['sciserver-files'] = JSON.parse(sciserverFiles);
    StorageMetadata['gme'] = JSON.parse(gme);
    const STORAGE_BACKENDS = Object.keys(StorageMetadata);

    Storage.getComponentId = function() {
        return 'Storage';
    };

    Storage.getAvailableBackends = function() {
        const settings = {backends: STORAGE_BACKENDS};  // all by default
        if (require.isBrowser) {
            const ComponentSettings = requirejs('js/Utils/ComponentSettings');
            ComponentSettings.resolveWithWebGMEGlobal(
                settings,
                this.getComponentId()
            );
        } else {  // Running in NodeJS
            const path = require('path');
            const dirname = path.dirname(module.uri);
            const deploymentSettings = JSON.parse(requirejs('text!' + dirname + '/../../../config/components.json'));
            Object.assign(settings, deploymentSettings[this.getComponentId()]);
        }

        return settings.backends;
    };

    Storage.getBackend = function(id) {
        const metadata = this.getStorageMetadata(id);
        return new StorageBackend(id, metadata);
    };

    Storage.getStorageMetadata = function(id) {
        id = id.toLowerCase();
        if (!STORAGE_BACKENDS.includes(id)) {
            throw new Error(`Storage backend not found: ${id}`);
        }

        const metadata = StorageMetadata[id];
        metadata.id = id;
        return metadata;
    };

    Storage.getMetadata = async function(dataInfo, logger, configs) {
        const client = await this.getClientForDataInfo(dataInfo, logger, configs);
        return client.getMetadata(dataInfo);
    };

    Storage.getDownloadURL = async function(dataInfo, logger, configs) {
        const client = await this.getClientForDataInfo(dataInfo, logger, configs);
        return client.getDownloadURL(dataInfo);
    };

    Storage.getFile = async function(dataInfo, logger, configs) {
        const client = await this.getClientForDataInfo(dataInfo, logger, configs);
        return client.getFile(dataInfo);
    };

    Storage.deleteFile = async function(dataInfo, logger, configs) {
        const client = await this.getClientForDataInfo(dataInfo, logger, configs);
        return client.deleteFile(dataInfo);
    };

    Storage.getCachePath = async function(dataInfo, logger, configs) {
        const client = await this.getClientForDataInfo(dataInfo, logger, configs);
        return await client.getCachePath(dataInfo);
    };

    Storage.getClientForDataInfo = async function(dataInfo, logger, configs={}) {
        const config = configs[dataInfo.backend];
        const backend = this.getBackend(dataInfo.backend);
        return await backend.getClient(logger, config);
    };

    Storage.getClient = async function(id, logger, config={}) {
        const backend = this.getBackend(id);
        return await backend.getClient(logger, config);
    };

    return Storage;
});
<commit_msg>Return copy of storage metadata. Fixes #1418 (#1420)<commit_after>/*globals define, requirejs */
define([
    'module',
    './backends/StorageBackend',
    'text!deepforge/storage/backends/sciserver-files/metadata.json',
    'text!deepforge/storage/backends/gme/metadata.json',
],function(
    module,
    StorageBackend,
    sciserverFiles,
    gme,
) {
    const Storage = {};
    const StorageMetadata = {};
    StorageMetadata['sciserver-files'] = JSON.parse(sciserverFiles);
    StorageMetadata['gme'] = JSON.parse(gme);
    const STORAGE_BACKENDS = Object.keys(StorageMetadata);

    Storage.getComponentId = function() {
        return 'Storage';
    };

    Storage.getAvailableBackends = function() {
        const settings = {backends: STORAGE_BACKENDS};  // all by default
        if (require.isBrowser) {
            const ComponentSettings = requirejs('js/Utils/ComponentSettings');
            ComponentSettings.resolveWithWebGMEGlobal(
                settings,
                this.getComponentId()
            );
        } else {  // Running in NodeJS
            const path = require('path');
            const dirname = path.dirname(module.uri);
            const deploymentSettings = JSON.parse(requirejs('text!' + dirname + '/../../../config/components.json'));
            Object.assign(settings, deploymentSettings[this.getComponentId()]);
        }

        return settings.backends;
    };

    Storage.getBackend = function(id) {
        const metadata = this.getStorageMetadata(id);
        return new StorageBackend(id, metadata);
    };

    Storage.getStorageMetadata = function(id) {
        id = id.toLowerCase();
        if (!STORAGE_BACKENDS.includes(id)) {
            throw new Error(`Storage backend not found: ${id}`);
        }

        const metadata = StorageMetadata[id];
        metadata.id = id;
        return deepCopy(metadata);
    };

    Storage.getMetadata = async function(dataInfo, logger, configs) {
        const client = await this.getClientForDataInfo(dataInfo, logger, configs);
        return client.getMetadata(dataInfo);
    };

    Storage.getDownloadURL = async function(dataInfo, logger, configs) {
        const client = await this.getClientForDataInfo(dataInfo, logger, configs);
        return client.getDownloadURL(dataInfo);
    };

    Storage.getFile = async function(dataInfo, logger, configs) {
        const client = await this.getClientForDataInfo(dataInfo, logger, configs);
        return client.getFile(dataInfo);
    };

    Storage.deleteFile = async function(dataInfo, logger, configs) {
        const client = await this.getClientForDataInfo(dataInfo, logger, configs);
        return client.deleteFile(dataInfo);
    };

    Storage.getCachePath = async function(dataInfo, logger, configs) {
        const client = await this.getClientForDataInfo(dataInfo, logger, configs);
        return await client.getCachePath(dataInfo);
    };

    Storage.getClientForDataInfo = async function(dataInfo, logger, configs={}) {
        const config = configs[dataInfo.backend];
        const backend = this.getBackend(dataInfo.backend);
        return await backend.getClient(logger, config);
    };

    Storage.getClient = async function(id, logger, config={}) {
        const backend = this.getBackend(id);
        return await backend.getClient(logger, config);
    };

    function deepCopy(obj) {
        return JSON.parse(JSON.stringify(obj));
    }

    return Storage;
});
<|endoftext|>


<commit_before>directivesModule.directive("redactor", function () {
  var linkFn = function (scope, el, attr, ngModel) {
		scope.redactor = el.redactor({
			focus: false,
			callback: function (o) {
				el.keydown(function () {
					scope.$apply(ngModel.$setViewValue(o.getCode()));
				});
			}
		});
	}
	return {
		require: '?ngModel',
		link: linkFn,
		restrict: 'A',
	};
});
<commit_msg>Update redactor.js<commit_after>/*
// http://stackoverflow.com/a/16428909/1069899

HTML View:

    <form ng-submit="addPost()">
        <textarea ng-model="newPost.content" redactor required></textarea>

        <input type="submit" value="add post">
    </form>

    {{newPost.content}}

Controller function:
$scope.addPost = function() {
  var post;
  post = Post.save($scope.newPost);
  console.log(post);
  $scope.posts.unshift(post);
  return $scope.newPost.content = "
Add a new post...
";
};
*/
directives.directive("redactor", function() {
  return {
    require: "?ngModel",
    link: function($scope, elem, attrs, controller) {
      return controller.$render = function() {
        elem.redactor({
          keyupCallback: function() {
            return $scope.$apply(controller.$setViewValue(elem.getCode()));
          },
          execCommandCallback: function() {
            return $scope.$apply(controller.$setViewValue(elem.getCode()));
          },
        });
        return elem.setCode(controller.$viewValue);
      };
    }
  };
});
<|endoftext|>