<commit_before>// default browser scroll bar width
const SCROLL_BAR_SIZE = 17
const BAR_COLOR = "rgb(241, 241, 241)"
const ARROW_COLOR = "rgb(80, 80, 80)"
const ARROW_DISABLED_COLOR = "rgb(163, 163, 163)"
const ARROW_HILIGHT = "#fff"
const ARROWBG_HOVER_COLOR = "#d2d2d2"
const ARROWBG_ACTIVE_COLOR = "#787878"
const HANDLE_COLOR = "rgb(193, 193, 193)"
const HANDLE_HOVER_COLOR = "#a8a8a8"
const HANDLE_ACTIVE_COLOR = "#787878"

const ScrollBarOrientaion = {
  HORIZONTAL: 0,
  VERTICAL: 1
}

const ButtonState = {
  NORMAL: 0,
  HOVER: 1,
  ACTIVE: 2,
  DISABLE: 3
}

class ShapeButton extends createjs.Shape {
  constructor() {
    super()
    this.setBounds(0, 0, 0, 0)
    this._state = ButtonState.NORMAL
    this._enable = true
    this.foregroundColors = ["red", "green", "yellow", "blue"]
    this.backgroundColors = ["blue", "red", "green", "yellow"]
    this.on("mouseover", e => {
      this.state = ButtonState.HOVER
    })
    this.on("mouseout", e => {
      this.state = ButtonState.NORMAL
    })
    this.on("mousedown", e => {
      this.state = ButtonState.ACTIVE
    })
    this.on("pressup", e => {
      this.state = e.target.hitTest(e.localX, e.localY) ?
        ButtonState.HOVER : ButtonState.NORMAL
    })
  }

  set enable(enable) {
    this._enable = enable
    this.state = this._state
  }

  get isEnabled() {
    return this._enable
  }

  get state() {
    return this._state
  }

  set state(state) {
    this._state = this.isEnabled ? state : ButtonState.DISABLE
    this.redraw()
  }

  redraw() {
    this.graphics
      .clear()
      .beginFill(this.backgroundColors[this.state])
      .rect(0, 0, this.getBounds().width, this.getBounds().height)
    this.drawForeground(this.foregroundColors[this.state])
  }

  drawForeground(color) {
    // override
  }

  setForegroundColor(state, color) {
    this.foregroundColors[state] = color
    this.redraw()
  }

  setBackgroundColor(state, color) {
    this.backgroundColors[state] = color
    this.redraw()
  }
}

class ArrowButton extends ShapeButton {
  constructor(arrowRotation) {
    super()
    this.arrowRotation = arrowRotation
    this.arrowWidth = 10
    this.arrowHeight = 5
  }

  drawForeground(color) {
    function drawPoints(g, mat, points) {
      points.forEach((point, i) => {
        const p = mat.transformPoint(point[0], point[1])
        p.x = Math.floor(p.x)
        p.y = Math.floor(p.y)
        if (i == 0) {
          g.moveTo(p.x, p.y)
        } else {
          g.lineTo(p.x, p.y)
        }
      })
    }

    const b = this.getBounds()
    const mat = new createjs.Matrix2D()
      .translate(b.width / 2, b.height / 2)
      .rotate(this.arrowRotation)

    const g = this.graphics
      .beginFill(color)
    drawPoints(g, mat, [
      [0, -this.arrowHeight / 2],
      [this.arrowWidth / 2, this.arrowHeight / 2],
      [-this.arrowWidth / 2, this.arrowHeight / 2]
    ])
  }
}

class ScrollBar extends createjs.Container {
  constructor(orientation) {
    super()

    this._size = {
      width: 0,
      height: 0
    }
    this._contentLength = 0
    this._value = 0
    this.unitIncrement = 120
    this.blockIncrement = 240
    this.orientation = orientation

    this.background = new createjs.Shape
    this.background.on("mousedown", e => {
      const pos = this.isVertical ? e.localY : e.localX
      const b = this.handle.getBounds()
      const handleHead = this.isVertical ? this.handle.y : this.handle.x
      const handleTail = this.isVertical ? this.handle.y + b.height : this.handle.x + b.width
      if (pos < handleHead) {
        this._changeValue(e, this.value + this.blockIncrement)
      }
      if (pos > handleTail) {
        this._changeValue(e, this.value - this.blockIncrement)
      }
    })
    this.addChild(this.background)

    const rot = this.isVertical ? 0 : -90

    this.headArrow = new ArrowButton(rot)
    this.headArrow.setBackgroundColor(ButtonState.NORMAL, BAR_COLOR)
    this.headArrow.setBackgroundColor(ButtonState.HOVER, ARROWBG_HOVER_COLOR)
    this.headArrow.setBackgroundColor(ButtonState.ACTIVE, ARROWBG_ACTIVE_COLOR)
    this.headArrow.setForegroundColor(ButtonState.NORMAL, ARROW_COLOR)
    this.headArrow.setForegroundColor(ButtonState.HOVER, ARROW_COLOR)
    this.headArrow.setForegroundColor(ButtonState.ACTIVE, ARROW_HILIGHT)
    this.headArrow.on("mousedown", e => {
      this._changeValue(e, this.value + this.unitIncrement)
    })
    this.addChild(this.headArrow)

    this.tailArrow = new ArrowButton(rot + 180)
    this.tailArrow.setBackgroundColor(ButtonState.NORMAL, BAR_COLOR)
    this.tailArrow.setBackgroundColor(ButtonState.HOVER, ARROWBG_HOVER_COLOR)
    this.tailArrow.setBackgroundColor(ButtonState.ACTIVE, ARROWBG_ACTIVE_COLOR)
    this.tailArrow.setForegroundColor(ButtonState.NORMAL, ARROW_COLOR)
    this.tailArrow.setForegroundColor(ButtonState.HOVER, ARROW_COLOR)
    this.tailArrow.setForegroundColor(ButtonState.ACTIVE, ARROW_HILIGHT)
    this.tailArrow.on("mousedown", e => {
      this._changeValue(e, this.value - this.unitIncrement)
    })
    this.addChild(this.tailArrow)

    this.handle = new ShapeButton
    this.handle.setBackgroundColor(ButtonState.NORMAL, HANDLE_COLOR)
    this.handle.setBackgroundColor(ButtonState.HOVER, HANDLE_HOVER_COLOR)
    this.handle.setBackgroundColor(ButtonState.ACTIVE, HANDLE_ACTIVE_COLOR)
    this.handle.on("mousedown", e => {
      this.startPos = {
        x: e.stageX,
        y: e.stageY,
        value: this.value
      }
    })
    this.handle.on("pressmove", e => {
      const delta = this.isVertical ? this.startPos.y - e.stageY : this.startPos.x - e.stageX
      this._changeValue(e, this.startPos.value + this.positionToValue(delta))
    })
    this.addChild(this.handle)
  }

  _changeValue(e, value) {
    const changed = this._value != value
    this.value = value
    if (changed) this.dispatchEvent("change", e)
  }

  get value() {
    return this._value
  }

  set value(value) {
    this._value = Math.max(Math.min(0, value), this.maxValue)
    this.redraw()
  }

  set size(size) {
    this._size = size
    this.setBounds(0, 0, size.width, size.height)
    this.redraw()
  }

  get size() {
    return this._size
  }

  get contentLength() {
    return this._contentLength
  }

  set contentLength(length) {
    this._contentLength = length
    this.redraw()
  }

  redraw() {
    this.background.graphics
      .clear()
      .beginFill(BAR_COLOR)
      .rect(0, 0, this.size.width, this.size.height)

    this.drawArrows()
    this.drawHandle()
  }

  get barWidth() {
    return this.isVertical ? this.size.width : this.size.height
  }

  get barLength() {
    return !this.isVertical ? this.size.width : this.size.height
  }

  get isVertical() {
    return this.orientation == ScrollBarOrientaion.VERTICAL
  }

  get maxValue() {
    return this.barLength - this._contentLength
  }

  positionToValue(pos) {
    return pos * this._contentLength / (this.barLength - 2 * this.barWidth)
  }

  drawHandle() {
    const maxLength = this.barLength - this.barWidth * 2

    const handleSize = [
      this.barWidth * 0.8,
      maxLength * this.barLength / this._contentLength
    ]

    const handlePos = [
      (this.barWidth - handleSize[0]) / 2,
      this.barWidth + maxLength * (1 - this.barLength / this._contentLength) * (this.value / this.maxValue)
    ]

    const px = this.isVertical ? 0 : 1
    const py = this.isVertical ? 1 : 0

    this.handle.x = handlePos[px]
    this.handle.y = handlePos[py]
    this.handle.setBounds(0, 0, handleSize[px], handleSize[py])
    this.handle.redraw()
  }

  drawArrows() {
    const size = this.barWidth
    const px = this.isVertical ? 0 : 1
    const py = this.isVertical ? 1 : 0

    const tailPos = [0, this.barLength - size]
    this.tailArrow.x = tailPos[px]
    this.tailArrow.y = tailPos[py]

    this.headArrow.setBounds(0, 0, size, size)
    this.tailArrow.setBounds(0, 0, size, size)
    this.headArrow.arrowWidth = size / 2
    this.headArrow.arrowHeight = size / 4
    this.tailArrow.arrowWidth = size / 2
    this.tailArrow.arrowHeight = size / 4
    this.headArrow.redraw()
    this.tailArrow.redraw()
  }
}

class ScrollContainer extends createjs.Container {
  constructor(canvas) {
    super()
    this.container = new createjs.Container()
    this.addChild(this.container)

    this.scrollBarV = new ScrollBar(ScrollBarOrientaion.VERTICAL)
    this.addChild(this.scrollBarV)

    this.scrollBarH = new ScrollBar(ScrollBarOrientaion.HORIZONTAL)
    this.addChild(this.scrollBarH)

    this.scrollBarV.on("change", e => {
      this.container.y = e.target.value
    })

    this.scrollBarH.on("change", e => {
      this.container.x = e.target.value
    })

    canvas.addEventListener("mousewheel", e => {
      const h = this.contentSize.height - this.getBounds().height
      const w = this.contentSize.width - this.getBounds().width
      this.scrollY = Math.min(0, Math.max(this.scrollY + e.wheelDeltaY, -h - SCROLL_BAR_SIZE))
      this.scrollX = Math.min(0, Math.max(this.scrollX + e.wheelDeltaX, -w - SCROLL_BAR_SIZE))
    })

    this.superAddChild = this.addChild

    this.addChild = child => {
      this.container.addChild(child)
    }
  }

  get scrollX() {
    return this.container.x
  }

  set scrollX(x) {
    this.container.x = x
    this.scrollBarH.value = x
    this.dispatchEvent("scroll")
  }

  get scrollY() {
    return this.container.y
  }

  set scrollY(y) {
    this.container.y = y
    this.scrollBarV.value = y
    this.dispatchEvent("scroll")
  }

  set contentSize(size) {
    this.container.setBounds(0, 0, size.width, size.height)
    this.scrollBarH.contentLength = size.width
    this.scrollBarV.contentLength = size.height
  }

  get contentSize() {
    return {
      width: this.container.getBounds().width,
      height: this.container.getBounds().height,
    }
  }

