<commit_before>const Bot = require('./lib/Bot')
const SOFA = require('sofa-js')
const Fiat = require('./lib/Fiat')
const unit = require('./lib/unit')
const FigureSymbols = [`🍐`, `🍌`, `🍉`, `🔔`, `🍋`, `🍓`, `🏆`, `7⃣`, `🍒`, `🌞`]

let bot = new Bot()

// ROUTING

bot.onEvent = function(session, message) {
  switch (message.type) {
    case 'Init':
      welcome(session)
      break
    case 'Message':
      onMessage(session, message)
      break
    case 'Command':
      onCommand(session, message)
      break
    case 'Payment':
      onPayment(session, message)
      break
    case 'PaymentRequest':
      welcome(session)
      break
  }
}

function onMessage(session, message) {
  welcome(session)
}

function onCommand(session, command) {
  switch (command.content.value) {
    case 'play':
      play(session)
      break
    }
}

function onPayment(session, message) {
  if (message.fromAddress == session.config.paymentAddress) {
    // handle payments sent by the bot
    if (message.status == 'confirmed') {
      // perform special action once the payment has been confirmed
      // on the network
    } else if (message.status == 'error') {
      // oops, something went wrong with a payment we tried to send!
    }
  } else {
    // handle payments sent to the bot
    if (message.status == 'unconfirmed') {
      // payment has been sent to the ethereum network, but is not yet confirmed
      sendMessage(session, `Let the games begin! 🎲`)
      sendMessage(session, `❔❔❔`)
    } else if (message.status == 'confirmed') {
      // handle when the payment is actually confirmed!
      var figures = [randomDigit(), randomDigit(), randomDigit()]
      sendMessage(session, FigureSymbols[figures[0]] + `❔❔`)
      sendMessage(session, FigureSymbols[figures[0]] + FigureSymbols[figures[1]] + `❔`)
      sendMessage(session, FigureSymbols[figures[0]] + FigureSymbols[figures[1]] + FigureSymbols[figures[2]])
      generateResults(session, message, figures)
    } else if (message.status == 'error') {
      sendMessage(session, `There was an error with your payment! 🚫`)
    }
  }
}

// STATES

function welcome(session) {
  sendMessage(session, `Welcome to the Toshi Casino. With a little luck, you can turn the ETH you send to me into a fortune. Let me know when you are ready to play.`)
}

function play(session) {
  sendMessage(session, `Get ready. The money you send to me will be your stake. For a different amount, just use the 'Pay' feature in the top right.`)
  Fiat.fetch().then((toEth) => {
    session.requestEth(toEth.USD(1))
  });
}

// BUSINESS LOGIC

function twoMatches(session, message, figure) {
  sendMessage(session, `Oh wow, you got 2 ` + FigureSymbols[figure] + `s. Payday! 💸`)
  session.sendEth(unit.fromWei(message.value, 'ether') * (2 + (figure/10)))
}

function threeMatches(session, message, figure) {
  sendMessage(session, `Amazing, you got 3 ` + FigureSymbols[figure] + `s. Jackpot! 💰💰💰`)
  session.sendEth(unit.fromWei(message.value, 'ether') * (50 + figure))
}

function generateResults(session, message, figures) {
  if (figures[0] == figures[1] && figures[1] == figures[2]) {
    threeMatches(session, message, figures[0])
  } else if (figures[0] == figures[1] || figures[0] == figures[2]) {
    twoMatches(session, message, figures[0])
  } else if (figures[1] == figures[2]) {
    twoMatches(session, message, figures[1])
  } else {
    sendMessage(session, `Hmm, unfortunately no match. Better luck next time! 🍀`)
  }
}

// HELPERS

function sendMessage(session, message) {
  let controls = [
    {type: 'button', label: 'Play', value: 'play'}
  ]
  session.reply(SOFA.Message({
    body: message,
    controls: controls,
    showKeyboard: false,
  }))
}

function randomDigit() {
  return Math.floor(Math.random() * 10)
}
<commit_msg>Add apostrohpes<commit_after>const Bot = require('./lib/Bot');
const SOFA = require('sofa-js');
const Fiat = require('./lib/Fiat')
const unit = require('./lib/unit')
const FigureSymbols = [`🍐`, `🍌`, `🍉`, `🔔`, `🍋`, `🍓`, `🏆`, `7⃣`, `🍒`, `🌞`]

let bot = new Bot()

// ROUTING

bot.onEvent = function(session, message) {
  switch (message.type) {
    case 'Init':
      welcome(session)
      break
    case 'Message':
      onMessage(session, message)
      break
    case 'Command':
      onCommand(session, message)
      break
    case 'Payment':
      onPayment(session, message)
      break
    case 'PaymentRequest':
      welcome(session)
      break
  }
}

function onMessage(session, message) {
  welcome(session)
}

function onCommand(session, command) {
  switch (command.content.value) {
    case 'play':
      play(session)
      break
    }
}

function onPayment(session, message) {
  if (message.fromAddress == session.config.paymentAddress) {
    // handle payments sent by the bot
    if (message.status == 'confirmed') {
      // perform special action once the payment has been confirmed
      // on the network
    } else if (message.status == 'error') {
      // oops, something went wrong with a payment we tried to send!
    }
  } else {
    // handle payments sent to the bot
    if (message.status == 'unconfirmed') {
      // payment has been sent to the ethereum network, but is not yet confirmed
      sendMessage(session, `Let the games begin! 🎲`)
      sendMessage(session, `❔❔❔`)
    } else if (message.status == 'confirmed') {
      // handle when the payment is actually confirmed!
      var figures = [randomDigit(), randomDigit(), randomDigit()]
      sendMessage(session, FigureSymbols[figures[0]] + `❔❔`)
      sendMessage(session, FigureSymbols[figures[0]] + FigureSymbols[figures[1]] + `❔`)
      sendMessage(session, FigureSymbols[figures[0]] + FigureSymbols[figures[1]] + FigureSymbols[figures[2]])
      generateResults(session, message, figures)
    } else if (message.status == 'error') {
      sendMessage(session, `There was an error with your payment! 🚫`)
    }
  }
}

// STATES

function welcome(session) {
  sendMessage(session, `Welcome to the Toshi Casino. With a little luck, you can turn the ETH you send to me into a fortune. Let me know when you are ready to play.`)
}

function play(session) {
  sendMessage(session, `Get ready. The money you send to me will be your stake. For a different amount, just use the 'Pay' feature in the top right.`)
  Fiat.fetch().then((toEth) => {
    session.requestEth(toEth.USD(1))
  });
}

// BUSINESS LOGIC

function twoMatches(session, message, figure) {
  sendMessage(session, `Oh wow, you got 2 ` + FigureSymbols[figure] + `'s. Payday! 💸`)
  session.sendEth(unit.fromWei(message.value, 'ether') * (2 + (figure/10)))
}

function threeMatches(session, message, figure) {
  sendMessage(session, `Amazing, you got 3 ` + FigureSymbols[figure] + `'s. Jackpot! 💰💰💰`)
  session.sendEth(unit.fromWei(message.value, 'ether') * (50 + figure))
}

function generateResults(session, message, figures) {
  if (figures[0] == figures[1] && figures[1] == figures[2]) {
    threeMatches(session, message, figures[0])
  } else if (figures[0] == figures[1] || figures[0] == figures[2]) {
    twoMatches(session, message, figures[0])
  } else if (figures[1] == figures[2]) {
    twoMatches(session, message, figures[1])
  } else {
    sendMessage(session, `Hmm, unfortunately no match. Better luck next time! 🍀`)
  }
}

// HELPERS

function sendMessage(session, message) {
  let controls = [
    {type: 'button', label: 'Play', value: 'play'}
  ]
  session.reply(SOFA.Message({
    body: message,
    controls: controls,
    showKeyboard: false,
  }))
}

function randomDigit() {
  return Math.floor(Math.random() * 10)
}
<|endoftext|>