  setBounds(x, y, width, height) {
    super.setBounds(x, y, width, height)
    this.contentSize = {
      width: Math.max(width, this.contentSize.width),
      height: Math.max(height, this.contentSize.height)
    }

    this.scrollBarV.x = width - SCROLL_BAR_SIZE
    this.scrollBarV.size = {
      width: SCROLL_BAR_SIZE,
      height: height - SCROLL_BAR_SIZE
    }

    this.scrollBarH.y = height - SCROLL_BAR_SIZE
    this.scrollBarH.size = {
      width: width - SCROLL_BAR_SIZE,
      height: SCROLL_BAR_SIZE
    }
  }
}
<commit_msg>fix scroll<commit_after>// default browser scroll bar width
const SCROLL_BAR_SIZE = 17
const BAR_COLOR = "rgb(241, 241, 241)"
const ARROW_COLOR = "rgb(80, 80, 80)"
const ARROW_DISABLED_COLOR = "rgb(163, 163, 163)"
const ARROW_HILIGHT = "#fff"
const ARROWBG_HOVER_COLOR = "#d2d2d2"
const ARROWBG_ACTIVE_COLOR = "#787878"
const HANDLE_COLOR = "rgb(193, 193, 193)"
const HANDLE_HOVER_COLOR = "#a8a8a8"
const HANDLE_ACTIVE_COLOR = "#787878"

const ScrollBarOrientaion = {
  HORIZONTAL: 0,
  VERTICAL: 1
}

const ButtonState = {
  NORMAL: 0,
  HOVER: 1,
  ACTIVE: 2,
  DISABLE: 3
}

class ShapeButton extends createjs.Shape {
  constructor() {
    super()
    this.setBounds(0, 0, 0, 0)
    this._state = ButtonState.NORMAL
    this._enable = true
    this.foregroundColors = ["red", "green", "yellow", "blue"]
    this.backgroundColors = ["blue", "red", "green", "yellow"]
    this.on("mouseover", e => {
      this.state = ButtonState.HOVER
    })
    this.on("mouseout", e => {
      this.state = ButtonState.NORMAL
    })
    this.on("mousedown", e => {
      this.state = ButtonState.ACTIVE
    })
    this.on("pressup", e => {
      this.state = e.target.hitTest(e.localX, e.localY) ?
        ButtonState.HOVER : ButtonState.NORMAL
    })
  }

  set enable(enable) {
    this._enable = enable
    this.state = this._state
  }

  get isEnabled() {
    return this._enable
  }

  get state() {
    return this._state
  }

  set state(state) {
    this._state = this.isEnabled ? state : ButtonState.DISABLE
    this.redraw()
  }

  redraw() {
    this.graphics
      .clear()
      .beginFill(this.backgroundColors[this.state])
      .rect(0, 0, this.getBounds().width, this.getBounds().height)
    this.drawForeground(this.foregroundColors[this.state])
  }

  drawForeground(color) {
    // override
  }

  setForegroundColor(state, color) {
    this.foregroundColors[state] = color
    this.redraw()
  }

  setBackgroundColor(state, color) {
    this.backgroundColors[state] = color
    this.redraw()
  }
}

class ArrowButton extends ShapeButton {
  constructor(arrowRotation) {
    super()
    this.arrowRotation = arrowRotation
    this.arrowWidth = 10
    this.arrowHeight = 5
  }

  drawForeground(color) {
    function drawPoints(g, mat, points) {
      points.forEach((point, i) => {
        const p = mat.transformPoint(point[0], point[1])
        p.x = Math.floor(p.x)
        p.y = Math.floor(p.y)
        if (i == 0) {
          g.moveTo(p.x, p.y)
        } else {
          g.lineTo(p.x, p.y)
        }
      })
    }

    const b = this.getBounds()
    const mat = new createjs.Matrix2D()
      .translate(b.width / 2, b.height / 2)
      .rotate(this.arrowRotation)

    const g = this.graphics
      .beginFill(color)
    drawPoints(g, mat, [
      [0, -this.arrowHeight / 2],
      [this.arrowWidth / 2, this.arrowHeight / 2],
      [-this.arrowWidth / 2, this.arrowHeight / 2]
    ])
  }
}

class ScrollBar extends createjs.Container {
  constructor(orientation) {
    super()

    this._size = {
      width: 0,
      height: 0
    }
    this._contentLength = 0
    this._value = 0
    this.unitIncrement = 120
    this.blockIncrement = 240
    this.orientation = orientation

    this.background = new createjs.Shape
    this.background.on("mousedown", e => {
      const pos = this.isVertical ? e.localY : e.localX
      const b = this.handle.getBounds()
      const handleHead = this.isVertical ? this.handle.y : this.handle.x
      const handleTail = this.isVertical ? this.handle.y + b.height : this.handle.x + b.width
      if (pos < handleHead) {
        this._changeValue(e, this.value + this.blockIncrement)
      }
      if (pos > handleTail) {
        this._changeValue(e, this.value - this.blockIncrement)
      }
    })
    this.addChild(this.background)

    const rot = this.isVertical ? 0 : -90

    this.headArrow = new ArrowButton(rot)
    this.headArrow.setBackgroundColor(ButtonState.NORMAL, BAR_COLOR)
    this.headArrow.setBackgroundColor(ButtonState.HOVER, ARROWBG_HOVER_COLOR)
    this.headArrow.setBackgroundColor(ButtonState.ACTIVE, ARROWBG_ACTIVE_COLOR)
    this.headArrow.setForegroundColor(ButtonState.NORMAL, ARROW_COLOR)
    this.headArrow.setForegroundColor(ButtonState.HOVER, ARROW_COLOR)
    this.headArrow.setForegroundColor(ButtonState.ACTIVE, ARROW_HILIGHT)
    this.headArrow.on("mousedown", e => {
      this._changeValue(e, this.value + this.unitIncrement)
    })
    this.addChild(this.headArrow)

    this.tailArrow = new ArrowButton(rot + 180)
    this.tailArrow.setBackgroundColor(ButtonState.NORMAL, BAR_COLOR)
    this.tailArrow.setBackgroundColor(ButtonState.HOVER, ARROWBG_HOVER_COLOR)
    this.tailArrow.setBackgroundColor(ButtonState.ACTIVE, ARROWBG_ACTIVE_COLOR)
    this.tailArrow.setForegroundColor(ButtonState.NORMAL, ARROW_COLOR)
    this.tailArrow.setForegroundColor(ButtonState.HOVER, ARROW_COLOR)
    this.tailArrow.setForegroundColor(ButtonState.ACTIVE, ARROW_HILIGHT)
    this.tailArrow.on("mousedown", e => {
      this._changeValue(e, this.value - this.unitIncrement)
    })
    this.addChild(this.tailArrow)

    this.handle = new ShapeButton
    this.handle.setBackgroundColor(ButtonState.NORMAL, HANDLE_COLOR)
    this.handle.setBackgroundColor(ButtonState.HOVER, HANDLE_HOVER_COLOR)
    this.handle.setBackgroundColor(ButtonState.ACTIVE, HANDLE_ACTIVE_COLOR)
    this.handle.on("mousedown", e => {
      this.startPos = {
        x: e.stageX,
        y: e.stageY,
        value: this.value
      }
    })
    this.handle.on("pressmove", e => {
      const delta = this.isVertical ? this.startPos.y - e.stageY : this.startPos.x - e.stageX
      this._changeValue(e, this.startPos.value + this.positionToValue(delta))
    })
    this.addChild(this.handle)
  }

  _changeValue(e, value) {
    const oldValue = this._value
    this.value = value
    if (oldValue != this.value) this.dispatchEvent("change", e)
  }

  get value() {
    return this._value
  }

  set value(value) {
    this._value = Math.max(Math.min(0, value), this.maxValue)
    this.redraw()
  }

  set size(size) {
    this._size = size
    this.setBounds(0, 0, size.width, size.height)
    this.redraw()
  }

  get size() {
    return this._size
  }

  get contentLength() {
    return this._contentLength
  }

  set contentLength(length) {
    this._contentLength = length
    this.redraw()
  }

  redraw() {
    this.background.graphics
      .clear()
      .beginFill(BAR_COLOR)
      .rect(0, 0, this.size.width, this.size.height)

    this.drawArrows()
    this.drawHandle()
  }

  get barWidth() {
    return this.isVertical ? this.size.width : this.size.height
  }

  get barLength() {
    return !this.isVertical ? this.size.width : this.size.height
  }

  get isVertical() {
    return this.orientation == ScrollBarOrientaion.VERTICAL
  }

  get maxValue() {
    return Math.min(0.001, this.barLength - this._contentLength)
  }

  positionToValue(pos) {
    return pos * this._contentLength / (this.barLength - 2 * this.barWidth)
  }

  drawHandle() {
    function normalize(v) {
      return Math.max(0, Math.min(1, v))
    }
    const maxLength = this.barLength - this.barWidth * 2

    const handleSize = [
      this.barWidth * 0.8,
      maxLength * normalize(this.barLength / this._contentLength)
    ]

    const handlePos = [
      (this.barWidth - handleSize[0]) / 2,
      this.barWidth + maxLength * (1 - normalize(this.barLength / this._contentLength)) * normalize(this.value / this.maxValue)
    ]

    const px = this.isVertical ? 0 : 1
    const py = this.isVertical ? 1 : 0

    this.handle.x = handlePos[px]
    this.handle.y = handlePos[py]
    this.handle.setBounds(0, 0, handleSize[px], handleSize[py])
    this.handle.redraw()
  }

  drawArrows() {
    const size = this.barWidth
    const px = this.isVertical ? 0 : 1
    const py = this.isVertical ? 1 : 0

    const tailPos = [0, this.barLength - size]
    this.tailArrow.x = tailPos[px]
    this.tailArrow.y = tailPos[py]

    this.headArrow.setBounds(0, 0, size, size)
    this.tailArrow.setBounds(0, 0, size, size)
    this.headArrow.arrowWidth = size / 2
    this.headArrow.arrowHeight = size / 4
    this.tailArrow.arrowWidth = size / 2
    this.tailArrow.arrowHeight = size / 4
    this.headArrow.redraw()
    this.tailArrow.redraw()
  }
}

class ScrollContainer extends createjs.Container {
  constructor(canvas) {
    super()
    this.container = new createjs.Container()
    this.addChild(this.container)

    this.scrollBarV = new ScrollBar(ScrollBarOrientaion.VERTICAL)
    this.addChild(this.scrollBarV)

    this.scrollBarH = new ScrollBar(ScrollBarOrientaion.HORIZONTAL)
    this.addChild(this.scrollBarH)

    this.scrollBarV.on("change", e => {
      this.container.y = e.target.value
    })

    this.scrollBarH.on("change", e => {
      console.log(e.target.value)
      this.container.x = e.target.value
    })

    canvas.addEventListener("mousewheel", e => {
      const h = this.contentSize.height - this.getBounds().height
      const w = this.contentSize.width - this.getBounds().width
      this.scrollY = Math.min(0, Math.max(this.scrollY + e.wheelDeltaY, -h - SCROLL_BAR_SIZE))
      this.scrollX = Math.min(0, Math.max(this.scrollX + e.wheelDeltaX, -w - SCROLL_BAR_SIZE))
    })

    this.superAddChild = this.addChild

    this.addChild = child => {
      this.container.addChild(child)
    }
  }

  get scrollX() {
    return this.container.x
  }

  set scrollX(x) {
    this.container.x = x
    this.scrollBarH.value = x
    this.dispatchEvent("scroll")
  }

  get scrollY() {
    return this.container.y
  }

  set scrollY(y) {
    this.container.y = y
    this.scrollBarV.value = y
    this.dispatchEvent("scroll")
  }

  set contentSize(size) {
    this.container.setBounds(0, 0, size.width, size.height)
    this.scrollBarH.contentLength = size.width
    this.scrollBarV.contentLength = size.height
  }

  get contentSize() {
    return {
      width: this.container.getBounds().width,
      height: this.container.getBounds().height,
    }
  }

  setBounds(x, y, width, height) {
    super.setBounds(x, y, width, height)
    this.contentSize = {
      width: Math.max(width, this.contentSize.width),
      height: Math.max(height, this.contentSize.height)
    }

    this.scrollBarV.x = width - SCROLL_BAR_SIZE
    this.scrollBarV.size = {
      width: SCROLL_BAR_SIZE,
      height: height - SCROLL_BAR_SIZE
    }

    this.scrollBarH.y = height - SCROLL_BAR_SIZE
    this.scrollBarH.size = {
      width: width - SCROLL_BAR_SIZE,
      height: SCROLL_BAR_SIZE
    }
  }
}
<|endoftext|>


<commit_before>/*
 * containers.js: Instance methods for working with containers
 * for Openstack Object Storage
 *
 * (C) 2013 Rackspace, Ken Perkins
 * MIT LICENSE
 *
 */

var async = require('async'),
    request = require('request'),
  base = require('../../../core/storage'),
    pkgcloud = require('../../../../pkgcloud'),
    _ = require('underscore');

/**
 * client.getContainers
 *
 * @description get the list of containers for an account
 *
 * @param {object|Function}   options
 * @param {Number}            [options.limit]   the number of records to return
 * @param {String}            [options.marker]  Marker value. Operation returns object names that are greater than this value.
 * @param {String}            [options.end_marker]  Operation returns object names that are less than this value.
 * @param {Function}          callback
 */
exports.getContainers = function (options, callback) {
  var self = this;

  if (typeof options === 'function') {
    callback = options;
    options = {};
  }

  var getContainerOpts = {
    path: '',
    qs: _.extend({
      format: 'json'
    }, _.pick(options, ['limit', 'marker', 'end_marker']))
  };
  ;
  this._request(getContainerOpts, function (err, body) {
    if (err) {
      return callback(err);
    }
    else if (!body || !(body instanceof Array)) {
      return new Error('Malformed API Response')
    }

    return callback(null, body.map(function (container) {
      return new self.models.Container(self, container);
    }));
  });
};

/**
 * client.getContainer
 *
 * @description get the details for a specific container
 *
 * @param {String|object}     container     the container or containerName
 * @param callback
 */
exports.getContainer = function (container, callback) {
  var containerName = container instanceof this.models.Container ? container.name : container,
    self = this;

  this._request({
    method: 'HEAD',
    container: containerName
  }, function (err, body, res) {
    if (err) {
      return callback(err);
    }

    var details = _.extend({}, body, {
      name: containerName,
      count: parseInt(res.headers['x-container-object-count'], 10),
      bytes: parseInt(res.headers['x-container-bytes-used'], 10)
    });

    details.metadata = self.deserializeMetadata(self.CONTAINER_META_PREFIX, res.headers);

    callback(null, new self.models.Container(self, details));
  });
};

/**
 * client.createContainer
 *
 * @description create a new container
 *
 * @param {object}    options
 * @param {String}    options.name      the name of the new container
 * @param {object}    [options.metadata]  optional metadata about the container
 * @param callback
 */
exports.createContainer = function (options, callback) {
  var containerName = typeof options === 'object' ? options.name : options,
      self = this;

  var createContainerOpts = {
    method: 'PUT',
    container: containerName
  };

  if (options.metadata) {
    createContainerOpts.headers = self.serializeMetadata(self.CONTAINER_META_PREFIX, options.metadata);
  }

  this._request(createContainerOpts, function (err) {
    return err
      ? callback(err)
      : callback(null, new self.models.Container(self, { name: containerName, metadata: options.metadata }));
  });
};

/**
 * client.updateContainerMetadata
 *
 * @description Updates the metadata in the specified `container` in
 * the storage container associated with this instance.
 *
 * @param {String|object}     container     the container or containerName
 * @param callback
 */
exports.updateContainerMetadata = function (container, callback) {
  this._updateContainerMetadata(container,
    this.serializeMetadata(this.CONTAINER_META_PREFIX, container.metadata),
    callback);
};

/**
 * client.updateContainerMetadata
 *
 * @description Removes the provided `metadata` in the specified
 * `container` in the storage container associated with this instance.
 *
 * @param {String|object}     container     the container or containerName
 * @param {object}            metadataToRemove     the metadata to remove from the container
 * @param callback
 */
exports.removeContainerMetadata = function (container, metadataToRemove, callback) {
  this._updateContainerMetadata(container,
    this.serializeMetadata(this.CONTAINER_REMOVE_META_PREFIX, metadataToRemove),
    callback);
};

/**
 * client._updateContainerMetadata
 *
 * @description Convenience function for updating container metadata
 */
exports._updateContainerMetadata = function(container, metadata, callback) {
  var self = this;

  if (!(container instanceof self.models.Container)) {
    throw new Error('Must update an existing container instance');
  }

  var updateContainerOpts = {
    method: 'POST',
    container: container.name,
    headers: metadata
  };

  this._request(updateContainerOpts, function (err) {

    // omit our newly deleted header fields, if any
    if (!err) {
      container.metadata = _.omit(container.metadata,
        _.keys(self.deserializeMetadata(self.CONTAINER_REMOVE_META_PREFIX, metadata)));
    }

    return err
      ? callback(err)
      : callback(null, container);
  });
};

/**
 * client.destroyContainer
 *
 * @description Delete the storage container and all files within it
 *
 * @param {String|object}     container     the container or containerName
 * @param callback
 */
exports.destroyContainer = function (container, callback) {
  var containerName = container instanceof this.models.Container ? container.name : container,
      self = this;

  // first fetch the container, to get the count of objects
  this.getContainer(container, function(err, container) {
    if (err) {
      callback(err);
      return;
    }

    // we need to call get files, but with a limit of the current count of the container
    // with a modest offset incase of any cache staleness
    self.getFiles(container, { limit: container.count + 1000 }, function (err, files) {
      if (err) {
        return callback(err);
      }

      function deleteContainer(err) {
        if (err) {
          return callback(err);
        }

        self._request({
          method: 'DELETE',
          container: containerName
        }, function (err) {
          // if the file we're deleting returns a 404 error, ignore it
          if (err && err.statusCode === 404) {
            callback(null, false);
            return;
          }
          // non-404 case, propagate it
          else if (err) {
            callback(err);
            return;
          }

          callback(null, true);
        });
      }

      function destroyFile(file, next) {
        file.remove(next);
      }

      if (files.length === 0) {
        return deleteContainer();
      }

      async.forEachLimit(files, 15, destroyFile, deleteContainer);
    });
  });
};
<commit_msg>Removing extraneous semicolon<commit_after>/*
 * containers.js: Instance methods for working with containers
 * for Openstack Object Storage
 *
 * (C) 2013 Rackspace, Ken Perkins
 * MIT LICENSE
 *
 */

var async = require('async'),
    request = require('request'),
  base = require('../../../core/storage'),
    pkgcloud = require('../../../../pkgcloud'),
    _ = require('underscore');

/**
 * client.getContainers
 *
 * @description get the list of containers for an account
 *
 * @param {object|Function}   options
 * @param {Number}            [options.limit]   the number of records to return
 * @param {String}            [options.marker]  Marker value. Operation returns object names that are greater than this value.
 * @param {String}            [options.end_marker]  Operation returns object names that are less than this value.
 * @param {Function}          callback
 */
exports.getContainers = function (options, callback) {
  var self = this;

  if (typeof options === 'function') {
    callback = options;
    options = {};
  }

  var getContainerOpts = {
    path: '',
    qs: _.extend({
      format: 'json'
    }, _.pick(options, ['limit', 'marker', 'end_marker']))
  };

  this._request(getContainerOpts, function (err, body) {
    if (err) {
      return callback(err);
    }
    else if (!body || !(body instanceof Array)) {
      return new Error('Malformed API Response')
    }

    return callback(null, body.map(function (container) {
      return new self.models.Container(self, container);
    }));
  });
};

/**
 * client.getContainer
 *
 * @description get the details for a specific container
 *
 * @param {String|object}     container     the container or containerName
 * @param callback
 */
exports.getContainer = function (container, callback) {
  var containerName = container instanceof this.models.Container ? container.name : container,
    self = this;

  this._request({
    method: 'HEAD',
    container: containerName
  }, function (err, body, res) {
    if (err) {
      return callback(err);
    }

    var details = _.extend({}, body, {
      name: containerName,
      count: parseInt(res.headers['x-container-object-count'], 10),
      bytes: parseInt(res.headers['x-container-bytes-used'], 10)
    });

    details.metadata = self.deserializeMetadata(self.CONTAINER_META_PREFIX, res.headers);

    callback(null, new self.models.Container(self, details));
  });
};

/**
 * client.createContainer
 *
 * @description create a new container
 *
 * @param {object}    options
 * @param {String}    options.name      the name of the new container
 * @param {object}    [options.metadata]  optional metadata about the container
 * @param callback
 */
exports.createContainer = function (options, callback) {
  var containerName = typeof options === 'object' ? options.name : options,
      self = this;

  var createContainerOpts = {
    method: 'PUT',
    container: containerName
  };

  if (options.metadata) {
    createContainerOpts.headers = self.serializeMetadata(self.CONTAINER_META_PREFIX, options.metadata);
  }

  this._request(createContainerOpts, function (err) {
    return err
      ? callback(err)
      : callback(null, new self.models.Container(self, { name: containerName, metadata: options.metadata }));
  });
};

/**
 * client.updateContainerMetadata
 *
 * @description Updates the metadata in the specified `container` in
 * the storage container associated with this instance.
 *
 * @param {String|object}     container     the container or containerName
 * @param callback
 */
exports.updateContainerMetadata = function (container, callback) {
  this._updateContainerMetadata(container,
    this.serializeMetadata(this.CONTAINER_META_PREFIX, container.metadata),
    callback);
};

/**
 * client.updateContainerMetadata
 *
 * @description Removes the provided `metadata` in the specified
 * `container` in the storage container associated with this instance.
 *
 * @param {String|object}     container     the container or containerName
 * @param {object}            metadataToRemove     the metadata to remove from the container
 * @param callback
 */
exports.removeContainerMetadata = function (container, metadataToRemove, callback) {
  this._updateContainerMetadata(container,
    this.serializeMetadata(this.CONTAINER_REMOVE_META_PREFIX, metadataToRemove),
    callback);
};

/**
 * client._updateContainerMetadata
 *
 * @description Convenience function for updating container metadata
 */
exports._updateContainerMetadata = function(container, metadata, callback) {
  var self = this;

  if (!(container instanceof self.models.Container)) {
    throw new Error('Must update an existing container instance');
  }

  var updateContainerOpts = {
    method: 'POST',
    container: container.name,
    headers: metadata
  };

  this._request(updateContainerOpts, function (err) {

    // omit our newly deleted header fields, if any
    if (!err) {
      container.metadata = _.omit(container.metadata,
        _.keys(self.deserializeMetadata(self.CONTAINER_REMOVE_META_PREFIX, metadata)));
    }

    return err
      ? callback(err)
      : callback(null, container);
  });
};

/**
 * client.destroyContainer
 *
 * @description Delete the storage container and all files within it
 *
 * @param {String|object}     container     the container or containerName
 * @param callback
 */
exports.destroyContainer = function (container, callback) {
  var containerName = container instanceof this.models.Container ? container.name : container,
      self = this;

  // first fetch the container, to get the count of objects
  this.getContainer(container, function(err, container) {
    if (err) {
      callback(err);
      return;
    }

    // we need to call get files, but with a limit of the current count of the container
    // with a modest offset incase of any cache staleness
    self.getFiles(container, { limit: container.count + 1000 }, function (err, files) {
      if (err) {
        return callback(err);
      }

      function deleteContainer(err) {
        if (err) {
          return callback(err);
        }

        self._request({
          method: 'DELETE',
          container: containerName
        }, function (err) {
          // if the file we're deleting returns a 404 error, ignore it
          if (err && err.statusCode === 404) {
            callback(null, false);
            return;
          }
          // non-404 case, propagate it
          else if (err) {
            callback(err);
            return;
          }

          callback(null, true);
        });
      }

      function destroyFile(file, next) {
        file.remove(next);
      }

      if (files.length === 0) {
        return deleteContainer();
      }

      async.forEachLimit(files, 15, destroyFile, deleteContainer);
    });
  });
};
<|endoftext|>