<commit_before>function generateHumerusPuns() {
  var lols = ["Q: What do you call a skeleton detective?\n\n A: Sherlock Bones",
              "(We're trying so hard tibia punny)",
              "Q: What instrument does a skeleton play? \n\nA: A trombone!",
              "Q: What do skeletons say before they eat? \n\nA: Bone Appetit!",
              "Q: Why did the skeleton run into the forest? \n\nA: He was bone to be wild",
              "Q: What do skeletons order in restaurants? \n\nA: Spare Ribs!",
              "Q: How do skeletons call their friends? \n\nA: On the telebone!",
              "Q: What do you call a stupid skeleton? \n\nA: A bone head!",
              "Q: How did skeletons send their letters in the old days? \n\nA: By bone-y express!",
              "Q: What happened to the skeleton who stayed by the fire too long ? \n\nA: He became bone dry!",
              ];
  var random = Math.floor(Math.random() * lols.length)
  return lols[random].replace(/\n/g, '
');
}
<commit_msg>finished whooo<commit_after>function generateHumerusPuns() {
  var lols = ["Q: What do you call a skeleton detective?\n\n A: Sherlock Bones!",
              "(We're trying so hard tibia punny.)",
              "Q: What instrument does a skeleton play? \n\nA: A trombone!",
              "Q: What do skeletons say before they eat? \n\nA: Bone Appetit!",
              "Q: Why did the skeleton run into the forest? \n\nA: He was bone to be wild!",
              "Q: What do skeletons order in restaurants? \n\nA: Spare Ribs!",
              "Q: How do skeletons call their friends? \n\nA: On the telebone!",
              "Q: What do you call a stupid skeleton? \n\nA: A bone head!",
              "Q: How did skeletons send their letters in the old days? \n\nA: By bone-y express!",
              "Q: What happened to the skeleton who stayed by the fire too long ? \n\nA: He became bone dry!",
              ];
  var random = Math.floor(Math.random() * lols.length)
  return lols[random].replace(/\n/g, '
');
}
<|endoftext|>


<commit_before>import request from 'request'
import helpers from '../../../lib/test_helpers.js'
import assert from 'assert'
import moment from 'moment'

const transactionTypes = ['buy', 'sell']

describe('stats', function () {
  this.timeout(20000)
  const statsFieldsType = {
    ask: Number,
    bid: Number,
    daily_change: Number,
    daily_change_percent: Number,
    global_units: Number,
    global_volume: Number,
    last_price: Number,
    last_transaction_type: String,
    market_cap: Number,
    max: Number,
    min: Number,
    open: Number,
    volume_1h: Number,
    volume_1h_buy: Number,
    volume_1h_sell: Number,
    volume_24h: Number,
    volume_24h_buy: Number,
    volume_24h_sell: Number,
    timestampApis: Date,
  }
  const statsFields = Object.keys(statsFieldsType)
  const timestampFormat = 'YYYY-MM-DDTHH:mm:ss'
  it('should return object containing specific fields with correct types', (done) => {
    const params = helpers.testRequestParams('/aur')
    request.get(params, (err, res, body) => {
      if (err) throw err
      let json
      try {
        json = JSON.parse(body)
      } catch (e) {
        throw e
      }
      helpers.assertPresenceOfFields(statsFields, [json])
      helpers.assertTypesOfFields(statsFieldsType, [json])
      assert(
        transactionTypes.includes(json.last_transaction_type),
        `Unexpected transaction type '${json.last_transaction_type}'`
      )
      assert(
        moment(json.timestampApis, timestampFormat, true).isValid(),
        `Unexpected timestamp format, ${json.timestampApis}' does not match ${timestampFormat}`
      )
      done()
    })
  })
})

describe('history', function () {
  this.timeout(20000)
  const historyFieldsType = {
    date: Date,
    rate: Number,
  }
  const historyFields = Object.keys(historyFieldsType)
  const timestampFormat = 'YYYY-MM-DDTHH:mm:ss'
  const dateFormat = 'YYYY-MM-DD'
  it('should return results array of objects containing correct fields', (done) => {
    const params = helpers.testRequestParams('/aur/history')
    request.get(params, (err, res, body) => {
      if (err) throw err
      let json
      try {
        json = JSON.parse(body)
      } catch (e) {
        throw e
      }
      assert(json.results, 'Does not contain a \'results\' field')
      assert(json.currency, 'Does not contain a \'currency\' field')
      assert(json.market, 'Does not contain a \'market\' field')
      helpers.assertPresenceOfFields(historyFields, json.results)
      helpers.assertTypesOfFields(historyFieldsType, json.results)
      assert(
        json.currency.constructor === String,
        'Unexpected currency type, should be String'
      )
      assert(
        json.market.constructor === String,
        'Unexpected market type, should be String'
      )
      assert(
        moment(json.timestampApis, timestampFormat, true).isValid(),
        `Unexpected timestamp format, '${json.timestampApis}' does not match ${timestampFormat}`
      )
      json.results.forEach((result, i) => {
        assert(
          moment(result.date, dateFormat, true).isValid(),
          (`Unexpected date format in result #${i};` +
          ` '${result.date}' does not match ${dateFormat}`)
        )
      })
      done()
    })
  })
})

describe('transactions', function () {
  this.timeout(20000)
  const transactionsFieldsType = {
    id: Number,
    amount_isk: Number,
    amount_aur: Number,
    rate: Number,
    type: String,
    timestamp: Date,
  }
  const transactionsFields = Object.keys(transactionsFieldsType)
  const timestampFormat = 'YYYY-MM-DDTHH:mm:ss'
  it('should return results array of objects containing correct fields', (done) => {
    const params = helpers.testRequestParams('/aur/transactions')
    request.get(params, (err, res, body) => {
      if (err) throw err
      let json
      try {
        json = JSON.parse(body)
      } catch (e) {
        throw e
      }
      assert(json.results, 'Does not contain a \'results\' field')
      helpers.assertPresenceOfFields(transactionsFields, json.results)
      helpers.assertTypesOfFields(transactionsFieldsType, json.results)
      json.results.forEach((result, i) => {
        assert(
          transactionTypes.includes(result.type),
          `Unexpected transaction type '${result.type}' in result #${i}`
        )
        assert(
          moment(result.timestamp, timestampFormat, true).isValid(),
          (`Unexpected timestamp format in result #${i};` +
          ` '${result.timestamp}' does not match ${timestampFormat}`)
        )
      })
      done()
    })
  })
})

describe('order-book', function () {
  this.timeout(20000)
  const bidAskFieldsType = {
    rate: Number,
    order_amount_aur: Number,
    order_value_isk: Number,
    timestamp: Date,
  }
  const bidAskFields = Object.keys(bidAskFieldsType)
  const timestampFormat = 'YYYY-MM-DDTHH:mm'
  it('should return bid/ask arrays of objects containing correct fields', (done) => {
    const params = helpers.testRequestParams('/aur/order-book')
    request.get(params, (err, res, body) => {
      if (err) throw err
      let json
      try {
        json = JSON.parse(body)
      } catch (e) {
        throw e
      }
      assert(json.ask, 'Does not contain a \'ask\' field')
      helpers.assertPresenceOfFields(bidAskFields, json.ask)
      helpers.assertTypesOfFields(bidAskFieldsType, json.ask)
      json.ask.forEach((result, i) => {
        assert(
          moment(result.timestamp, timestampFormat, true).isValid(),
          (`Unexpected timestamp format in ask result #${i};` +
          ` '${result.timestamp}' does not match ${timestampFormat}`)
        )
      })
      assert(json.bid, 'Does not contain a \'bid\' field')
      helpers.assertPresenceOfFields(bidAskFields, json.bid)
      helpers.assertTypesOfFields(bidAskFieldsType, json.bid)
      json.bid.forEach((result, i) => {
        assert(
          moment(result.timestamp, timestampFormat, true).isValid(),
          (`Unexpected timestamp format in bid result #${i};` +
          ` "${result.timestamp}" does not match ${timestampFormat}`)
        )
      })
      done()
    })
  })
})
<commit_msg>test: Use indexOf instead of includes in aur test<commit_after>import request from 'request'
import helpers from '../../../lib/test_helpers.js'
import assert from 'assert'
import moment from 'moment'

const transactionTypes = ['buy', 'sell']

describe('stats', function () {
  this.timeout(20000)
  const statsFieldsType = {
    ask: Number,
    bid: Number,
    daily_change: Number,
    daily_change_percent: Number,
    global_units: Number,
    global_volume: Number,
    last_price: Number,
    last_transaction_type: String,
    market_cap: Number,
    max: Number,
    min: Number,
    open: Number,
    volume_1h: Number,
    volume_1h_buy: Number,
    volume_1h_sell: Number,
    volume_24h: Number,
    volume_24h_buy: Number,
    volume_24h_sell: Number,
    timestampApis: Date,
  }
  const statsFields = Object.keys(statsFieldsType)
  const timestampFormat = 'YYYY-MM-DDTHH:mm:ss'
  it('should return object containing specific fields with correct types', (done) => {
    const params = helpers.testRequestParams('/aur')
    request.get(params, (err, res, body) => {
      if (err) throw err
      let json
      try {
        json = JSON.parse(body)
      } catch (e) {
        throw e
      }
      helpers.assertPresenceOfFields(statsFields, [json])
      helpers.assertTypesOfFields(statsFieldsType, [json])
      assert(
        ~transactionTypes.indexOf(json.last_transaction_type),
        `Unexpected transaction type '${json.last_transaction_type}'`
      )
      assert(
        moment(json.timestampApis, timestampFormat, true).isValid(),
        `Unexpected timestamp format, ${json.timestampApis}' does not match ${timestampFormat}`
      )
      done()
    })
  })
})

describe('history', function () {
  this.timeout(20000)
  const historyFieldsType = {
    date: Date,
    rate: Number,
  }
  const historyFields = Object.keys(historyFieldsType)
  const timestampFormat = 'YYYY-MM-DDTHH:mm:ss'
  const dateFormat = 'YYYY-MM-DD'
  it('should return results array of objects containing correct fields', (done) => {
    const params = helpers.testRequestParams('/aur/history')
    request.get(params, (err, res, body) => {
      if (err) throw err
      let json
      try {
        json = JSON.parse(body)
      } catch (e) {
        throw e
      }
      assert(json.results, 'Does not contain a \'results\' field')
      assert(json.currency, 'Does not contain a \'currency\' field')
      assert(json.market, 'Does not contain a \'market\' field')
      helpers.assertPresenceOfFields(historyFields, json.results)
      helpers.assertTypesOfFields(historyFieldsType, json.results)
      assert(
        json.currency.constructor === String,
        'Unexpected currency type, should be String'
      )
      assert(
        json.market.constructor === String,
        'Unexpected market type, should be String'
      )
      assert(
        moment(json.timestampApis, timestampFormat, true).isValid(),
        `Unexpected timestamp format, '${json.timestampApis}' does not match ${timestampFormat}`
      )
      json.results.forEach((result, i) => {
        assert(
          moment(result.date, dateFormat, true).isValid(),
          (`Unexpected date format in result #${i};` +
          ` '${result.date}' does not match ${dateFormat}`)
        )
      })
      done()
    })
  })
})

describe('transactions', function () {
  this.timeout(20000)
  const transactionsFieldsType = {
    id: Number,
    amount_isk: Number,
    amount_aur: Number,
    rate: Number,
    type: String,
    timestamp: Date,
  }
  const transactionsFields = Object.keys(transactionsFieldsType)
  const timestampFormat = 'YYYY-MM-DDTHH:mm:ss'
  it('should return results array of objects containing correct fields', (done) => {
    const params = helpers.testRequestParams('/aur/transactions')
    request.get(params, (err, res, body) => {
      if (err) throw err
      let json
      try {
        json = JSON.parse(body)
      } catch (e) {
        throw e
      }
      assert(json.results, 'Does not contain a \'results\' field')
      helpers.assertPresenceOfFields(transactionsFields, json.results)
      helpers.assertTypesOfFields(transactionsFieldsType, json.results)
      json.results.forEach((result, i) => {
        assert(
          ~transactionTypes.indexOf(result.type),
          `Unexpected transaction type '${result.type}' in result #${i}`
        )
        assert(
          moment(result.timestamp, timestampFormat, true).isValid(),
          (`Unexpected timestamp format in result #${i};` +
          ` '${result.timestamp}' does not match ${timestampFormat}`)
        )
      })
      done()
    })
  })
})

describe('order-book', function () {
  this.timeout(20000)
  const bidAskFieldsType = {
    rate: Number,
    order_amount_aur: Number,
    order_value_isk: Number,
    timestamp: Date,
  }
  const bidAskFields = Object.keys(bidAskFieldsType)
  const timestampFormat = 'YYYY-MM-DDTHH:mm'
  it('should return bid/ask arrays of objects containing correct fields', (done) => {
    const params = helpers.testRequestParams('/aur/order-book')
    request.get(params, (err, res, body) => {
      if (err) throw err
      let json
      try {
        json = JSON.parse(body)
      } catch (e) {
        throw e
      }
      assert(json.ask, 'Does not contain a \'ask\' field')
      helpers.assertPresenceOfFields(bidAskFields, json.ask)
      helpers.assertTypesOfFields(bidAskFieldsType, json.ask)
      json.ask.forEach((result, i) => {
        assert(
          moment(result.timestamp, timestampFormat, true).isValid(),
          (`Unexpected timestamp format in ask result #${i};` +
          ` '${result.timestamp}' does not match ${timestampFormat}`)
        )
      })
      assert(json.bid, 'Does not contain a \'bid\' field')
      helpers.assertPresenceOfFields(bidAskFields, json.bid)
      helpers.assertTypesOfFields(bidAskFieldsType, json.bid)
      json.bid.forEach((result, i) => {
        assert(
          moment(result.timestamp, timestampFormat, true).isValid(),
          (`Unexpected timestamp format in bid result #${i};` +
          ` "${result.timestamp}" does not match ${timestampFormat}`)
        )
      })
      done()
    })
  })
})
<|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict';

// config.js: challenge #4

// Author: Carlan Calazans  (mailto:carlancalazans at gmail dot com)
// Copyright: Copyright (c) 2016
// License: MIT

export default class Config {

}<commit_msg>[easy] challenge #4<commit_after><|endoftext|>


<commit_before>/*! ============================================================
 * bootstrapSwitch v1.7 by Larentis Mattia @SpiritualGuru
 * http://www.larentis.eu/
 *
 * Enhanced for radiobuttons by Stein, Peter @BdMdesigN
 * http://www.bdmdesign.org/
 *
 * Project site:
 * http://www.larentis.eu/switch/
 * ============================================================
 * Licensed under the Apache License, Version 2.0
 * http://www.apache.org/licenses/LICENSE-2.0
 * ============================================================ */

!function ($) {
  "use strict";

  $.fn['bootstrapSwitch'] = function (method) {
    var inputSelector = 'input[type!="hidden"]';
    var methods = {
      init: function () {
        return this.each(function () {
            var $element = $(this)
              , $div
              , $switchLeft
              , $switchRight
              , $label
              , $form = $element.closest('form')
              , myClasses = ""
              , classes = $element.attr('class')
              , color
              , moving
              , onLabel = "ON"
              , offLabel = "OFF"
              , icon = false;

            $.each(['switch-mini', 'switch-small', 'switch-large'], function (i, el) {
              if (classes.indexOf(el) >= 0)
                myClasses = el;
            });

            $element.addClass('has-switch');

            if ($element.data('on') !== undefined)
              color = "switch-" + $element.data('on');

            if ($element.data('on-label') !== undefined)
              onLabel = $element.data('on-label');

            if ($element.data('off-label') !== undefined)
              offLabel = $element.data('off-label');

            if ($element.data('label-icon') !== undefined)
              icon = $element.data('label-icon');

            $switchLeft = $('')
              .addClass("switch-left")
              .addClass(myClasses)
              .addClass(color)
              .html(onLabel);

            color = '';
            if ($element.data('off') !== undefined)
              color = "switch-" + $element.data('off');

            $switchRight = $('')
              .addClass("switch-right")
              .addClass(myClasses)
              .addClass(color)
              .html(offLabel);

            $label = $('')
              .html(" ")
              .addClass(myClasses)
              .attr('for', $element.find(inputSelector).attr('id'));

            if (icon) {
              $label.html('');
            }

            $div = $element.find(inputSelector).wrap($('
')).parent().data('animated', false);

            if ($element.data('animated') !== false)
              $div.addClass('switch-animate').data('animated', true);

            $div
              .append($switchLeft)
              .append($label)
              .append($switchRight);

            $element.find('>div').addClass(
              $element.find(inputSelector).is(':checked') ? 'switch-on' : 'switch-off'
            );

            if ($element.find(inputSelector).is(':disabled'))
              $(this).addClass('deactivate');

            var changeStatus = function ($this) {
              $this.siblings('label').trigger('mousedown').trigger('mouseup').trigger('click');
            };

            $element.on('keydown', function (e) {
              if (e.keyCode === 32) {
                e.stopImmediatePropagation();
                e.preventDefault();
                changeStatus($(e.target).find('span:first'));
              }
            });

            $switchLeft.on('click', function (e) {
              changeStatus($(this));
            });

            $switchRight.on('click', function (e) {
              changeStatus($(this));
            });

            $element.find(inputSelector).on('change', function (e, skipOnChange) {
              var $this = $(this)
                , $element = $this.parent()
                , thisState = $this.is(':checked')
                , state = $element.is('.switch-off');

              e.preventDefault();

              $element.css('left', '');

              if (state === thisState) {

                if (thisState)
                  $element.removeClass('switch-off').addClass('switch-on');
                else $element.removeClass('switch-on').addClass('switch-off');

                if ($element.data('animated') !== false)
                  $element.addClass("switch-animate");

                if (typeof skipOnChange === 'boolean' && skipOnChange)
                  return;

                $element.parent().trigger('switch-change', {'el': $this, 'value': thisState})
              }
            });

            $element.find('label').on('mousedown touchstart', function (e) {
              var $this = $(this);
              moving = false;

              e.preventDefault();
              e.stopImmediatePropagation();

              $this.closest('div').removeClass('switch-animate');

              if ($this.closest('.has-switch').is('.deactivate')) {
                $this.unbind('click');
              } else if ( $this.closest('.switch-on').parent().is('.radio-no-uncheck') ) {
                $this.unbind('click');
              } else {
                $this.on('mousemove touchmove', function (e) {
                  var $element = $(this).closest('.make-switch')
                    , relativeX = (e.pageX || e.originalEvent.targetTouches[0].pageX) - $element.offset().left
                    , percent = (relativeX / $element.width()) * 100
                    , left = 25
                    , right = 75;

                  moving = true;

                  if (percent < left)
                    percent = left;
                  else if (percent > right)
                    percent = right;

                  $element.find('>div').css('left', (percent - right) + "%")
                });

                $this.on('click touchend', function (e) {
                  var $this = $(this)
                    , $target = $(e.target)
                    , $myRadioCheckBox = $target.siblings('input');

                  e.stopImmediatePropagation();
                  e.preventDefault();

                  $this.unbind('mouseleave');

                  if (moving)
                    $myRadioCheckBox.prop('checked', !(parseInt($this.parent().css('left')) < -25));
                  else
                    $myRadioCheckBox.prop("checked", !$myRadioCheckBox.is(":checked"));

                  moving = false;
                  $myRadioCheckBox.trigger('change');
                });

                $this.on('mouseleave', function (e) {
                  var $this = $(this)
                    , $myInputBox = $this.siblings('input');

                  e.preventDefault();
                  e.stopImmediatePropagation();

                  $this.unbind('mouseleave');
                  $this.trigger('mouseup');

                  $myInputBox.prop('checked', !(parseInt($this.parent().css('left')) < -25)).trigger('change');
                });

                $this.on('mouseup', function (e) {
                  e.stopImmediatePropagation();
                  e.preventDefault();

                  $(this).unbind('mousemove');
                });
              }
            });

            if ($form.data('bootstrapSwitch') !== 'injected') {
              $form.bind('reset', function () {
                setTimeout(function () {
                  $form.find('.make-switch').each(function () {
                    var $input = $(this).find(inputSelector);

                    $input.prop('checked', $input.is(':checked')).trigger('change');
                  });
                }, 1);
              });
              $form.data('bootstrapSwitch', 'injected');
            }
          }
        );
      },
      toggleActivation: function () {
        var $this = $(this);

        $this.toggleClass('deactivate');
        $this.find(inputSelector).prop('disabled', $this.is('.deactivate'));
      },
      isActive: function () {
        return !$(this).hasClass('deactivate');
      },
      setActive: function (active) {
        var $this = $(this);

        if (active) {
          $this.removeClass('deactivate');
          $this.find(inputSelector).removeAttr('disabled');
        }
        else {
          $this.addClass('deactivate');
          $this.find(inputSelector).attr('disabled', 'disabled');
        }
      },
      toggleState: function (skipOnChange) {
        var $input = $(this).find(':checkbox');
        $input.prop('checked', !$input.is(':checked')).trigger('change', skipOnChange);
      },
      toggleRadioState: function (skipOnChange) {
        var $radioinput = $(this).find(':radio');
          $radioinput.not(':checked').prop('checked', !$radioinput.is(':checked')).trigger('change', skipOnChange);
      },
      toggleRadioStateAllowUncheck: function (uncheck, skipOnChange) {
        var $radioinput = $(this).find(':radio');
        if (uncheck) {
          $radioinput.not(':checked').trigger('change', skipOnChange);
        }
        else {
          $radioinput.not(':checked').prop('checked', !$radioinput.is(':checked')).trigger('change', skipOnChange);
        }
      },
      setState: function (value, skipOnChange) {
        $(this).find(inputSelector).prop('checked', value).trigger('change', skipOnChange);
      },
      setOnLabel: function(value) {
        var $switchLeft = $(this).find(".switch-left");
        $switchLeft.html(value);
      },
      setOffLabel: function(value) {
        var $switchRight = $(this).find(".switch-right");
        $switchRight.html(value);
      },
      setOnClass: function(value) {
        var $switchLeft = $(this).find(".switch-left");
        var color = '';
        if (value !== undefined) {
          if ($(this).attr('data-on') !== undefined) {
            color = "switch-" + $(this).attr('data-on')
          }
          $switchLeft.removeClass(color);
          color = "switch-" + value;
          $switchLeft.addClass(color);
        }
      },
      setOffClass: function(value) {
        var $switchRight = $(this).find(".switch-right");
        var color = '';
        if (value !== undefined) {
          if ($(this).attr('data-off') !== undefined) {
            color = "switch-" + $(this).attr('data-off')
          }
          $switchRight.removeClass(color);
          color = "switch-" + value;
          $switchRight.addClass(color);
        }
      },
      setAnimated: function(value) {
        var $element = $(this).find(inputSelector).parent();
        if (value === undefined) value = false;
        $element.data('animated', value);
        $element.attr('data-animated', value);

        if ($element.data('animated') !== false) {
          $element.addClass("switch-animate");
        } else {
          $element.removeClass("switch-animate");
        }
      },
      setSizeClass: function(value) {
        var $element = $(this);
        var $switchLeft = $element.find(".switch-left");
        var $switchRight = $element.find(".switch-right");
        var $label = $element.find("label");
        $.each(['switch-mini', 'switch-small', 'switch-large'], function (i, el) {
          if (el !== value) {
            $switchLeft.removeClass(el);
            $switchRight.removeClass(el);
            $label.removeClass(el);
          } else {
            $switchLeft.addClass(el);
            $switchRight.addClass(el);
            $label.addClass(el);
          }
        });
      },
      status: function () {
        return $(this).find(inputSelector).is(':checked');
      },
      destroy: function () {
        var $element = $(this)
          , $div = $element.find('div')
          , $form = $element.closest('form')
          , $inputbox;

        $div.find(':not(input)').remove();

        $inputbox = $div.children();
        $inputbox.unwrap().unwrap();

        $inputbox.unbind('change');

        if ($form) {
          $form.unbind('reset');
          $form.removeData('bootstrapSwitch');
        }

        return $inputbox;
      }
    };

    if (methods[method])
      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
    else if (typeof method === 'object' || !method)
      return methods.init.apply(this, arguments);
    else
      $.error('Method ' + method + ' does not exist!');
  };
}(jQuery);

(function($) {  // creates scope for $ sign assigned to jQuery
    $(function () { // on dom ready
        $('.make-switch')['bootstrapSwitch'](); // attach bootstrapswitch
    });
})(jQuery);
<commit_msg>Update to v1.8 and add function for Text Label<commit_after>/*! ============================================================
 * bootstrapSwitch v1.8 by Larentis Mattia @SpiritualGuru
 * http://www.larentis.eu/
 *
 * Enhanced for radiobuttons by Stein, Peter @BdMdesigN
 * http://www.bdmdesign.org/
 *
 * Project site:
 * http://www.larentis.eu/switch/
 * ============================================================
 * Licensed under the Apache License, Version 2.0
 * http://www.apache.org/licenses/LICENSE-2.0
 * ============================================================ */

!function ($) {
  "use strict";

  $.fn['bootstrapSwitch'] = function (method) {
    var inputSelector = 'input[type!="hidden"]';
    var methods = {
      init: function () {
        return this.each(function () {
            var $element = $(this)
              , $div
              , $switchLeft
              , $switchRight
              , $label
              , $form = $element.closest('form')
              , myClasses = ""
              , classes = $element.attr('class')
              , color
              , moving
              , onLabel = "ON"
              , offLabel = "OFF"
              , icon = false
              , textLabel = false;

            $.each(['switch-mini', 'switch-small', 'switch-large'], function (i, el) {
              if (classes.indexOf(el) >= 0)
                myClasses = el;
            });

            $element.addClass('has-switch');

            if ($element.data('on') !== undefined)
              color = "switch-" + $element.data('on');

            if ($element.data('on-label') !== undefined)
              onLabel = $element.data('on-label');

            if ($element.data('off-label') !== undefined)
              offLabel = $element.data('off-label');

            if ($element.data('label-icon') !== undefined)
              icon = $element.data('label-icon');

            if ($element.data('text-label') !== undefined)
              textLabel = $element.data('text-label');

            $switchLeft = $('')
              .addClass("switch-left")
              .addClass(myClasses)
              .addClass(color)
              .html(onLabel);

            color = '';
            if ($element.data('off') !== undefined)
              color = "switch-" + $element.data('off');

            $switchRight = $('')
              .addClass("switch-right")
              .addClass(myClasses)
              .addClass(color)
              .html(offLabel);

            $label = $('')
              .html(" ")
              .addClass(myClasses)
              .attr('for', $element.find(inputSelector).attr('id'));

            if (icon) {
              $label.html('');
            }

            if (textLabel) {
              $label.html('
' + textLabel + '
');
            }

            $div = $element.find(inputSelector).wrap($('
')).parent().data('animated', false);

            if ($element.data('animated') !== false)
              $div.addClass('switch-animate').data('animated', true);

            $div
              .append($switchLeft)
              .append($label)
              .append($switchRight);

            $element.find('>div').addClass(
              $element.find(inputSelector).is(':checked') ? 'switch-on' : 'switch-off'
            );

            if ($element.find(inputSelector).is(':disabled'))
              $(this).addClass('deactivate');

            var changeStatus = function ($this) {
              $this.siblings('label').trigger('mousedown').trigger('mouseup').trigger('click');
            };

            $element.on('keydown', function (e) {
              if (e.keyCode === 32) {
                e.stopImmediatePropagation();
                e.preventDefault();
                changeStatus($(e.target).find('span:first'));
              }
            });

            $switchLeft.on('click', function (e) {
              changeStatus($(this));
            });

            $switchRight.on('click', function (e) {
              changeStatus($(this));
            });

            $element.find(inputSelector).on('change', function (e, skipOnChange) {
              var $this = $(this)
                , $element = $this.parent()
                , thisState = $this.is(':checked')
                , state = $element.is('.switch-off');

              e.preventDefault();

              $element.css('left', '');

              if (state === thisState) {

                if (thisState)
                  $element.removeClass('switch-off').addClass('switch-on');
                else $element.removeClass('switch-on').addClass('switch-off');

                if ($element.data('animated') !== false)
                  $element.addClass("switch-animate");

                if (typeof skipOnChange === 'boolean' && skipOnChange)
                  return;

                $element.parent().trigger('switch-change', {'el': $this, 'value': thisState})
              }
            });

            $element.find('label').on('mousedown touchstart', function (e) {
              var $this = $(this);
              moving = false;

              e.preventDefault();
              e.stopImmediatePropagation();

              $this.closest('div').removeClass('switch-animate');

              if ($this.closest('.has-switch').is('.deactivate')) {
                $this.unbind('click');
              } else if ( $this.closest('.switch-on').parent().is('.radio-no-uncheck') ) {
                $this.unbind('click');
              } else {
                $this.on('mousemove touchmove', function (e) {
                  var $element = $(this).closest('.make-switch')
                    , relativeX = (e.pageX || e.originalEvent.targetTouches[0].pageX) - $element.offset().left
                    , percent = (relativeX / $element.width()) * 100
                    , left = 25
                    , right = 75;

                  moving = true;

                  if (percent < left)
                    percent = left;
                  else if (percent > right)
                    percent = right;

                  $element.find('>div').css('left', (percent - right) + "%")
                });

                $this.on('click touchend', function (e) {
                  var $this = $(this)
                    , $target = $(e.target)
                    , $myRadioCheckBox = $target.siblings('input');

                  e.stopImmediatePropagation();
                  e.preventDefault();

                  $this.unbind('mouseleave');

                  if (moving)
                    $myRadioCheckBox.prop('checked', !(parseInt($this.parent().css('left')) < -25));
                  else
                    $myRadioCheckBox.prop("checked", !$myRadioCheckBox.is(":checked"));

                  moving = false;
                  $myRadioCheckBox.trigger('change');
                });

                $this.on('mouseleave', function (e) {
                  var $this = $(this)
                    , $myInputBox = $this.siblings('input');

                  e.preventDefault();
                  e.stopImmediatePropagation();

                  $this.unbind('mouseleave');
                  $this.trigger('mouseup');

                  $myInputBox.prop('checked', !(parseInt($this.parent().css('left')) < -25)).trigger('change');
                });

                $this.on('mouseup', function (e) {
                  e.stopImmediatePropagation();
                  e.preventDefault();

                  $(this).unbind('mousemove');
                });
              }
            });

            if ($form.data('bootstrapSwitch') !== 'injected') {
              $form.bind('reset', function () {
                setTimeout(function () {
                  $form.find('.make-switch').each(function () {
                    var $input = $(this).find(inputSelector);

                    $input.prop('checked', $input.is(':checked')).trigger('change');
                  });
                }, 1);
              });
              $form.data('bootstrapSwitch', 'injected');
            }
          }
        );
      },
      toggleActivation: function () {
        var $this = $(this);

        $this.toggleClass('deactivate');
        $this.find(inputSelector).prop('disabled', $this.is('.deactivate'));
      },
      isActive: function () {
        return !$(this).hasClass('deactivate');
      },
      setActive: function (active) {
        var $this = $(this);

        if (active) {
          $this.removeClass('deactivate');
          $this.find(inputSelector).removeAttr('disabled');
        }
        else {
          $this.addClass('deactivate');
          $this.find(inputSelector).attr('disabled', 'disabled');
        }
      },
      toggleState: function (skipOnChange) {
        var $input = $(this).find(':checkbox');
        $input.prop('checked', !$input.is(':checked')).trigger('change', skipOnChange);
      },
      toggleRadioState: function (skipOnChange) {
        var $radioinput = $(this).find(':radio');
          $radioinput.not(':checked').prop('checked', !$radioinput.is(':checked')).trigger('change', skipOnChange);
      },
      toggleRadioStateAllowUncheck: function (uncheck, skipOnChange) {
        var $radioinput = $(this).find(':radio');
        if (uncheck) {
          $radioinput.not(':checked').trigger('change', skipOnChange);
        }
        else {
          $radioinput.not(':checked').prop('checked', !$radioinput.is(':checked')).trigger('change', skipOnChange);
        }
      },
      setState: function (value, skipOnChange) {
        $(this).find(inputSelector).prop('checked', value).trigger('change', skipOnChange);
      },
      setOnLabel: function(value) {
        var $switchLeft = $(this).find(".switch-left");
        $switchLeft.html(value);
      },
      setOffLabel: function(value) {
        var $switchRight = $(this).find(".switch-right");
        $switchRight.html(value);
      },
      setOnClass: function(value) {
        var $switchLeft = $(this).find(".switch-left");
        var color = '';
        if (value !== undefined) {
          if ($(this).attr('data-on') !== undefined) {
            color = "switch-" + $(this).attr('data-on')
          }
          $switchLeft.removeClass(color);
          color = "switch-" + value;
          $switchLeft.addClass(color);
        }
      },
      setOffClass: function(value) {
        var $switchRight = $(this).find(".switch-right");
        var color = '';
        if (value !== undefined) {
          if ($(this).attr('data-off') !== undefined) {
            color = "switch-" + $(this).attr('data-off')
          }
          $switchRight.removeClass(color);
          color = "switch-" + value;
          $switchRight.addClass(color);
        }
      },
      setAnimated: function(value) {
        var $element = $(this).find(inputSelector).parent();
        if (value === undefined) value = false;
        $element.data('animated', value);
        $element.attr('data-animated', value);

        if ($element.data('animated') !== false) {
          $element.addClass("switch-animate");
        } else {
          $element.removeClass("switch-animate");
        }
      },
      setSizeClass: function(value) {
        var $element = $(this);
        var $switchLeft = $element.find(".switch-left");
        var $switchRight = $element.find(".switch-right");
        var $label = $element.find("label");
        $.each(['switch-mini', 'switch-small', 'switch-large'], function (i, el) {
          if (el !== value) {
            $switchLeft.removeClass(el);
            $switchRight.removeClass(el);
            $label.removeClass(el);
          } else {
            $switchLeft.addClass(el);
            $switchRight.addClass(el);
            $label.addClass(el);
          }
        });
      },
      status: function () {
        return $(this).find(inputSelector).is(':checked');
      },
      destroy: function () {
        var $element = $(this)
          , $div = $element.find('div')
          , $form = $element.closest('form')
          , $inputbox;

        $div.find(':not(input)').remove();

        $inputbox = $div.children();
        $inputbox.unwrap().unwrap();

        $inputbox.unbind('change');

        if ($form) {
          $form.unbind('reset');
          $form.removeData('bootstrapSwitch');
        }

        return $inputbox;
      }
    };

    if (methods[method])
      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
    else if (typeof method === 'object' || !method)
      return methods.init.apply(this, arguments);
    else
      $.error('Method ' + method + ' does not exist!');
  };
}(jQuery);

(function($) {  // creates scope for $ sign assigned to jQuery
    $(function () { // on dom ready
        $('.make-switch')['bootstrapSwitch'](); // attach bootstrapswitch
    });
})(jQuery);
<|endoftext|>


<commit_before>define('kademlia/bus', ['./message', 'peerjs', 'when', 'Bacon'], function(m, Peer, when, Bacon) {
    'use strict';

    function Bus(id, brokerInfo) {
        var peer = new Peer(id, brokerInfo)
          , connections  = {}
          , transactions = {}
        ;

        var messages     = new Bacon.Bus();
        var closeEvents  = new Bacon.Bus();

        peer.on('connection', function(conn) {
            // TODO: clean up previous connection?
            initConnection(conn);
        });
        // TODO: attempt to reconnect when connection has been lost
        // TODO: make errors loggable
        // TODO: API to shut down all connections

        /**
         * Send a message using an existing connection; or establish
         * a short-lived connection if necessary.
         *
         * TODO: limit to short-lived connection!
         */
        function query(peer, message) {
            var conn = connections[peer.id];
            if (!conn) {
                console.log('not connected yet; connecting now', peer.id);
                return connect(peer).then(function() {
                    return query(peer, message);
                });
            }

            return transaction(function(transId) {
                dispatch(conn, transId, message);
            });
        }

        function dispatch(conn, transId, message) {
            conn.send(m.build(message, transId));
        }

        /**
         * Establish a long-lived connection.
         */
        function connect(peer) {
            return withBroker(peer, function(broker) {
                return when.promise(function(resolve, reject) {
                    var conn = broker.connect(peer.id, {
                        reliable: false
                    });
                    initConnection(conn);
                    conn.on('open', function() {
                        resolve(conn);
                    });
                    conn.on('error', reject);
                });
            });
        }

        function disconnect(otherId) {
            getConnection(otherId).then(function(conn) {
                conn.close();
            });
        }

        function initConnection(conn) {
            var id = conn.peer;
            var stream = new Bacon.EventStream(function(subscriber) {
                conn
                .on('open', function() {
                    connections[id] = conn;
                })
                .on('data', function(data) {
                    var msg = m.decode(data);
                    if (!react(conn, msg)) {
                        // Emit events only for incoming queries
                        subscriber(new Bacon.Next([msg, function(resp) {
                            dispatch(conn, msg.t, resp);
                        }]));
                    }
                })
                .on('error', function(err) {
                    subscriber(new Bacon.Error(err));
                })
                .on('close', function() {
                    if (connections[id] === conn) {
                        delete connections[id];
                    }
                    closeEvents.push(id);
                    subscriber(new Bacon.End());
                });
                return function unsubscribe() {
                    conn.close();  // TODO: This triggers a 'close' event, right?
                };
            });
            messages.plug(stream);
        }

        function react(message) {
            var isResp   = message.y === 'r' && message.t;
            var deferred = isResp && transactions[message.t];
            if (deferred) {
                deferred.resolve(message);
                delete transactions[message.t];
            }
            return !!deferred;
        }

        function getConnection(id) {
            return when.resolve(connections[id]);
            // TODO: connect to peer if not already connected
            // TODO: this should go through routing table?
        }

        //// TODO: reuse broker connections where convenient
        //// TODO: create new module to manage broker pool
        //function withBroker(brokerInfo, fn) {
        //    return when.promise(function(resolve, reject, notify) {
        //        var peer = new Peer(id, brokerInfo);
        //        peer.on('error', reject);

        //        var promise = fn(peer);
        //        promise.then(resolve, reject, notify);
        //        promise.ensure(function() {
        //            peer.disconnect();
        //        });
        //    });
        //}

        // TODO: implement real broker functionality
        function withBroker(brokerInfo, fn) {
            return when.promise(function(resolve, reject, notify) {
                // use bus-wide peer reference
                peer.on('error', reject);
                var promise = fn(peer);
                promise.then(resolve, reject, notify);
            });
        }

        function transaction(fn) {
            var id = mkTransactionId()
              , deferred = when.defer();
            transactions[id] = deferred;
            fn(id);
            return deferred.promise;
        }

        function mkTransactionId() {
            var id = randChar() + randChar();
            if (transactions.hasOwnProperty(id)) {
                return mkTransactionId();
            }
            return id;
        }

        function randChar() {
            var x = Math.floor(Math.random() * 26);
            return String.fromCharCode(97 + x);
        }

        return {
            query:       query,
            connect:     connect,
            disconnect:  disconnect,
            messages:    messages,
            closeEvents: closeEvents
        };
    }

    return Bus;

    //function react(conn, msg) {
    //    if (msg.y === 'q' && msg.q === 'ping') {
    //        sendPong(conn, msg);
    //    }
    //};

    //function sendPong(conn, msg) {
    //    if (msg.a && msg.a.id && msg.t) {
    //        conn.send({
    //            t: msg.t,
    //            y: 'r',
    //            r: { id: selfId }
    //        });
    //    }
    //};

});
<commit_msg>ping is working<commit_after>define('kademlia/bus', ['./message', 'peerjs', 'when', 'Bacon'], function(m, Peer, when, Bacon) {
    'use strict';

    function Bus(id, brokerInfo) {
        var peer = new Peer(id, brokerInfo)
          , connections  = {}
          , transactions = {}
        ;

        var messages     = new Bacon.Bus();
        var closeEvents  = new Bacon.Bus();

        peer.on('connection', function(conn) {
            // TODO: clean up previous connection?
            initConnection(conn);
        });
        // TODO: attempt to reconnect when connection has been lost
        // TODO: make errors loggable
        // TODO: API to shut down all connections

        /**
         * Send a message using an existing connection; or establish
         * a short-lived connection if necessary.
         *
         * TODO: limit to short-lived connection!
         */
        function query(peer, message) {
            var conn = connections[peer.id];
            if (!conn) {
                console.log('not connected yet; connecting now', peer.id);
                return connect(peer).then(function() {
                    return query(peer, message);
                });
            }

            return transaction(function(transId) {
                dispatch(conn, transId, message);
            });
        }

        function dispatch(conn, transId, message) {
            conn.send(m.build(message, transId));
        }

        /**
         * Establish a long-lived connection.
         */
        function connect(peer) {
            return withBroker(peer, function(broker) {
                return when.promise(function(resolve, reject) {
                    var conn = broker.connect(peer.id, {
                        reliable: false
                    });
                    initConnection(conn);
                    conn.on('open', function() {
                        resolve(conn);
                    });
                    conn.on('error', reject);
                });
            });
        }

        function disconnect(otherId) {
            getConnection(otherId).then(function(conn) {
                conn.close();
            });
        }

        function initConnection(conn) {
            var id = conn.peer;
            var stream = new Bacon.EventStream(function(subscriber) {
                conn
                .on('open', function() {
                    connections[id] = conn;
                })
                .on('data', function(data) {
                    var msg = m.decode(data);
                    if (!react(msg)) {
                        // Emit events only for incoming queries
                        subscriber(new Bacon.Next([msg, function(resp) {
                            dispatch(conn, msg.t, resp);
                        }]));
                    }
                })
                .on('error', function(err) {
                    subscriber(new Bacon.Error(err));
                })
                .on('close', function() {
                    if (connections[id] === conn) {
                        delete connections[id];
                    }
                    closeEvents.push(id);
                    subscriber(new Bacon.End());
                });
                return function unsubscribe() {
                    conn.close();  // TODO: This triggers a 'close' event, right?
                };
            });
            messages.plug(stream);
        }

        function react(message) {
            var isResp   = message.y === 'r' && message.t;
            var deferred = isResp && transactions[message.t];
            if (deferred) {
                deferred.resolve(message);
                delete transactions[message.t];
            }
            return !!deferred;
        }

        function getConnection(id) {
            return when.resolve(connections[id]);
            // TODO: connect to peer if not already connected
            // TODO: this should go through routing table?
        }

        //// TODO: reuse broker connections where convenient
        //// TODO: create new module to manage broker pool
        //function withBroker(brokerInfo, fn) {
        //    return when.promise(function(resolve, reject, notify) {
        //        var peer = new Peer(id, brokerInfo);
        //        peer.on('error', reject);

        //        var promise = fn(peer);
        //        promise.then(resolve, reject, notify);
        //        promise.ensure(function() {
        //            peer.disconnect();
        //        });
        //    });
        //}

        // TODO: implement real broker functionality
        function withBroker(brokerInfo, fn) {
            return when.promise(function(resolve, reject, notify) {
                // use bus-wide peer reference
                peer.on('error', reject);
                var promise = fn(peer);
                promise.then(resolve, reject, notify);
            });
        }

        function transaction(fn) {
            var id = mkTransactionId()
              , deferred = when.defer();
            transactions[id] = deferred;
            fn(id);
            return deferred.promise;
        }

        function mkTransactionId() {
            var id = randChar() + randChar();
            if (transactions.hasOwnProperty(id)) {
                return mkTransactionId();
            }
            return id;
        }

        function randChar() {
            var x = Math.floor(Math.random() * 26);
            return String.fromCharCode(97 + x);
        }

        return {
            query:       query,
            connect:     connect,
            disconnect:  disconnect,
            messages:    messages,
            closeEvents: closeEvents
        };
    }

    return Bus;

    //function react(conn, msg) {
    //    if (msg.y === 'q' && msg.q === 'ping') {
    //        sendPong(conn, msg);
    //    }
    //};

    //function sendPong(conn, msg) {
    //    if (msg.a && msg.a.id && msg.t) {
    //        conn.send({
    //            t: msg.t,
    //            y: 'r',
    //            r: { id: selfId }
    //        });
    //    }
    //};

});
<|endoftext|>


<commit_before>if (! Symbol.asyncIterator) {
    Symbol.asyncIterator = Symbol('asyncIterator');
}

global.__jymfony = global.__jymfony || {};

const forAwait = (iterator, callback) => {
    if (isPromise(iterator)) {
        return iterator.then(resolved => forAwait(resolved, callback));
    }

    const originalIterator = iterator;
    if (isArray(iterator)) {
        iterator = iterator.values();
    }

    if (! iterator.next) {
        iterator = iterator[Symbol.asyncIterator] || iterator[Symbol.iterator];
    }

    if (! iterator) {
        throw new Error(Object.prototype.toString.call(originalIterator) + ' is not iterable');
    } else if (! isFunction(iterator.next) && isFunction(iterator)) {
        iterator = iterator();
    }

    return new Promise((resolve, reject) => {
        async function next() {
            try {
                const step = await iterator.next();
                if (! step.done) {
                    const retVal = await callback(await step.value);
                    if (undefined !== retVal) {
                        return resolve(retVal);
                    }

                    return next();
                }

                resolve(await step.value);
            } catch (e) {
                reject(e);
            }

            return null;
        }

        next();
    });
};

__jymfony.forAwait = forAwait;
<commit_msg>[util] correctly bind function to iterator on for await<commit_after>if (! Symbol.asyncIterator) {
    Symbol.asyncIterator = Symbol('asyncIterator');
}

global.__jymfony = global.__jymfony || {};

const forAwait = (iterator, callback) => {
    if (isPromise(iterator)) {
        return iterator.then(resolved => forAwait(resolved, callback));
    }

    const originalIterator = iterator;
    if (isArray(iterator)) {
        iterator = iterator.values();
    }

    if (! iterator.next) {
        iterator = iterator[Symbol.asyncIterator] || iterator[Symbol.iterator];
    }

    if (! iterator) {
        throw new Error(Object.prototype.toString.call(originalIterator) + ' is not iterable');
    } else if (! isFunction(iterator.next) && isFunction(iterator)) {
        iterator = iterator.call(originalIterator);
    }

    return new Promise((resolve, reject) => {
        async function next() {
            try {
                const step = await iterator.next();
                if (! step.done) {
                    const retVal = await callback(await step.value);
                    if (undefined !== retVal) {
                        return resolve(retVal);
                    }

                    return next();
                }

                resolve(await step.value);
            } catch (e) {
                reject(e);
            }

            return null;
        }

        next();
    });
};

__jymfony.forAwait = forAwait;
<|endoftext|>


<commit_before>/**
 * @author mrdoob / http://mrdoob.com/
 */

var OpenSimToolbar = function ( editor ) {

	var signals = editor.signals;

	var container = new UI.Panel();
	container.setPaddingTop('20px');
	container.setId( 'opensim_toolbar' );

	var buttons = new UI.Panel();
	container.add( buttons );

	var camera = editor.camera;
    // -X
	var viewminx = new UI.Button(false, 'icons/backView_axes.png').onClick(function () {
		viewfromMinusX();
	});
	buttons.add(viewminx);
	function viewfromMinusX() {
	    var bbox = computeModelBbox();
	    var center = new THREE.Vector3();
	    bbox.center(center);
	    var newpos = new THREE.Vector3().copy(center);
	    var fov = editor.camera.fov * (Math.PI / 180);
	    // Calculate the camera distance
	    var objectSize = Math.max(bbox.max.y - bbox.min.y, bbox.max.z - bbox.min.z) / 2;
	    var distance = Math.abs(objectSize / Math.sin(fov / 2));
	    newpos.x = bbox.min.x - distance;
	    editor.updateCamera(newpos, center);

    };
    // +X
	var viewx = new UI.Button(false, 'icons/frontView_axes.png').onClick(function () {

	    viewfromPlusX();

	});
	buttons.add(viewx);

	function viewfromPlusX() {
	    var bbox = computeModelBbox();
	    var center = new THREE.Vector3();
	    bbox.center(center);
	    //var helper = new THREE.BoundingBoxHelper(modelObject, 0xff0000);
	    //helper.update();
	    // If you want a visible bounding box
	    //editor.scene.add(helper);
	    // create a sphere at new CameraPos
	    var newpos = new THREE.Vector3().copy(center);
	    var fov = editor.camera.fov * (Math.PI / 180);
	    // Calculate the camera distance
	    var objectSize = Math.max(bbox.max.y - bbox.min.y, bbox.max.z - bbox.min.z) / 2;
	    var distance = Math.abs(objectSize / Math.sin(fov / 2));
	    newpos.x = bbox.max.x + distance;
	    editor.updateCamera(newpos, center);

    };
    // -Y
	var viewminy = new UI.Button(false, 'icons/bottomView_axes.png').onClick(function () {
	    viewfromMinusY();
	});
	buttons.add(viewminy);
	function viewfromMinusY() {
	    var bbox = computeModelBbox();
	    var center = new THREE.Vector3();
	    bbox.center(center);
	    var newpos = new THREE.Vector3().copy(center);
	    var fov = editor.camera.fov * (Math.PI / 180);
	    // Calculate the camera distance
	    var objectSize = Math.max(bbox.max.x - bbox.min.x, bbox.max.z - bbox.min.z) / 2;
	    var distance = Math.abs(objectSize / Math.sin(fov / 2));
	    newpos.y = bbox.min.y - distance;
	    editor.updateCamera(newpos, center);

    };
    // +Y
	var viewplusy = new UI.Button(false, 'icons/topView_axes.png').onClick(function () {
	    viewfromPlusY();
	});
	buttons.add(viewplusy);
	function viewfromPlusY() {
	    var bbox = computeModelBbox();
	    var center = new THREE.Vector3();
	    bbox.center(center);
	    var newpos = new THREE.Vector3().copy(center);
	    var fov = editor.camera.fov * (Math.PI / 180);
	    // Calculate the camera distance
	    var objectSize = Math.max(bbox.max.x - bbox.min.x, bbox.max.z - bbox.min.z) / 2;
	    var distance = Math.abs(objectSize / Math.sin(fov / 2));
	    newpos.y = bbox.max.y + distance;
	    editor.updateCamera(newpos, center);

    };
    // -Z
	var viewminz = new UI.Button(false, 'icons/leftView_axes.png').onClick(function () {
	    viewfromMinusZ();
	});
	buttons.add(viewminz);
	function viewfromMinusZ() {

	    var bbox = computeModelBbox();
	    var center = new THREE.Vector3();
	    bbox.center(center);
	    var newpos = new THREE.Vector3().copy(center);
	    var fov = editor.camera.fov * (Math.PI / 180);
	    // Calculate the camera distance
	    var objectSize = Math.max(bbox.max.x - bbox.min.x, bbox.max.y - bbox.min.y)/2;
	    var distance = Math.abs(objectSize / Math.sin(fov / 2));
	    newpos.z = bbox.min.z - distance;
	    editor.updateCamera(newpos, center);

	};
    // +Z
	var viewplusz = new UI.Button(false, 'icons/rightView_axes.png').onClick(function () {
	    viewfromPlusZ();
	});
	buttons.add(viewplusz);
	function viewfromPlusZ() {

	    var bbox = computeModelBbox();
	    var center = new THREE.Vector3();
	    bbox.center(center);
	    var newpos = new THREE.Vector3().copy(center);
	    var fov = editor.camera.fov * (Math.PI / 180);
	    // Calculate the camera distance
	    var objectSize = Math.max(bbox.max.x - bbox.min.x, bbox.max.y - bbox.min.y)/2;
	    var distance = Math.abs(objectSize / Math.sin(fov / 2));
	    newpos.z = bbox.max.z + distance;
	    editor.updateCamera(newpos, center);

    };

	var view_zoomin = new UI.Button(false, 'icons/zoom-in.png').onClick(function () {
	    editor.viewZoom(+100);
	});
	buttons.add(view_zoomin);
	var view_zoomout = new UI.Button(false, 'icons/zoom-out.png').onClick(function () {
	    editor.viewZoom(-100);
	});
	buttons.add(view_zoomout);
	var view_refit = new UI.Button(false, 'icons/refit.png').onClick(function () {
	    //var modelObject = editor.scene.getObjectByName('OpenSimModel');
	    var bbox = computeModelBbox();
	    var center = new THREE.Vector3();
	    bbox.center(center);
	    //var newpos = new THREE.Vector3().copy(camera.location);
	    var fov = camera.fov * (Math.PI / 180);
	    var objectSize = Math.max(bbox.max.x - bbox.min.x, bbox.max.y - bbox.min.y, bbox.max.z - bbox.min.z);
	    var distance = Math.abs(objectSize / Math.sin(fov / 2));
	    //var helper = new THREE.BoundingBoxHelper(modelObject, 0xff0000);
	    //helper.update();
	    //editor.scene.add(helper);
	    // Zoom out only if model is outside view, also zoom in if too small
	    var curDistance = center.distanceTo(camera.position);
	    editor.viewZoom(curDistance - distance);

	});
	buttons.add(view_refit);

	var snapshot = new UI.Button(false, 'icons/camera.gif').onClick(function () {
            saveAsImage();
	});
	buttons.add(snapshot);

	function computeModelBbox() {
	    var modelObject = editor.scene.getObjectByName('OpenSimModel');
	    return (new THREE.Box3().setFromObject(modelObject));
	};
        function saveAsImage() {
            var canvas = document.getElementById("viewport");
            getImageData = true;
            //canvas.children[1].render();
	    var img    = canvas.children[1].toDataURL("image/jpeg");
	    saveFile(img, "opensim_snapshot.jpg");
	};
        // Support saving image to file
        var saveFile = function (strData, filename) {
            var link = document.createElement('a');
            if (typeof link.download === 'string') {
                document.body.appendChild(link); //Firefox requires the link to be in the body
                link.download = filename;
                link.href = strData;
                link.click();
                document.body.removeChild(link); //remove the link when done
            } else {
                location.replace(uri);
            }
        };

	return container;

}
<commit_msg>Tooltips for buttons<commit_after>/**
 * @author mrdoob / http://mrdoob.com/
 */

var OpenSimToolbar = function ( editor ) {

	var signals = editor.signals;

	var container = new UI.Panel();
	container.setPaddingTop('20px');
	container.setId( 'opensim_toolbar' );

	var buttons = new UI.Panel();
	container.add( buttons );

	var camera = editor.camera;
    // -X
	var viewminx = new UI.Button(false, 'icons/backView_axes.png').onClick(function () {
		viewfromMinusX();
	});
	viewminx.dom.title = 'Back';
	buttons.add(viewminx);
	function viewfromMinusX() {
	    var bbox = computeModelBbox();
	    var center = new THREE.Vector3();
	    bbox.center(center);
	    var newpos = new THREE.Vector3().copy(center);
	    var fov = editor.camera.fov * (Math.PI / 180);
	    // Calculate the camera distance
	    var objectSize = Math.max(bbox.max.y - bbox.min.y, bbox.max.z - bbox.min.z) / 2;
	    var distance = Math.abs(objectSize / Math.sin(fov / 2));
	    newpos.x = bbox.min.x - distance;
	    editor.updateCamera(newpos, center);

    };
    // +X
	var viewx = new UI.Button(false, 'icons/frontView_axes.png').onClick(function () {

	    viewfromPlusX();

	});
	viewx.dom.title = 'Front';
	buttons.add(viewx);

	function viewfromPlusX() {
	    var bbox = computeModelBbox();
	    var center = new THREE.Vector3();
	    bbox.center(center);
	    //var helper = new THREE.BoundingBoxHelper(modelObject, 0xff0000);
	    //helper.update();
	    // If you want a visible bounding box
	    //editor.scene.add(helper);
	    // create a sphere at new CameraPos
	    var newpos = new THREE.Vector3().copy(center);
	    var fov = editor.camera.fov * (Math.PI / 180);
	    // Calculate the camera distance
	    var objectSize = Math.max(bbox.max.y - bbox.min.y, bbox.max.z - bbox.min.z) / 2;
	    var distance = Math.abs(objectSize / Math.sin(fov / 2));
	    newpos.x = bbox.max.x + distance;
	    editor.updateCamera(newpos, center);

    };
    // -Y
	var viewminy = new UI.Button(false, 'icons/bottomView_axes.png').onClick(function () {
	    viewfromMinusY();
	});
	viewminy.dom.title = 'Bottom';
	buttons.add(viewminy);
	function viewfromMinusY() {
	    var bbox = computeModelBbox();
	    var center = new THREE.Vector3();
	    bbox.center(center);
	    var newpos = new THREE.Vector3().copy(center);
	    var fov = editor.camera.fov * (Math.PI / 180);
	    // Calculate the camera distance
	    var objectSize = Math.max(bbox.max.x - bbox.min.x, bbox.max.z - bbox.min.z) / 2;
	    var distance = Math.abs(objectSize / Math.sin(fov / 2));
	    newpos.y = bbox.min.y - distance;
	    editor.updateCamera(newpos, center);

    };
    // +Y
	var viewplusy = new UI.Button(false, 'icons/topView_axes.png').onClick(function () {
	    viewfromPlusY();
	});
	viewplusy.dom.title = 'Top';
	buttons.add(viewplusy);
	function viewfromPlusY() {
	    var bbox = computeModelBbox();
	    var center = new THREE.Vector3();
	    bbox.center(center);
	    var newpos = new THREE.Vector3().copy(center);
	    var fov = editor.camera.fov * (Math.PI / 180);
	    // Calculate the camera distance
	    var objectSize = Math.max(bbox.max.x - bbox.min.x, bbox.max.z - bbox.min.z) / 2;
	    var distance = Math.abs(objectSize / Math.sin(fov / 2));
	    newpos.y = bbox.max.y + distance;
	    editor.updateCamera(newpos, center);

    };
    // -Z
	var viewminz = new UI.Button(false, 'icons/leftView_axes.png').onClick(function () {
	    viewfromMinusZ();
	});
	viewminz.dom.title = 'Left';
	buttons.add(viewminz);
	function viewfromMinusZ() {

	    var bbox = computeModelBbox();
	    var center = new THREE.Vector3();
	    bbox.center(center);
	    var newpos = new THREE.Vector3().copy(center);
	    var fov = editor.camera.fov * (Math.PI / 180);
	    // Calculate the camera distance
	    var objectSize = Math.max(bbox.max.x - bbox.min.x, bbox.max.y - bbox.min.y)/2;
	    var distance = Math.abs(objectSize / Math.sin(fov / 2));
	    newpos.z = bbox.min.z - distance;
	    editor.updateCamera(newpos, center);

	};
    // +Z
	var viewplusz = new UI.Button(false, 'icons/rightView_axes.png').onClick(function () {
	    viewfromPlusZ();
	});
	viewplusz.dom.title = 'Right';
	buttons.add(viewplusz);
	function viewfromPlusZ() {

	    var bbox = computeModelBbox();
	    var center = new THREE.Vector3();
	    bbox.center(center);
	    var newpos = new THREE.Vector3().copy(center);
	    var fov = editor.camera.fov * (Math.PI / 180);
	    // Calculate the camera distance
	    var objectSize = Math.max(bbox.max.x - bbox.min.x, bbox.max.y - bbox.min.y)/2;
	    var distance = Math.abs(objectSize / Math.sin(fov / 2));
	    newpos.z = bbox.max.z + distance;
	    editor.updateCamera(newpos, center);

    };

	var view_zoomin = new UI.Button(false, 'icons/zoom-in.png').onClick(function () {
	    editor.viewZoom(+100);
	});
	view_zoomin.dom.title = 'Zoom-in';
	buttons.add(view_zoomin);
	var view_zoomout = new UI.Button(false, 'icons/zoom-out.png').onClick(function () {
	    editor.viewZoom(-100);
	});
	view_zoomout.dom.title = 'Zoom-out';
	buttons.add(view_zoomout);
	var view_refit = new UI.Button(false, 'icons/refit.png').onClick(function () {
	    //var modelObject = editor.scene.getObjectByName('OpenSimModel');
	    var bbox = computeModelBbox();
	    var center = new THREE.Vector3();
	    bbox.center(center);
	    //var newpos = new THREE.Vector3().copy(camera.location);
	    var fov = camera.fov * (Math.PI / 180);
	    var objectSize = Math.max(bbox.max.x - bbox.min.x, bbox.max.y - bbox.min.y, bbox.max.z - bbox.min.z);
	    var distance = Math.abs(objectSize / Math.sin(fov / 2));
	    //var helper = new THREE.BoundingBoxHelper(modelObject, 0xff0000);
	    //helper.update();
	    //editor.scene.add(helper);
	    // Zoom out only if model is outside view, also zoom in if too small
	    var curDistance = center.distanceTo(camera.position);
	    editor.viewZoom(curDistance - distance);

	});
	view_refit.dom.title = 'Fit';
	buttons.add(view_refit);

	var snapshot = new UI.Button(false, 'icons/camera.gif').onClick(function () {
            saveAsImage();
	});
	snapshot.dom.title = 'Snapshot';
	buttons.add(snapshot);

	function computeModelBbox() {
	    var modelObject = editor.scene.getObjectByName('OpenSimModel');
	    return (new THREE.Box3().setFromObject(modelObject));
	};
        function saveAsImage() {
            var canvas = document.getElementById("viewport");
            getImageData = true;
            //canvas.children[1].render();
	    var img    = canvas.children[1].toDataURL("image/jpeg");
	    saveFile(img, "opensim_snapshot.jpg");
	};
        // Support saving image to file
        var saveFile = function (strData, filename) {
            var link = document.createElement('a');
            if (typeof link.download === 'string') {
                document.body.appendChild(link); //Firefox requires the link to be in the body
                link.download = filename;
                link.href = strData;
                link.click();
                document.body.removeChild(link); //remove the link when done
            } else {
                location.replace(uri);
            }
        };

	return container;

}
<|endoftext|>


<commit_before>class SvgBarchartStrategy {
	constructor(data, config){
		this._loadConfigOnContext(config);
		//Create range function
		this.xAxisName = "x";
		this.yAxisName = "y";
		this.x = d3.scale.ordinal().rangeRoundBands([0, this.width], .1);
		this.y = d3.scale.linear().range([this.height, 0]);

	  var width = this.width - this.margin.left - this.margin.right;
	  var height = this.height - this.margin.top - this.margin.bottom;

		//Create scale
		this.xAxis = d3.svg.axis()
			.scale(this.x)
			.orient("bottom")
			.ticks(10);

		this.yAxis = d3.svg.axis()
			.scale(this.y)
			.orient("left")
			.innerTickSize(-width)
	    .outerTickSize(0)
	    .tickPadding(20)
	    .ticks(this.ticks, this.tickLabel);

		this.colors = d3.scale.category20();

		this.keyFunction = (d=>d.x);
	};

	/**
	 * Renders a barchart based on data object
	 * @param  {Object} data Data Object. Contains an array with x and y properties.
	 *
	 */
	draw(data){

		if(!this._initialized){
			this._initialize();
		}
		//Re-scale axis
	  this.x.domain(data.map(this.keyFunction));
	  this.y.domain([0, d3.max(data,d=>d[this.yAxisName])]);
	  //Create a transition effect for axis rescaling
	  this.svg.select('.x.axis').transition().duration(this.transitionDuration).call(this.xAxis);
	  this.svg.select('.y.axis').transition().duration(this.transitionDuration).call(this.yAxis);

	  //Bind data
		var bars = this.svg.selectAll(".bar").data(data, this.keyFunction);
		//For new data, add bars and events
		bars.enter()
			.append("rect")
	    .attr("class", "bar")
	    .attr("y", this.y(0))
	    .attr("height", this.height - this.y(0))
		  .attr("fill", (d,i) => this.colors(i))
		  //namespaces let us to provide more than one functon for the same event
		  .on('mousedown.user', this.events.down)
	    .on('mouseup.user', this.events.up)
	    .on('mouseleave.user', this.events.leave)
	    .on('mouseover.user', this.events.over)
	    .on('click.user', this.events.click);

		bars.exit()
	    .transition()
	    .duration(300)
	    .attr("y", this.y(0))
	    .attr("height", this.height - this.y(0))
	    .style('fill-opacity', 1e-6)
	    .style()
	    .remove();

		bars
	    .transition()
	    .duration(300)
	    .attr("x", d=> this.x(d[this.xAxisName]))
	    .attr("width", this.x.rangeBand())
	    .attr("y", d=> this.y(d[this.yAxisName]))
	    .attr("height", d => (this.height - this.y(d[this.yAxisName])));
	};

	_initialize(){
		var width = this.width + this.margin.left + this.margin.right;
		var height = this.height + this.margin.left + this.margin.right;
		//Create a global 'g' (group) element
		this.svg = d3
			.select(this.selector).append("svg")
			.attr({'width': width, 'height': height})
		  .append("g")
		  .attr("transform", "translate(" + this.margin.left + "," + this.margin.top + ")");

		//Append a new group with 'x' aXis

		this.svg.append("g")
			.attr("class", "x axis")
			.attr("transform", "translate(0," + this.height + ")")
			.call(this.xAxis);

		//Append a new group with 'y' aXis
		this.svg.append("g")
	      .attr("class", "y axis")
	      .attr("stroke-dasharray", "5, 5")
	      .call(this.yAxis)
	   	  .append("text");
		this._initialized = true;
	};

	/**
	 * This method adds config options to the chart context.
	 * @param  {Object} config Config object
	 */
	_loadConfigOnContext(config){
		config = config || {events:{}};
		this.margin = config.margin || _default.margin;
		this.width = config.width || _default.width;
		this.height = config.height || _default.height;
		this.ticks = config.ticks || _default.ticks;
		this.tickLabel = config.tickLabel || _default.tickLabel
		this.selector = config.selector || _default.selector;
		this.transitionDuration = config.transitionDuration || _default.transitionDuration;
		this.tooltip = config.tooltip || _default.tooltip;
		this.events = {};
		this.events.down = config.events.down || _default.events.down;
		this.events.up = config.events.up || _default.events.up;
		this.events.over = config.events.over || _default.events.over;
		this.events.click = config.events.click || _default.events.click;
		this.events.leave = config.events.leave || _default.events.leave;
	};
};<commit_msg>code format<commit_after>class SvgBarchartStrategy {
    constructor(data, config) {
        this._loadConfigOnContext(config);
        //Create range function
        this.xAxisName = "x";
        this.yAxisName = "y";
        this.x = d3.scale.ordinal().rangeRoundBands([0, this.width], .1);
        this.y = d3.scale.linear().range([this.height, 0]);

        var width = this.width - this.margin.left - this.margin.right;
        var height = this.height - this.margin.top - this.margin.bottom;

        //Create scale
        this.xAxis = d3.svg.axis()
            .scale(this.x)
            .orient("bottom")
            .ticks(10);

        this.yAxis = d3.svg.axis()
            .scale(this.y)
            .orient("left")
            .innerTickSize(-width)
            .outerTickSize(0)
            .tickPadding(20)
            .ticks(this.ticks, this.tickLabel);

        this.colors = d3.scale.category20();

        this.keyFunction = (d => d.x);
    };

	/**
	 * Renders a barchart based on data object
	 * @param  {Object} data Data Object. Contains an array with x and y properties.
	 *
	 */
    draw(data) {

        if (!this._initialized) {
            this._initialize();
        }
        //Re-scale axis
        this.x.domain(data.map(this.keyFunction));
        this.y.domain([0, d3.max(data, d => d[this.yAxisName])]);
        //Create a transition effect for axis rescaling
        this.svg.select('.x.axis').transition().duration(this.transitionDuration).call(this.xAxis);
        this.svg.select('.y.axis').transition().duration(this.transitionDuration).call(this.yAxis);

        //Bind data
        var bars = this.svg.selectAll(".bar").data(data, this.keyFunction);
        //For new data, add bars and events
        bars.enter()
            .append("rect")
            .attr("class", "bar")
            .attr("y", this.y(0))
            .attr("height", this.height - this.y(0))
            .attr("fill", (d, i) => this.colors(i))
            //namespaces let us to provide more than one functon for the same event
            .on('mousedown.user', this.events.down)
            .on('mouseup.user', this.events.up)
            .on('mouseleave.user', this.events.leave)
            .on('mouseover.user', this.events.over)
            .on('click.user', this.events.click);

        bars.exit()
            .transition()
            .duration(300)
            .attr("y", this.y(0))
            .attr("height", this.height - this.y(0))
            .style('fill-opacity', 1e-6)
            .style()
            .remove();

        bars
            .transition()
            .duration(300)
            .attr("x", d => this.x(d[this.xAxisName]))
            .attr("width", this.x.rangeBand())
            .attr("y", d => this.y(d[this.yAxisName]))
            .attr("height", d => (this.height - this.y(d[this.yAxisName])));
    };

    _initialize() {
        var width = this.width + this.margin.left + this.margin.right;
        var height = this.height + this.margin.left + this.margin.right;
        //Create a global 'g' (group) element
        this.svg = d3
            .select(this.selector).append("svg")
            .attr({ 'width': width, 'height': height })
            .append("g")
            .attr("transform", "translate(" + this.margin.left + "," + this.margin.top + ")");

        //Append a new group with 'x' aXis

        this.svg.append("g")
            .attr("class", "x axis")
            .attr("transform", "translate(0," + this.height + ")")
            .call(this.xAxis);

        //Append a new group with 'y' aXis
        this.svg.append("g")
            .attr("class", "y axis")
            .attr("stroke-dasharray", "5, 5")
            .call(this.yAxis)
            .append("text");
        this._initialized = true;
    };

	/**
	 * This method adds config options to the chart context.
	 * @param  {Object} config Config object
	 */
    _loadConfigOnContext(config) {
        config = config || { events: {} };
        this.margin = config.margin || _default.margin;
        this.width = config.width || _default.width;
        this.height = config.height || _default.height;
        this.ticks = config.ticks || _default.ticks;
        this.tickLabel = config.tickLabel || _default.tickLabel
        this.selector = config.selector || _default.selector;
        this.transitionDuration = config.transitionDuration || _default.transitionDuration;
        this.tooltip = config.tooltip || _default.tooltip;
        this.events = {};
        this.events.down = config.events.down || _default.events.down;
        this.events.up = config.events.up || _default.events.up;
        this.events.over = config.events.over || _default.events.over;
        this.events.click = config.events.click || _default.events.click;
        this.events.leave = config.events.leave || _default.events.leave;
    };
};<|endoftext|>