<commit_before>var harvest = require('harvest');

module.exports = exports = function(creep) {
    if (creep.energy === 0) {
        creep.moveTo(Game.spawns.Spawn1);
        Game.spawns.Spawn1.transferEnergy(creep);
    }
    else {
        var target = creep.pos.findClosest(Game.CONSTRUCTION_SITES);
        if (target) {
            creep.moveTo(target);
            creep.build(target);
        } else {
            harvest(creep);
        }
    }
};
<commit_msg>Update build method with better fallback.<commit_after>var harvest = require('harvest');

module.exports = exports = function(creep) {
    var spawn = Game.spawns[creep.memory.spawnName];
    var target = spawn.pos.findClosest(Game.CONSTRUCTION_SITES, {
        filter: function(site) {
            return site.my;
        }
    });

    if (target) {
        if (creep.energy === 0) {
            creep.moveTo(spawn);
            spawn.transferEnergy(creep);
        } else {
            creep.moveTo(target);
            creep.build(target);
        }
    } else {
        harvest(creep);
    }
};
<|endoftext|>


<commit_before>/*
 * Copyright 2013 Next Century Corporation
 * 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.
 *
 */

charts.LineChart = function (rootElement, selector, opts) {
	opts = opts || {};
	this.chartSelector = selector;
	this.element = d3.select(rootElement).select(selector);

	this.xAttribute = opts.x;
	//this.xLabel = opts.xLabel || this.determineXLabel();
	this.yAttribute = opts.y;
	//this.yLabel = opts.yLabel || this.determineYLabel();
	this.margin = $.extend({}, charts.LineChart.DEFAULT_MARGIN, opts.margin || {});

	this.categories = [];

	/*this.viewboxXMin = 0;
	this.viewboxYMin = 0;
	this.viewboxXMax = 618;
	this.viewboxYMax = 270;*/

	//this.style = $.extend({}, charts.LineChart.DEFAULT_STYLE, opts.style);

	if (opts.responsive) {
		this.redrawOnResize();
	}
	return this;
};

charts.LineChart.DEFAULT_HEIGHT = 300;
charts.LineChart.DEFAULT_WIDTH = 600;
charts.LineChart.DEFAULT_MARGIN = {top: 20, bottom: 30, left: 40, right: 20};
charts.LineChart.DEFAULT_STYLE = {};

charts.LineChart.prototype.determineWidth = function (element) {
	if (this.userSetWidth) {
		return this.userSetWidth;
	}
	else if ($(element[0]).width() !== 0) {
		return $(element[0]).width();
	}
	return charts.LineChart.DEFAULT_WIDTH;
};

charts.LineChart.prototype.determineHeight = function (element) {
	if (this.userSetHeight) {
		return this.userSetHeight;
	}
	else if ($(element[0]).height() !== 0) {
		return $(element[0]).height();
	}
	return charts.LineChart.DEFAULT_HEIGHT;
};

charts.LineChart.prototype.categoryForItem = function (item) {
	var me = this;
	if (typeof this.xAttribute === 'function') {
		return this.xAttribute.call(this, item);
	}

	return item[this.xAttribute];
};

charts.LineChart.prototype.createCategories = function (data) {
	var me = this;
	return _.chain(data)
		.map(function (item) {
			return me.categoryForItem(item);
		})
		.unique()
		.filter(function (item) {
			return !_.isNull(item) && !_.isUndefined(item);
		})
		.sort(charts.LineChart.sortComparator)
		.value();
};

charts.LineChart.sortComparator = function (a, b) {
	if (a instanceof Date && b instanceof Date) {
		return charts.LineChart.compareValues(a.getTime(), b.getTime());
	}
	return charts.LineChart.compareValues(a, b);
};

charts.LineChart.compareValues = function (a, b) {
	if (a < b) {
		return -1;
	}
	if (a > b) {
		return 1;
	}
	return 0;
};

charts.LineChart.prototype.drawChart = function() {
	var me = this;

	$(this.element[0]).empty();

	me.height = me.determineHeight(me.element);
	me.width = me.determineWidth(me.element);

	//me.x = d3.time.scale().range([0, me.width]);

	me.svg = me.element.append("svg")
		.attr("width", me.width)// + me.margin.left + me.margin.right)
		.attr("height", me.height) //+ me.margin.top + me.margin.bottom)
	.append("g")
		.attr("transform", "translate(" + me.margin.left + "," + me.margin.top + ")");
};

charts.LineChart.prototype.drawLine = function(opts) {
	var me = this;

	if(!($.isArray(opts))) {
		opts = [opts];
	}

	me.data = opts;

	var fullDataSet = [];
	//get list of all data
	for(var i = 0; i < opts.length; i++) {
		fullDataSet = fullDataSet.concat(opts[i].data);
	}

	me.categories = me.createCategories(fullDataSet);

	me.x =  d3.scale.ordinal()
		.domain(me.categories)
		.rangePoints([0, (me.width - (me.margin.left + me.margin.right))],.25);

	var xAxis = d3.svg.axis()
		.scale(me.x)
		.orient("bottom");

	me.svg.append("g")
		.attr("class", "x axis")
		.attr("transform", "translate(0," + (me.height - (me.margin.top + me.margin.bottom)) + ")")
		.call(xAxis);

	me.y = d3.scale.linear().range([(me.height - (me.margin.top + me.margin.bottom)), 0]);

	var yAxis = d3.svg.axis()
		.scale(me.y)
		.orient("left");

	me.y.domain([0, d3.max(fullDataSet, function(d) { return d[me.yAttribute]; })]);

	me.svg.append("g")
		.attr("class", "y axis")
		.call(yAxis)
	.append("text")
		.attr("transform", "rotate(-90)")
		.attr("y", 6)
		.attr("dy", ".71em")
		.style("text-anchor", "end")
		.text(me.yAttribute);

	var cls;
	var data;
	var line;
	for(var i = 0; i < opts.length; i++) {
		cls = (opts[i].classString ? " " + opts[i].classString : "");
		data = opts[i].data;

		data = data.sort(function(a,b) {
			if(a[me.xAttribute] < b[me.xAttribute]) {
				return -1;
			} else if(a[me.xAttribute] === b[me.xAttribute]) {
				return 0;
			} else {
				return 1;
			}
		});

		line = d3.svg.line()
		.x(function(d) {
			return me.x(d[me.xAttribute]); })
		.y(function(d) { return me.y(d[me.yAttribute]); });

		me.svg.append("path")
		.datum(data)
		.attr("class", "line" + cls)
		.attr("d", line);

		if(data.length < 40){
			me.svg.selectAll("dot")
	            .data(data)
	          .enter().append("circle")
	            .attr("class", "dot" + cls)
	            .attr("r", 4)
	            .attr("cx", function(d) { return me.x(d[me.xAttribute]); })
	            .attr("cy", function(d) { return me.y(d[me.yAttribute]); });
	    }
	}
};

charts.LineChart.prototype.redrawOnResize = function () {
	var me = this;

	function drawChart() {
		me.drawChart();
		if(me.data) {
			me.drawLine(me.data);
		}
	}

	// Debounce is needed because browser resizes fire this resize even multiple times.
	// Cache the handler so we can remove it from the window on destroy.
	me.resizeHandler = _.debounce(drawChart, 10);
	$(window).resize(me.resizeHandler);

};

charts.LineChart.destroy = function(el, selector) {
	var element = d3.select(el).select(selector);
	$(window).off('resize', this.resizeHandler);
	$(element[0]).empty();
};<commit_msg>Adjusted line chart margins and remove Y-axis label<commit_after>/*
 * Copyright 2013 Next Century Corporation
 * 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.
 *
 */

charts.LineChart = function (rootElement, selector, opts) {
	opts = opts || {};
	this.chartSelector = selector;
	this.element = d3.select(rootElement).select(selector);

	this.xAttribute = opts.x;
	//this.xLabel = opts.xLabel || this.determineXLabel();
	this.yAttribute = opts.y;
	//this.yLabel = opts.yLabel || this.determineYLabel();
	this.margin = $.extend({}, charts.LineChart.DEFAULT_MARGIN, opts.margin || {});

	this.categories = [];

	/*this.viewboxXMin = 0;
	this.viewboxYMin = 0;
	this.viewboxXMax = 618;
	this.viewboxYMax = 270;*/

	//this.style = $.extend({}, charts.LineChart.DEFAULT_STYLE, opts.style);

	if (opts.responsive) {
		this.redrawOnResize();
	}
	return this;
};

charts.LineChart.DEFAULT_HEIGHT = 300;
charts.LineChart.DEFAULT_WIDTH = 600;
charts.LineChart.DEFAULT_MARGIN = {top: 20, bottom: 30, left: 35, right: 20};
charts.LineChart.DEFAULT_STYLE = {};

charts.LineChart.prototype.determineWidth = function (element) {
	if (this.userSetWidth) {
		return this.userSetWidth;
	}
	else if ($(element[0]).width() !== 0) {
		return $(element[0]).width();
	}
	return charts.LineChart.DEFAULT_WIDTH;
};

charts.LineChart.prototype.determineHeight = function (element) {
	if (this.userSetHeight) {
		return this.userSetHeight;
	}
	else if ($(element[0]).height() !== 0) {
		return $(element[0]).height();
	}
	return charts.LineChart.DEFAULT_HEIGHT;
};

charts.LineChart.prototype.categoryForItem = function (item) {
	var me = this;
	if (typeof this.xAttribute === 'function') {
		return this.xAttribute.call(this, item);
	}

	return item[this.xAttribute];
};

charts.LineChart.prototype.createCategories = function (data) {
	var me = this;
	return _.chain(data)
		.map(function (item) {
			return me.categoryForItem(item);
		})
		.unique()
		.filter(function (item) {
			return !_.isNull(item) && !_.isUndefined(item);
		})
		.sort(charts.LineChart.sortComparator)
		.value();
};

charts.LineChart.sortComparator = function (a, b) {
	if (a instanceof Date && b instanceof Date) {
		return charts.LineChart.compareValues(a.getTime(), b.getTime());
	}
	return charts.LineChart.compareValues(a, b);
};

charts.LineChart.compareValues = function (a, b) {
	if (a < b) {
		return -1;
	}
	if (a > b) {
		return 1;
	}
	return 0;
};

charts.LineChart.prototype.drawChart = function() {
	var me = this;

	$(this.element[0]).empty();

	me.height = me.determineHeight(me.element);
	me.width = me.determineWidth(me.element);

	//me.x = d3.time.scale().range([0, me.width]);

	me.svg = me.element.append("svg")
		.attr("width", me.width)// + me.margin.left + me.margin.right)
		.attr("height", me.height) //+ me.margin.top + me.margin.bottom)
	.append("g")
		.attr("transform", "translate(" + me.margin.left + "," + me.margin.top + ")");
};

charts.LineChart.prototype.drawLine = function(opts) {
	var me = this;

	if(!($.isArray(opts))) {
		opts = [opts];
	}

	me.data = opts;

	var fullDataSet = [];
	//get list of all data
	for(var i = 0; i < opts.length; i++) {
		fullDataSet = fullDataSet.concat(opts[i].data);
	}

	me.categories = me.createCategories(fullDataSet);

	me.x =  d3.scale.ordinal()
		.domain(me.categories)
		.rangePoints([0, (me.width - (me.margin.left + me.margin.right))],.25);

	var xAxis = d3.svg.axis()
		.scale(me.x)
		.orient("bottom");

	me.svg.append("g")
		.attr("class", "x axis")
		.attr("transform", "translate(0," + (me.height - (me.margin.top + me.margin.bottom)) + ")")
		.call(xAxis);

	me.y = d3.scale.linear().range([(me.height - (me.margin.top + me.margin.bottom)), 0]);

	var yAxis = d3.svg.axis()
		.scale(me.y)
		.orient("left");

	me.y.domain([0, d3.max(fullDataSet, function(d) { return d[me.yAttribute]; })]);

	me.svg.append("g")
		.attr("class", "y axis")
		.call(yAxis);
	// .append("text")
	// 	.attr("transform", "rotate(-90)")
	// 	.attr("y", 6)
	// 	.attr("dy", ".71em")
	// 	.style("text-anchor", "end")
	// 	.text(me.yAttribute);

	var cls;
	var data;
	var line;
	for(var i = 0; i < opts.length; i++) {
		cls = (opts[i].classString ? " " + opts[i].classString : "");
		data = opts[i].data;

		data = data.sort(function(a,b) {
			if(a[me.xAttribute] < b[me.xAttribute]) {
				return -1;
			} else if(a[me.xAttribute] === b[me.xAttribute]) {
				return 0;
			} else {
				return 1;
			}
		});

		line = d3.svg.line()
		.x(function(d) {
			return me.x(d[me.xAttribute]); })
		.y(function(d) { return me.y(d[me.yAttribute]); });

		me.svg.append("path")
		.datum(data)
		.attr("class", "line" + cls)
		.attr("d", line);

		if(data.length < 40){
			me.svg.selectAll("dot")
	            .data(data)
	          .enter().append("circle")
	            .attr("class", "dot" + cls)
	            .attr("r", 4)
	            .attr("cx", function(d) { return me.x(d[me.xAttribute]); })
	            .attr("cy", function(d) { return me.y(d[me.yAttribute]); });
	    }
	}
};

charts.LineChart.prototype.redrawOnResize = function () {
	var me = this;

	function drawChart() {
		me.drawChart();
		if(me.data) {
			me.drawLine(me.data);
		}
	}

	// Debounce is needed because browser resizes fire this resize even multiple times.
	// Cache the handler so we can remove it from the window on destroy.
	me.resizeHandler = _.debounce(drawChart, 10);
	$(window).resize(me.resizeHandler);

};

charts.LineChart.destroy = function(el, selector) {
	var element = d3.select(el).select(selector);
	$(window).off('resize', this.resizeHandler);
	$(element[0]).empty();
};<|endoftext|>


<commit_before>'use strict';

// Requires utiljs.js

if (typeof GJS === "undefined") {
    var GJS = {};
}

/**
 * An object that owns a THREE.Object3D.
 * @constructor
 */
GJS.ThreeSceneObject = function() {
};

/**
 * Initialize.
 * @param {Object} options Options with the following keys:
 *   sceneParent (Object3D): Parent of the object in the scene.
 *   object (Object3D): Object that this object will own and add under sceneParent.
 */
GJS.ThreeSceneObject.prototype.initThreeSceneObject = function(options) {
    var defaults = {
        sceneParent: null,
        object: null
    };
    objectUtil.initWithDefaults(this, defaults, options);
    this._inScene = false;
};

/**
 * Add this object to the scene if it is not there.
 */
GJS.ThreeSceneObject.prototype.addToScene = function() {
    if (!this._inScene) {
        this.sceneParent.add(this.object);
        this._inScene = true;
    }
};

/**
 * Remove this object from the scene if it is in there.
 */
GJS.ThreeSceneObject.prototype.removeFromScene = function() {
    if (this._inScene) {
        this.sceneParent.remove(this.object);
        this._inScene = false;
    }
};

/**
 * @param {THREE.Object3D} object Object to query.
 * @return {boolean} True if object is in the owned part of the scene graph.
 */
GJS.ThreeSceneObject.prototype.ownsSceneObject = function(object) {
    var matches = false;
    this.getOwnQueryObject().traverse(function(obj) {
        if (obj === object) {
            matches = true;
        }
    });
    return matches;
};

/**
 * Override this to customize which parts of the scene this object is considered to own for the purposes of
 * ownsSceneObject.
 * @return {THREE.Object3D} object this object owns
 */
GJS.ThreeSceneObject.prototype.getOwnQueryObject = function() {
    return this.object;
};

/**
 * Update the object. Override this to do time-based updates.
 */
GJS.ThreeSceneObject.prototype.update = function(deltaTime) {
};
<commit_msg>Add three.js text helpers<commit_after>'use strict';

// Requires utiljs.js

if (typeof GJS === "undefined") {
    var GJS = {};
}

/**
 * An object that owns a THREE.Object3D.
 * @constructor
 */
GJS.ThreeSceneObject = function() {
};

/**
 * Initialize.
 * @param {Object} options Options with the following keys:
 *   sceneParent (Object3D): Parent of the object in the scene.
 *   object (Object3D): Object that this object will own and add under sceneParent.
 */
GJS.ThreeSceneObject.prototype.initThreeSceneObject = function(options) {
    var defaults = {
        sceneParent: null,
        object: null
    };
    objectUtil.initWithDefaults(this, defaults, options);
    this._inScene = false;
};

/**
 * Add this object to the scene if it is not there.
 */
GJS.ThreeSceneObject.prototype.addToScene = function() {
    if (!this._inScene) {
        this.sceneParent.add(this.object);
        this._inScene = true;
    }
};

/**
 * Remove this object from the scene if it is in there.
 */
GJS.ThreeSceneObject.prototype.removeFromScene = function() {
    if (this._inScene) {
        this.sceneParent.remove(this.object);
        this._inScene = false;
    }
};

/**
 * @param {THREE.Object3D} object Object to query.
 * @return {boolean} True if object is in the owned part of the scene graph.
 */
GJS.ThreeSceneObject.prototype.ownsSceneObject = function(object) {
    var matches = false;
    this.getOwnQueryObject().traverse(function(obj) {
        if (obj === object) {
            matches = true;
        }
    });
    return matches;
};

/**
 * Override this to customize which parts of the scene this object is considered to own for the purposes of
 * ownsSceneObject.
 * @return {THREE.Object3D} object this object owns
 */
GJS.ThreeSceneObject.prototype.getOwnQueryObject = function() {
    return this.object;
};

/**
 * Update the object. Override this to do time-based updates.
 */
GJS.ThreeSceneObject.prototype.update = function(deltaTime) {
};

/**
 * Base type for objects that display a text string as a Three.js mesh.
 * Use classes that inherit this class, like GJS.ThreeExtrudedTextObject to display text in the 3D scene.
 * @constructor
 */
GJS.ThreeTextObject = function() {
};

GJS.ThreeTextObject.prototype = new GJS.ThreeSceneObject();

/**
 * @param {Object} options
 */
GJS.ThreeTextObject.prototype.initThreeTextObject = function(options) {
    var defaults = {
        string: "",
        maxRowLength: -1,
        rowSpacing: 1.3,
        textAlign: 'center'
    };
    objectUtil.initWithDefaults(this, defaults, options);

    this.initThreeSceneObject(options);
    this.object = new THREE.Object3D();

    var string = this.string;
    this.string = "";
    this.setString(string);
};

/**
 * @param {string} string String to display.
 */
GJS.ThreeTextObject.prototype.setString = function(string) {
    this.string = string;
    this.stringSplitToRows = stringUtil.splitToRows(this.string, this.maxRowLength);
};

/**
 * An object that displays a text string as an extruded Three.js mesh.
 * To use this, first set GJS.ThreeExtrudedTextObject.defaultFont. You can use GJS.utilTHREE.loadFont to load the font.
 * The scene object that acts as a parent to the text will be stored under the property "object" and can be accessed
 * directly to set its model transform or to add additional children.
 * @param {Object} options Options with the following keys, in addition to THREE.TextGeometry and ThreeSceneObject
 * options:
 *   string (string)
 *   maxRowLength (number): Maximum row length in characters.
 *   rowSpacing (number): Relative spacing of rows.
 *   textAlign (string): 'left', 'center' or 'right'
 *   receiveShadow (boolean)
 *   castShadow (boolean)
 * @constructor
 */
GJS.ThreeExtrudedTextObject = function(options) {
    var defaults = {
        material: GJS.ThreeExtrudedTextObject.defaultMaterial,
        font: GJS.ThreeExtrudedTextObject.defaultFont,
        extrusionHeight: 0.1,
        curveSegments: 1,
        bevelEnabled: false,
        castShadow: false,
        receiveShadow: false
    };
    objectUtil.initWithDefaults(this, defaults, options);
    this.rowMeshes = [];
    this.initThreeTextObject(options);
};

GJS.ThreeExtrudedTextObject.defaultMaterial = new THREE.MeshPhongMaterial( { color: 0x333333, specular: 0x000000 } );
GJS.ThreeExtrudedTextObject.defaultFont = null;

GJS.ThreeExtrudedTextObject.prototype = new GJS.ThreeTextObject();

/**
 * @param {string} string String to display.
 */
GJS.ThreeExtrudedTextObject.prototype.setString = function(string) {
    if (string != this.string) {
        GJS.ThreeTextObject.prototype.setString.call(this, string);
        for (var i = 0; i < this.rowMeshes.length; ++i) {
            this.object.remove(this.rowMeshes[i]);
        }
        this.rowMeshes.splice(0);
        for (var i = 0; i < this.stringSplitToRows.length; ++i) {
            var rowMesh = this._createTextMesh(this.stringSplitToRows[i]);
            if (this.textAlign === 'left') {
                rowMesh.position.x = -rowMesh.geometry.boundingBox.min.x;
            } else if (this.textAlign === 'right') {
                rowMesh.position.x = -rowMesh.geometry.boundingBox.max.x;
            }
            rowMesh.position.y = (this.stringSplitToRows.length - i - 0.5) * this.rowSpacing;
            this.object.add(rowMesh);
            this.rowMeshes.push(rowMesh);
        }
    }
};

/**
 * @param {string} string String to create a mesh for.
 * @return {THREE.Object3D} Text geometry object.
 */
GJS.ThreeExtrudedTextObject.prototype._createTextMesh = function(string) {
    var textGeo = new THREE.TextGeometry( string, {
        font: this.font,
        size: 1,
        height: this.extrusionHeight,
        curveSegments: this.curveSegments,
        bevelEnabled: this.bevelEnabled,
    });
    textGeo.center();
    textGeo.computeBoundingBox();
    var textMesh = new THREE.Mesh( textGeo, this.material );
    textMesh.castShadow = this.castShadow;
    textMesh.receiveShadow = this.receiveShadow;
    return textMesh;
};
<|endoftext|>


<commit_before>var models = require("../../models")
module.exports = function(screenName,id){
    return new Promise(function(resolve,reject){
      if(!screenName && !id){
        return reject("screenName-or-id-require")
      }
      function retUser(err,res){
        if(!res){
          return reject("not-found-user")
        }
        return resolve(res)
      }
      if(screenName) {
        models.users.findOne({screenNameLower:screenName.toLowerCase()},retUser)
      } else {
        models.users.findOne({_id:models.mongoose.Types.ObjectId(id)},retUser)
      }
    })
}
<commit_msg>fix indent<commit_after>var models = require("../../models")
module.exports = function(screenName,id){
    return new Promise(function(resolve,reject){
        if(!screenName && !id){
            return reject("screenName-or-id-require")
        }
        function retUser(err,res){
            if(!res){
                return reject("not-found-user")
            }
            return resolve(res)
        }
        if(screenName) {
            models.users.findOne({screenNameLower:screenName.toLowerCase()},retUser)
        } else {
            models.users.findOne({_id:models.mongoose.Types.ObjectId(id)},retUser)
        }
    })
}
<|endoftext|>


<commit_before>jQuery(function(){
    var elements = {
        navlinks: jQuery('ul.navlinks > li > a[href][title]')
    };

    elements.navlinks.qtip({
        position: {
            corner: {
                target: 'bottomMiddle',
                tooltip: 'topMiddle'
            }
        },
        content: {
            text: false
        },
        style: {
            fontFamily: '"Lucida Grande", "Corbel", "Lucida Sans Unicode", "Lucida Sans", "DejaVu Sans", "Bitstream Vera Sans", "Liberation Sans", "Verdana", "Verdana Ref", "sans-serif"',
            border: {
                radius: 5,
                width: 0
            },
            name: 'dark',
            tip: 'topMiddle'
        },
        show: {
            delay: 5
        }
    });
});
<commit_msg>create an effect with the navtips<commit_after>jQuery(function(){
    var elements = {
        navlinks: jQuery('ul.navlinks > li > a[href][title]')
    };

    elements.navlinks.qtip({
        position: {
            corner: {
                target: 'bottomMiddle',
                tooltip: 'topMiddle'
            }
        },
        content: {
            text: false
        },
        style: {
            fontFamily: '"Lucida Grande", "Corbel", "Lucida Sans Unicode", "Lucida Sans", "DejaVu Sans", "Bitstream Vera Sans", "Liberation Sans", "Verdana", "Verdana Ref", "sans-serif"',
            border: {
                radius: 5,
                width: 0
            },
            name: 'dark',
            tip: 'topMiddle'
        },
        show: {
            delay: 10
        },
        hide: {
            delay: 150
        }
    });
});
<|endoftext|>


<commit_before>// Requires for the server-side context. *TODO* Note that `var` is omitted here
// because even within the `if()` IE will wipe globally defined variables if
// `var` is included, leaving us with broken objects.
if (typeof require !== 'undefined') {
    _ = require('underscore')._
    Backbone = require('backbone.js'),
    Bones = require('bones'),
    require('./models'); // Bones mixin.
}

var Bones = Bones || {};
Bones.views = Bones.views || {};

// Add `route()` method for handling normally linked paths into hash paths.
// Because IE7 provides an absolute URL for `attr('href')`, regex out the
// internal path and use it as the fragment.
Backbone.View = Backbone.View.extend({
    events: {
        'click a.route': 'route'
    },
    route: function(ev) {
        var fragment;
        if (_.isString(ev)) {
            fragment = ev;
        } else {
            fragment = $(ev.currentTarget).get(0).getAttribute('href', 2);
            if ($.browser.msie && $.browser.version < 8) {
                fragment = /^([a-z]+:\/\/.+?)?(\/.+?)$/.exec(fragment)[2];
            }
        }
        if (fragment.charAt(0) === '/') {
            var matched = _.any(Backbone.history.handlers, function(handler) {
                if (handler.route.test(fragment)) {
                    handler.callback(fragment);
                    return true;
                }
            });
            if (matched) {
                Backbone.history.saveLocation(fragment);
                return false;
            }
        }
        return true;
    }
});

// App
// ---
// View representing the entire app viewport. The view that should "fill" the
// viewport should be passed as `options.view`. When the View's element has
// been successfully added to the DOM a `ready` event will be triggered on that
// view.
Bones.views.App = Backbone.View.extend({
    initialize: function(options) {
        _.bindAll(this, 'render');
        this.render().trigger('attach');
    },
    render: function() {
        // Server side.
        if (Bones.server) {
            this.el = this.template('App', {
                content: this.options.view.html()
            });
            return this;
        }
        // Client side.
        $('body').attr('class', '');
        $('#app').html(this.options.view.el);
        this.options.view.trigger('ready');
        return this;
    }
});

// ErrorView
// ---------
// Error view.
Bones.views.Error = Backbone.View.extend({
    initialize: function(options) {
        _.bindAll(this, 'render');
        this.render().trigger('attach');
    },
    render: function() {
        $(this.el).html(this.template('Error', {
            message: this.options.message
        }));
        return this;
    }
});

// MapPreview
// ----------
// A web map client for displaying tile-based maps.
Bones.views.MapClient = Backbone.View.extend({
    className: 'MapClient',
    id: 'openlayers-map',
    initialize: function(options) {
        _.bindAll(this, 'ready', 'zoom', 'record');
    },
    ready: function() {
        var that = this;
        $.jsonp({
            url: this.waxURL(this.generateWax()),
            context: this,
            callback: 'grid',
            callbackParameter: 'callback',
            success: this.record,
            error: function() {}
        });
    },
    waxURL: function(wax) {
        return '/wax.json?' + $.param(wax);
    },
    generateWax: function(callback) {
        return _(this.model.wax()).extend({el: $(this.el).attr('id')});
    },
    record: function(data) {
        if (data && data.wax) {
            this.openlayers = wax.Record(data.wax);
            if (this.openlayers.events && this.openlayers.events.register) {
                this.openlayers.events.register(
                    'moveend',
                    this.openlayers,
                    this.zoom
                );
                this.openlayers.events.register(
                    'zoomend',
                    this.openlayers,
                    this.zoom
                );
                this.zoom({element: this.openlayers.div});
            }
        }
    },
    zoom: function(e) {
        if (!$('.zoom').size()) return;
        var zoom = this.model.get('minzoom') + this.openlayers.getZoom();
        $('.zoom.active').removeClass('active');
        $('.zoom-' + zoom).addClass('active');
    }
});

// HUD
// ---
// Base view that supports toggling on/off HUD displays.
Bones.views.HUD = Backbone.View.extend({
    initialize: function(options) {
        _.bindAll(this, 'hud', 'show', 'hide');
    },
    events: _.extend({
        'click .buttons a': 'hud'
    }, Backbone.View.prototype.events),
    hud: function(ev) {
        var link = $(ev.currentTarget);
        var hud = !link.is('.active')
            ? link.attr('href').split('#').pop()
            : false;
        this.hide();
        (hud) && (this.show(hud));
        return false;
    },
    show: function(hud) {
        this.hud = hud;
        $('.buttons a[href=#' + hud + ']').addClass('active');
        this.$('.hud.' + hud).addClass('active');
        $('body').addClass('hudActive');
        return this;
    },
    hide: function() {
        this.$('.buttons .active').removeClass('active');
        this.$('.hud.active').removeClass('active');
        $('body').removeClass('hudActive');
        return this;
    }
});

// Map
// ---
// View for exploring a single Map. Provides a fullscreen map client with HUD
// panels for enabled features (e.g. info, download, etc.)
Bones.views.Map = Bones.views.HUD.extend({
    initialize: function(options) {
        Bones.views.HUD.prototype.initialize.call(this, options);
        _.bindAll(this, 'render', 'ready', 'controlZoom', 'format');
        this.render().trigger('attach');
    },
    format: function(type, value) {
        switch (type) {
        case 'deg':
            return parseInt(value * 100, 10) / 100;
            break;
        case 'url':
            var id = this.model.id;
            return _.map(value, function(layer) {
                return layer + '1.0.0/' + id + '/{z}/{x}/{y}';
            });
            break;
        case 'download':
            return value + 'download/' + this.model.id + '.mbtiles';
            break;
        case 'size':
            return (Math.ceil(parseInt(value) / 1048576)) + ' MB';
            break;
        }
    },
    render: function() {
        $(this.el).html(this.template('Map', {
            features: Bones.settings.features,
            id: this.model.get('id'),
            name: this.model.get('name'),
            zoom: _.range(this.model.get('minzoom'), this.model.get('maxzoom') + 1),
            description: this.model.get('description') || null,
            type: this.model.get('type') || null,
            bounds: {
                w: this.format('deg', this.model.get('bounds')[0]),
                s: this.format('deg', this.model.get('bounds')[1]),
                e: this.format('deg', this.model.get('bounds')[2]),
                n: this.format('deg', this.model.get('bounds')[3])
            },
            url: this.format('url', this.model.layerURL()),
            download: this.format('download', this.model.layerURL()[0]),
            size: this.format('size', this.model.get('size'))
        }));
        this.map = new Bones.views.MapClient({model: this.model});
        this.bind('ready', this.map.ready);
        $(this.el).append(this.map.el);
        return this;
    }
});

// Maps
// ----
// View showing each map as a thumbnail. Main map browsing page.
Bones.views.Maps = Bones.views.HUD.extend({
    initialize: function(options) {
        Bones.views.HUD.prototype.initialize.call(this, options);
        _.bindAll(this, 'render');
        this.render().trigger('attach');
    },
    render: function() {
        $(this.el).html(this.template('Maps'));
        var that = this;
        this.collection.each(function(tileset) {
            tileset.view = new Bones.views.MapThumb({ model: tileset });
            $('ul.maps', that.el).append(tileset.view.el);
        });
        return this;
    }
});

// MapThumb
// --------
// Thumbnail view of a single map.
Bones.views.MapThumb = Backbone.View.extend({
    tagName: 'li',
    className: 'clearfix',
    initialize: function(options) {
        this.render().trigger('attach');
    },
    render: function() {
        $(this.el).html(this.template('MapThumb', {
            id: this.model.get('id'),
            name: this.model.get('name'),
            thumb: this.model.thumb()
        }));
        return this;
    }
});

(typeof module !== 'undefined') && (module.exports = Bones.views);

<commit_msg>Make mapclient view API pluggable.<commit_after>// Requires for the server-side context. *TODO* Note that `var` is omitted here
// because even within the `if()` IE will wipe globally defined variables if
// `var` is included, leaving us with broken objects.
if (typeof require !== 'undefined') {
    _ = require('underscore')._
    Backbone = require('backbone.js'),
    Bones = require('bones'),
    require('./models'); // Bones mixin.
}

var Bones = Bones || {};
Bones.views = Bones.views || {};

// Add `route()` method for handling normally linked paths into hash paths.
// Because IE7 provides an absolute URL for `attr('href')`, regex out the
// internal path and use it as the fragment.
Backbone.View = Backbone.View.extend({
    events: {
        'click a.route': 'route'
    },
    route: function(ev) {
        var fragment;
        if (_.isString(ev)) {
            fragment = ev;
        } else {
            fragment = $(ev.currentTarget).get(0).getAttribute('href', 2);
            if ($.browser.msie && $.browser.version < 8) {
                fragment = /^([a-z]+:\/\/.+?)?(\/.+?)$/.exec(fragment)[2];
            }
        }
        if (fragment.charAt(0) === '/') {
            var matched = _.any(Backbone.history.handlers, function(handler) {
                if (handler.route.test(fragment)) {
                    handler.callback(fragment);
                    return true;
                }
            });
            if (matched) {
                Backbone.history.saveLocation(fragment);
                return false;
            }
        }
        return true;
    }
});

// App
// ---
// View representing the entire app viewport. The view that should "fill" the
// viewport should be passed as `options.view`. When the View's element has
// been successfully added to the DOM a `ready` event will be triggered on that
// view.
Bones.views.App = Backbone.View.extend({
    initialize: function(options) {
        _.bindAll(this, 'render');
        this.render().trigger('attach');
    },
    render: function() {
        // Server side.
        if (Bones.server) {
            this.el = this.template('App', {
                content: this.options.view.html()
            });
            return this;
        }
        // Client side.
        $('body').attr('class', '');
        $('#app').html(this.options.view.el);
        this.options.view.trigger('ready');
        return this;
    }
});

// ErrorView
// ---------
// Error view.
Bones.views.Error = Backbone.View.extend({
    initialize: function(options) {
        _.bindAll(this, 'render');
        this.render().trigger('attach');
    },
    render: function() {
        $(this.el).html(this.template('Error', {
            message: this.options.message
        }));
        return this;
    }
});

// MapPreview
// ----------
// A web map client for displaying tile-based maps.
Bones.views.MapClient = Backbone.View.extend({
    className: 'MapClient',
    id: 'openlayers-map',
    initialize: function(options) {
        _.bindAll(this, 'ready', 'zoom', 'record', 'ol', 'olNav');
    },
    ready: function() {
        var that = this;
        $.jsonp({
            url: this.waxURL(this.generateWax()),
            context: this,
            callback: 'grid',
            callbackParameter: 'callback',
            success: this.record,
            error: function() {}
        });
    },
    waxURL: function(wax) {
        return '/wax.json?' + $.param(wax);
    },
    generateWax: function(callback) {
        return _(this.model.wax()).extend({el: $(this.el).attr('id')});
    },
    record: function(data) {
        if (data && data.wax) {
            var api = this.generateWax().api;
            this.map = wax.Record(data.wax);
            _(this[api]).isFunction() && this[api]();
        }
    },
    ol: function() {
        this.map.events.register('moveend', this.map, this.olNav);
        this.map.events.register('zoomend', this.map, this.olNav);
        this.olNav({element: this.map.div});
    },
    olNav: function(e) {
        if (!$('.zoom').size()) return;
        var zoom = this.model.get('minzoom') + this.map.getZoom();
        $('.zoom.active').removeClass('active');
        $('.zoom-' + zoom).addClass('active');
    }
});

// HUD
// ---
// Base view that supports toggling on/off HUD displays.
Bones.views.HUD = Backbone.View.extend({
    initialize: function(options) {
        _.bindAll(this, 'hud', 'show', 'hide');
    },
    events: _.extend({
        'click .buttons a': 'hud'
    }, Backbone.View.prototype.events),
    hud: function(ev) {
        var link = $(ev.currentTarget);
        var hud = !link.is('.active')
            ? link.attr('href').split('#').pop()
            : false;
        this.hide();
        (hud) && (this.show(hud));
        return false;
    },
    show: function(hud) {
        this.hud = hud;
        $('.buttons a[href=#' + hud + ']').addClass('active');
        this.$('.hud.' + hud).addClass('active');
        $('body').addClass('hudActive');
        return this;
    },
    hide: function() {
        this.$('.buttons .active').removeClass('active');
        this.$('.hud.active').removeClass('active');
        $('body').removeClass('hudActive');
        return this;
    }
});

// Map
// ---
// View for exploring a single Map. Provides a fullscreen map client with HUD
// panels for enabled features (e.g. info, download, etc.)
Bones.views.Map = Bones.views.HUD.extend({
    initialize: function(options) {
        Bones.views.HUD.prototype.initialize.call(this, options);
        _.bindAll(this, 'render', 'ready', 'controlZoom', 'format');
        this.render().trigger('attach');
    },
    format: function(type, value) {
        switch (type) {
        case 'deg':
            return parseInt(value * 100, 10) / 100;
            break;
        case 'url':
            var id = this.model.id;
            return _.map(value, function(layer) {
                return layer + '1.0.0/' + id + '/{z}/{x}/{y}';
            });
            break;
        case 'download':
            return value + 'download/' + this.model.id + '.mbtiles';
            break;
        case 'size':
            return (Math.ceil(parseInt(value) / 1048576)) + ' MB';
            break;
        }
    },
    render: function() {
        $(this.el).html(this.template('Map', {
            features: Bones.settings.features,
            id: this.model.get('id'),
            name: this.model.get('name'),
            zoom: _.range(this.model.get('minzoom'), this.model.get('maxzoom') + 1),
            description: this.model.get('description') || null,
            type: this.model.get('type') || null,
            bounds: {
                w: this.format('deg', this.model.get('bounds')[0]),
                s: this.format('deg', this.model.get('bounds')[1]),
                e: this.format('deg', this.model.get('bounds')[2]),
                n: this.format('deg', this.model.get('bounds')[3])
            },
            url: this.format('url', this.model.layerURL()),
            download: this.format('download', this.model.layerURL()[0]),
            size: this.format('size', this.model.get('size'))
        }));
        this.map = new Bones.views.MapClient({model: this.model});
        this.bind('ready', this.map.ready);
        $(this.el).append(this.map.el);
        return this;
    }
});

// Maps
// ----
// View showing each map as a thumbnail. Main map browsing page.
Bones.views.Maps = Bones.views.HUD.extend({
    initialize: function(options) {
        Bones.views.HUD.prototype.initialize.call(this, options);
        _.bindAll(this, 'render');
        this.render().trigger('attach');
    },
    render: function() {
        $(this.el).html(this.template('Maps'));
        var that = this;
        this.collection.each(function(tileset) {
            tileset.view = new Bones.views.MapThumb({ model: tileset });
            $('ul.maps', that.el).append(tileset.view.el);
        });
        return this;
    }
});

// MapThumb
// --------
// Thumbnail view of a single map.
Bones.views.MapThumb = Backbone.View.extend({
    tagName: 'li',
    className: 'clearfix',
    initialize: function(options) {
        this.render().trigger('attach');
    },
    render: function() {
        $(this.el).html(this.template('MapThumb', {
            id: this.model.get('id'),
            name: this.model.get('name'),
            thumb: this.model.thumb()
        }));
        return this;
    }
});

(typeof module !== 'undefined') && (module.exports = Bones.views);

<|endoftext|>


<commit_before>const assert = require('assert');

// ---------------------------------
// render()
// ---------------------------------

describe('render()', () => {

  const config = {};
  config.bnnSize = require('../src/bnnSize.js'),
  config.bnnPosition = require('../src/bnnPosition.js'),
  config.bnnGradient = require('../src/bnnGradient.js'),
  config.bnnImport = require('../src/bnnImport.js'),
  config.bnnAlign = require('../src/bnnAlign.js');

  const banana = require('../src/banana.js');
  // render() test 1
  it("should return the fully rendered css", () => {
    const stylesheet = ".a {color:#000;bnn-size: 50px 100px;}.b {color:#000;bnn-position: 10px 5px 8px 90px;margin: 10px;}";
    const result = banana.run(config).render("teste.bnn", stylesheet);
    const expect = ".a {\n  color: #000;\n  width: 50px;\n  height: 100px;\n}\n\n.b {\n  color: #000;\n  margin: 10px;\n  top: 10px;\n  right: 5px;\n  bottom: 8px;\n  left: 90px;\n}";

    assert.equal(result, expect);
  });

});
<commit_msg>Testes OK<commit_after>const assert = require('assert');

// ---------------------------------
// render()
// ---------------------------------

describe('render()', () => {

  const config = {};
  config.bnnSize = require('../src/bnnSize.js'),
  config.bnnPosition = require('../src/bnnPosition.js'),
  config.bnnGradient = require('../src/bnnGradient.js'),
  config.bnnImport = require('../src/bnnImport.js'),
  config.bnnAlign = require('../src/bnnAlign.js');

  const banana = require('../src/banana.js')(config);
  // render() test 1
  it("should return the fully rendered css", () => {
    const stylesheet = ".a {color:#000;bnn-size: 50px 100px;}.b {color:#000;bnn-position: 10px 5px 8px 90px;margin: 10px;}";
    const result = banana.render("teste.bnn", stylesheet);
    const expect = ".a {\n  color: #000;\n  width: 50px;\n  height: 100px;\n}\n\n.b {\n  color: #000;\n  margin: 10px;\n  top: 10px;\n  right: 5px;\n  bottom: 8px;\n  left: 90px;\n}";

    assert.equal(result, expect);
  });

});
<|endoftext|>


<commit_before>/* eslint-env jest */
import { visit } from './testUtils'

describe('Letterhead page', () => {
  it('loads in /letterhead', async () => {
    const page = visit('/letterhead')
    await page.end()
  })
})
<commit_msg>Add more tests to the letterhead view<commit_after>/* eslint-env jest */
import { visit } from './testUtils'

describe('Letterhead page', () => {
  it('loads in /letterhead', async () => {
    const page = visit('/letterhead')
    await page.end()
  })

  it('has 4 letterheads', async () => {
    const page = visit('/letterhead')
    const letterheadCount = await page
      .evaluate(() => document.querySelectorAll('.letterhead-card').length)
      .end()
    expect(letterheadCount).toEqual(4)
  })

  it('has 4 images from placeimg.com', async () => {
    const page = visit('/letterhead')
    const selector = '.letterhead-card img[src*="placeimg.com"]'
    const letterheadCount = await page
      .evaluate(sel => document.querySelectorAll(sel).length, selector)
      .end()
    expect(letterheadCount).toEqual(4)
  })

  it('has at least one letterhead with a button', async () => {
    const page = visit('/letterhead')
    const buttonIsVisible = await page.visible('.letterhead-card button').end()
    expect(buttonIsVisible).toEqual(true)
  })

  it('has some text before the letterheads', async () => {
    const page = visit('/letterhead')
    const textIsVisible = await page
      .visible('.container > .row:first-child p')
      .end()
    expect(textIsVisible).toEqual(true)
  })
})
<|endoftext|>


<commit_before>/**
 * 网络方法处理
 * @type {Object}
 */
var http = require("http");
var querystring = require("querystring");
var url = require("url");
var cookie = require("cookie");

module.exports = Class(function(){
    return {
        req: null,
        res: null,
        http: null,
        init: function(req, res){
            this.req = req;
            this.res = res;
            this.http = {
                startTime: Date.now()
            };
        },
        run: function(callback){
            this._request();
            this._response();
            var method = this.req.method.toLowerCase();
            var methods = ["post", "put", "patch"];
            if (methods.indexOf(method) > -1) {
                this.getData(callback);
            }else{
                callback && callback(this.http);
            }
        },
        /**
         * 检测含有post数据
         * @return {Boolean} [description]
         */
        hasPostData: function(){
            var encoding = 'transfer-encoding' in this.req.headers;
            var length = ('content-length' in this.req.headers) && this.req.headers['content-length'] !== '0';
            return encoding || length;
        },
        /**
         * 获取POST过来的数据，包含上传的文件
         * 依赖multiparty库
         * @param  {Function} callback [description]
         * @return {[type]}            [description]
         */
        getData: function(callback){
            //没有post数据，直接回调
            if (!this.hasPostData()) {
                return callback && callback(this.http);
            };
            var self = this;
            var multiReg = /^multipart\/(form-data|related);\s*boundary=(?:"([^"]+)"|([^;]+))$/i;
            var contentType = this.req.headers["content-type"] || "";
            //表单数据提交
            if (multiReg.test(contentType)) {
                var multiparty = require("multiparty");
                var form = new multiparty.Form();
                form.on("file", function(name, value){
                    self.http.file[name] = value;
                });
                form.on("field", function(name, value){
                    self.http.post[name] = value;
                });
                form.on("close", function(){
                    callback && callback(self.http);
                });
                form.parse(this.req);
            }else{
                var buffer = "";
                this.req.setEncoding(C('encoding'));
                this.req.on("data", function(chunk){
                    buffer += chunk;
                })
                this.req.on("end", function(){
                    //json数据格式
                    var jsonConentType = C('post_json_content_type');
                    if (!is_array(jsonConentType)) {
                        jsonConentType = [jsonConentType];
                    };
                    //xml数据格式，框架暂无实现
                    //业务可以根据tag: parse_xml 来实现对应的行为
                    var xmlContentType = C('post_xml_content_type');
                    if (!is_array(xmlContentType)) {
                        xmlContentType = [xmlContentType];
                    };
                    if (jsonConentType.indexOf(contentType) > -1) {
                        self.http.post = JSON.parse(buffer) || {};
                    }else if (xmlContentType.indexOf(contentType) > -1) {
                        self.http.post = tag("parse_xml", self.http, buffer);
                    }else{
                        self.http.post = querystring.parse(buffer) || {};
                    }
                    callback && callback(self.http);
                })
            }
        },
        _request: function(){
            var self = this;
            var req = {
                version: this.req.httpVersion,
                method: this.req.method.toLowerCase(),
                headers: this.req.headers,
                getHeader: function(name){
                    if (name == 'referer') {
                        name = 'referrer';
                    };
                    return this.headers[name] || "";
                },
                post: {},
                file: {},
                ip: function(){
                    return this.headers["x-real-ip"]
                        || this.headers["x-forwarded-for"]
                        || this.req.connection.remoteAddress
                        || this.req.socket.remoteAddress
                        || this.req.connection.socket.remoteAddress
                        || "";
                },
                cookie: cookie.parse(this.req.headers.cookie || "")
            };
            extend(this.http, req);

            //解析url中的参数
            var urlInfo = url.parse("//" + req.headers.host + this.req.url, true, true);
            this.http.pathname = urlInfo.pathname;
            //query只记录?后面的参数
            this.http.query = urlInfo.query;
            //get包含路由解析追加的参数
            this.http.get = extend({}, urlInfo.query);
            //主机名，带端口
            this.http.host = urlInfo.host;
            //主机名，不带端口
            this.http.hostname = urlInfo.hostname;

            this.http.req = this.req;
        },
        _response: function(){
            var res = {
                /**
                 * 发送header
                 * @param {[type]} name  [description]
                 * @param {[type]} value [description]
                 */
                setHeader: function(name, value){
                    this.res.setHeader(name, value);
                },
                _cookie: {}, //需要发送的cookie
                /**
                 * 设置cookie
                 * @param {[type]} name    [description]
                 * @param {[type]} value   [description]
                 * @param {[type]} options [description]
                 */
                setCookie: function(name, value, options){
                    if (name === true) {
                        var cookies = Object.values(this._cookie);
                        if (cookies.length) {
                            this.setHeader("Set-Cookie", cookies);
                            this._cookie = {};
                        };
                        return true;
                    };
                    options = options || {};
                    if (typeof options == 'number') {
                        options = {
                            expires: options
                        }
                    };
                    var expires = options.expires;
                    if (expires === undefined) {
                        expires = C('cookie_expires');
                    };
                    delete options.expires;
                    //if value is null, remove cookie
                    if (value === null) {
                        expires = -1000;
                    };
                    var defaultOptions = {
                        path: "/",
                        expires: new Date (Date.now() + expires)
                    };
                    if (expires === 0) {
                        delete defaultOptions.expires;
                    };
                    options = extend(defaultOptions, options || {});
                    value = cookie.serialize(name, value, options);
                    this._cookie[name] = value;
                },
                /**
                 * url跳转
                 * @param  {[type]} url  [description]
                 * @param  {[type]} code [description]
                 * @return {[type]}      [description]
                 */
                redirect: function(url, code){
                    this.res.statusCode = code || 302;
                    this.res.setHeader("Location", url);
                    this.end();
                },
                /**
                 * 发送执行时间
                 * @param  {[type]} name [description]
                 * @return {[type]}      [description]
                 */
                sendTime: function(name){
                    var time = Date.now() - this.startTime;
                    this.setHeader("X-" + name, time + "ms");
                },
                /**
                 * 输出内容
                 * @param  {[type]} obj      [description]
                 * @param  {[type]} encoding [description]
                 * @return {[type]}          [description]
                 */
                echo: function(obj, encoding){
                    this.setCookie(true);
                    if (is_array(obj) || is_object(obj)) {
                        obj = JSON.stringify(obj);
                    };
                    if (!is_string(obj) && !(obj instanceof Buffer)) {
                        obj += "";
                    };
                    this.res.write(obj, encoding || C('encoding'));
                },
                /**
                 * 结束URL
                 * @return {[type]} [description]
                 */
                end: function(){
                    this.setCookie(true);
                    this.res.end();
                }
            }
            extend(this.http, res);
            this.http.res = this.res;
        }
    }
});
/**
 * 命令行下的简易http对象
 * @param  {[type]} url [description]
 * @return {[type]}     [description]
 */
module.exports.cli = function(info){
    try{
        info = JSON.parse(info);
    }catch(e){
        info = {url: info};
    }
    if (info.url.indexOf("/") !== 0) {
        info.url = "/" + info.url;
    };
    //解析url中的参数
    var urlInfo = url.parse("//" + (info.host || "127.0.0.1") + info.url, true, true);
    var fn = function(){ return ""};
    return {
        method: info.method || "get",
        ip: function(){
            return info.ip || "127.0.0.1"
        },
        pathname: urlInfo.pathname,
        query: urlInfo.query,
        get: extend({}, urlInfo.query),
        host: urlInfo.host,
        hostname: urlInfo.hostname,
        getHeader: fn,
        setHeader: fn,
        post: {},
        file: {},
        cookie: {},
        setCookie: fn,
        echo: fn,
        end: fn,
        sendTime: fn,
        redirect: fn
    }
}<commit_msg>update<commit_after>/**
 * 网络方法处理
 * @type {Object}
 */
var http = require("http");
var querystring = require("querystring");
var url = require("url");
var cookie = require("cookie");

module.exports = Class(function(){
    return {
        req: null,
        res: null,
        http: null,
        init: function(req, res){
            this.req = req;
            this.res = res;
            this.http = {
                startTime: Date.now()
            };
        },
        run: function(callback){
            this._request();
            this._response();
            var method = this.req.method.toLowerCase();
            var methods = ["post", "put", "patch"];
            if (methods.indexOf(method) > -1) {
                this.getData(callback);
            }else{
                callback && callback(this.http);
            }
        },
        /**
         * 检测含有post数据
         * @return {Boolean} [description]
         */
        hasPostData: function(){
            var encoding = 'transfer-encoding' in this.req.headers;
            var length = ('content-length' in this.req.headers) && this.req.headers['content-length'] !== '0';
            return encoding || length;
        },
        /**
         * 获取POST过来的数据，包含上传的文件
         * 依赖multiparty库
         * @param  {Function} callback [description]
         * @return {[type]}            [description]
         */
        getData: function(callback){
            //没有post数据，直接回调
            if (!this.hasPostData()) {
                return callback && callback(this.http);
            };
            var self = this;
            var multiReg = /^multipart\/(form-data|related);\s*boundary=(?:"([^"]+)"|([^;]+))$/i;
            var contentType = this.req.headers["content-type"] || "";
            //表单数据提交
            if (multiReg.test(contentType)) {
                var multiparty = require("multiparty");
                var form = new multiparty.Form();
                form.on("file", function(name, value){
                    self.http.file[name] = value;
                });
                form.on("field", function(name, value){
                    self.http.post[name] = value;
                });
                form.on("close", function(){
                    callback && callback(self.http);
                });
                form.parse(this.req);
            }else{
                var buffer = "";
                this.req.setEncoding(C('encoding'));
                this.req.on("data", function(chunk){
                    buffer += chunk;
                })
                this.req.on("end", function(){
                    //json数据格式
                    var jsonConentType = C('post_json_content_type');
                    if (!is_array(jsonConentType)) {
                        jsonConentType = [jsonConentType];
                    };
                    if (jsonConentType.indexOf(contentType) > -1) {
                        self.http.post = JSON.parse(buffer) || {};
                    }else{
                        self.http.post = querystring.parse(buffer) || {};
                    }
                    callback && callback(self.http);
                })
            }
        },
        _request: function(){
            var self = this;
            var req = {
                version: this.req.httpVersion,
                method: this.req.method.toLowerCase(),
                headers: this.req.headers,
                getHeader: function(name){
                    if (name == 'referer') {
                        name = 'referrer';
                    };
                    return this.headers[name] || "";
                },
                post: {},
                file: {},
                ip: function(){
                    return this.headers["x-real-ip"]
                        || this.headers["x-forwarded-for"]
                        || this.req.connection.remoteAddress
                        || this.req.socket.remoteAddress
                        || this.req.connection.socket.remoteAddress
                        || "";
                },
                cookie: cookie.parse(this.req.headers.cookie || "")
            };
            extend(this.http, req);

            //解析url中的参数
            var urlInfo = url.parse("//" + req.headers.host + this.req.url, true, true);
            this.http.pathname = urlInfo.pathname;
            //query只记录?后面的参数
            this.http.query = urlInfo.query;
            //get包含路由解析追加的参数
            this.http.get = extend({}, urlInfo.query);
            //主机名，带端口
            this.http.host = urlInfo.host;
            //主机名，不带端口
            this.http.hostname = urlInfo.hostname;

            this.http.req = this.req;
        },
        _response: function(){
            var res = {
                /**
                 * 发送header
                 * @param {[type]} name  [description]
                 * @param {[type]} value [description]
                 */
                setHeader: function(name, value){
                    this.res.setHeader(name, value);
                },
                _cookie: {}, //需要发送的cookie
                /**
                 * 设置cookie
                 * @param {[type]} name    [description]
                 * @param {[type]} value   [description]
                 * @param {[type]} options [description]
                 */
                setCookie: function(name, value, options){
                    if (name === true) {
                        var cookies = Object.values(this._cookie);
                        if (cookies.length) {
                            this.setHeader("Set-Cookie", cookies);
                            this._cookie = {};
                        };
                        return true;
                    };
                    options = options || {};
                    if (typeof options == 'number') {
                        options = {
                            expires: options
                        }
                    };
                    var expires = options.expires;
                    if (expires === undefined) {
                        expires = C('cookie_expires');
                    };
                    delete options.expires;
                    //if value is null, remove cookie
                    if (value === null) {
                        expires = -1000;
                    };
                    var defaultOptions = {
                        path: "/",
                        expires: new Date (Date.now() + expires)
                    };
                    if (expires === 0) {
                        delete defaultOptions.expires;
                    };
                    options = extend(defaultOptions, options || {});
                    value = cookie.serialize(name, value, options);
                    this._cookie[name] = value;
                },
                /**
                 * url跳转
                 * @param  {[type]} url  [description]
                 * @param  {[type]} code [description]
                 * @return {[type]}      [description]
                 */
                redirect: function(url, code){
                    this.res.statusCode = code || 302;
                    this.res.setHeader("Location", url);
                    this.end();
                },
                /**
                 * 发送执行时间
                 * @param  {[type]} name [description]
                 * @return {[type]}      [description]
                 */
                sendTime: function(name){
                    var time = Date.now() - this.startTime;
                    this.setHeader("X-" + name, time + "ms");
                },
                /**
                 * 输出内容
                 * @param  {[type]} obj      [description]
                 * @param  {[type]} encoding [description]
                 * @return {[type]}          [description]
                 */
                echo: function(obj, encoding){
                    this.setCookie(true);
                    if (is_array(obj) || is_object(obj)) {
                        obj = JSON.stringify(obj);
                    };
                    if (!is_string(obj) && !(obj instanceof Buffer)) {
                        obj += "";
                    };
                    this.res.write(obj, encoding || C('encoding'));
                },
                /**
                 * 结束URL
                 * @return {[type]} [description]
                 */
                end: function(){
                    this.setCookie(true);
                    this.res.end();
                }
            }
            extend(this.http, res);
            this.http.res = this.res;
        }
    }
});
/**
 * 命令行下的简易http对象
 * @param  {[type]} url [description]
 * @return {[type]}     [description]
 */
module.exports.cli = function(info){
    try{
        info = JSON.parse(info);
    }catch(e){
        info = {url: info};
    }
    if (info.url.indexOf("/") !== 0) {
        info.url = "/" + info.url;
    };
    //解析url中的参数
    var urlInfo = url.parse("//" + (info.host || "127.0.0.1") + info.url, true, true);
    var fn = function(){ return ""};
    return {
        method: info.method || "get",
        ip: function(){
            return info.ip || "127.0.0.1"
        },
        pathname: urlInfo.pathname,
        query: urlInfo.query,
        get: extend({}, urlInfo.query),
        host: urlInfo.host,
        hostname: urlInfo.hostname,
        getHeader: fn,
        setHeader: fn,
        post: {},
        file: {},
        cookie: {},
        setCookie: fn,
        echo: fn,
        end: fn,
        sendTime: fn,
        redirect: fn
    }
}<|endoftext|>