<commit_before>var createBus = require('./bus')
var assert = require('assert')
var chai = require('chai')
var expect = chai.expect
chai.should()

// TODO: Way too messy test suite, needs cleanup
//
// TODO: Go over couldDeliver tag, check if it's on
// received logs and if so remove them

// TODO: Wild / pure workers
// TODO: Disallow functions and regexp in as messages
// TODO: Disallow anything but string as addess

// TODO: Unhandled exceptions

// TODO: Circular references. See
// http://knockoutjs.com/documentation/computedObservables.html
//
// THOUGHT: Make log a bit less public, and encourage use of the
// helper functions

describe('BusThing', function() {
  var bus;
  beforeEach(function() {
    bus = createBus()
  })

  it('basic case', function(done) {
    bus.on('greeting').then(function(x) {
      assert(x, 'hello!')
      done()
    })
    bus.inject('greeting', 'hello!')
    bus.log.all()[0].should.deep.equal({
      worker: {
        name: 'injector'
      },
      deliveries: [
        {
          envelope: {
            address: 'greeting',
            message: 'hello!'
          },
          sent: true,
          couldDeliver: true
        }
      ]
    })
    bus.log.all()[1].should.deep.equal({
      deliveries: [{
        envelope: {
          address: 'greeting',
          message: 'hello!'
        },
        received: true,
        trigger: 'on'
      }],
      worker: {
        name: null
      }
    })
    bus.log.wasLogged('greeting','hello!').should.be.false
  })

  it('sends response', function() {
    bus.on('greeting').then(function(x) {
      this.send('render', x)
    })
    bus.inject('greeting', 'hai world')
    bus.log.all()[1].should.deep.equal({
      deliveries: [
        {
          received: true,
          trigger: 'on',
          envelope: {
            address: 'greeting',
            message: 'hai world'
          }
        },{
          sent: true,
          envelope: {
            address: 'render',
            message: 'hai world'
          },
          couldDeliver: false
        }
      ],
      worker: {
        name: null
      }
    })
    bus.log.all().length.should.equal(2)

  })

  it('dual messages', function() {
    var sent = []
    bus
      .on('addressA')
      .on('addressB')
      .then(function(a, b) {
        sent.push({ a: a, b: b })
      })
    bus.inject('addressA', 'messageA')
    bus.inject('addressB', 'messageB')
    sent[0].should.deep.equal({
      'a': 'messageA',
      'b': undefined
    })
    sent[1].should.deep.equal({
      'a': 'messageA',
      'b': 'messageB'
    })
  })

  it('dual messages should be logged on first entry', function() {
    bus
      .on('a').then(function() {
        this.send('b', true)
        this.send('c', true)
      })
      .on('b').then(function() {
        this.send('d')
      })
    bus.inject('a')
    bus.log.all()[1].deliveries.should.deep.equal([
      {
        received: true,
        trigger: 'on',
        envelope: {
          address: "a",
          message: true
        }
      },{
        sent: true,
        envelope: {
          address: 'b',
          message: true
        },
        couldDeliver: true
      },
      {
        sent: true,
        envelope: {
          address: 'c',
          message: true
        },
        couldDeliver: false
      },
    ])
  })

  it('change', function() {
    var sent = []
    bus
      .change('addressA')
      .on('addressB')
      .then(function(a, b) {
        sent.push({a:a,b:b})
      })

    bus.inject('addressA', 'messageA1')
    .inject('addressA', 'messageA1') // Same, should be ignored
    .inject('addressB', 'messageB1')
    .inject('addressB', 'messageB1')
    .inject('addressA', 'messageA2') // Is changed, should trigger

    sent[1].should.deep.equal({
      'a': 'messageA1',
      'b': 'messageB1'
    })
    sent[3].should.deep.equal({
      'a': 'messageA2',
      'b': 'messageB1'
    })
  })

  it('change (deep equals)', function() {
    var noDeliveries = 0
    bus
      .change('buy')
      .then(function() {
        noDeliveries++
      })

    bus.inject('buy', {
      orders: [
        { price: 123.2  },
        { price: 817.21 },
      ]
    })
    bus.inject('buy', {
      orders: [
        { price: 123.2  },
        { price: 817.21 },
      ]
    })

    noDeliveries.should.equal(1)
  })

  it('can also detect message in on', function() {
    bus.on('picky-handler', {
      arr: [
        { prop: 1 }
      ]
    }).then(function() {
      this.send('ok', true)
    })
    bus.inject('picky-handler', {
      arr: [
        { prop: 2 } // <- different
      ]
    })
    bus.log.all()[0].should.deep.equal({
      worker: {
        name: 'injector'
      },
      deliveries: [
        {
          sent: true,
          envelope: {
            address: 'picky-handler',
            message: {
              arr: [
                { prop: 2 } // <- different
              ]
            }
          },
          couldDeliver: false
        }
      ]
    })
    bus.inject('picky-handler', {
      arr: [
        { prop: 1 } // <- correct
      ]
    })
    bus.log.all()[2].deliveries[1].should.deep.equal({
      sent: true,
      envelope: {
        address: 'ok',
        message: true
      },
      couldDeliver: false
    })
  })

  it('next', function() {
    var greetings = []
    bus
      .next('greeting')
      .then(function(x) {greetings.push(x) })
    bus.inject('greeting', 'hello')
    bus.inject('greeting', 'hi') // <- should be ignored
    greetings.should.deep.equal([ 'hello' ])
  })

  it('when', function() {
    var sent = []
    bus
      .when('isReady')
      .then(function(ready) { sent.push(ready) })
    bus.inject('isReady', false)
    bus.inject('isReady', true)
    bus.inject('isReady', true)

    sent.should.deep.equal([true, true])
  })

  it('throws an error when accidentally using node callbacks', function() {
    (function() {
      bus.on('greeting', function(x) {
        // this would never have been executed
      })
    }).should.throw('Second argument to "on" was a function. Expected message matcher. You probably meant to use .then()')
  })

  it('errors when calling bus.inject from inside transform', function() {
    (function() {
      bus
        .on('greeting').then(function(x) {
          bus.inject('hej')
        })
        .inject('greeting')
    }).should.throw(
      'Illegal call to inject method from inside handler. ' +
      'Use this.send instead.')
  })

  it('should also watch change', function() {
    (function() {
      bus.change('greeting', function(x) {
        // this would never have been executed
      })
    }).should.throw('Second argument to "change" was a function. Expected message matcher.')
  })

  it('then accepts pure envelopes', function() {
    bus.on('cook').then('oven-on', true)
    bus.inject('cook')
    bus.log.all()[1].deliveries[1].should.deep.equal({
      sent: true,
      envelope: {
        address: 'oven-on',
        message: true
      },
      couldDeliver: false
    })
  })

  it('wasSent (true)', function() {
    bus.on('init').then(function() {
      this.send('greeting', { txt: ['hi!'] } )
    })
    bus.log.wasSent('greeting', { txt: ['hi!'] }).should.be.false
    bus.inject('init')
    bus.log.wasSent('greeting', { txt: ['hi!'] }).should.be.true
  })

  it('wasSent (false)', function() {
    bus.on('init').then(function() {
      this.send('greeting', { txt: ['hello!'] })
    })
    bus.inject('init')
    bus.log.wasSent('greeting', { txt: ['hi!'] }).should.be.false
  })

  it('wasSent (only address)', function() {
    bus.on('init').then(function() {
      this.send('greeting', 'irrelephant')
    })
    bus.log.wasSent('greeting').should.be.false
    bus.inject('init')
    bus.log.wasSent('greeting').should.be.true
  })

  it('undefined message should be implicit true (callback)', function(done) {
    bus.on('generic-message').then(function(msg) {
      msg.should.be.true
      done()
    })
    bus.inject('generic-message')
  })

  it('undefined message should be implicit true (log)', function(done) {
    bus.on('start').then(function(msg) {
      this.send('hai')
      done()
    })
    bus.inject('start')
    bus.log.all()[0].deliveries[0].should.deep.equal({
      sent: true,
      envelope: {
        address: 'start',
        message: true
      },
      couldDeliver: true
    })
    bus.log.all()[1].deliveries[1].should.deep.equal({
      sent: true,
      envelope: {
        address: 'hai',
        message: true
      },
      couldDeliver: false
    })

  })

  it('null should count as message payload', function(done) {
    bus.on('generic-message').then(function(msg) {
      expect(msg).to.be.null
      done()
    })
    bus.inject('generic-message', null)
  })

  it('null should count as message payload (log)', function(done) {
    bus.on('start').then(function(msg) {
      this.send('hai', null)
      done()
    })
    bus.inject('start', null)
    bus.log.all()[0].deliveries[0].should.deep.equal({
      sent: true,
      envelope: {
        address: 'start',
        message: null
      },
      couldDeliver: true
    })

    bus.log.all()[1].deliveries[1].should.deep.equal({
      sent: true,
      envelope: {
        address: 'hai',
        message: null
      },
      couldDeliver: false
    })

  })

  it('false should count as message payload ', function(done) {
    bus.on('generic-message').then(function(msg) {
      expect(msg).to.be.false
      done()
    })
    bus.inject('generic-message', false)
  })

  it('unhandled should show interpretation', function() {
    bus.on('a').then(function() { this.send('b') })
    bus.inject('a')
    bus.log.all()[1].deliveries[1].should.deep.equal({
      sent: true,
      couldDeliver: false,
      envelope: {
        address: 'b',
        message: true
      }
    })
  })

  it('logs function name as worker name', function() {
    bus.on('start').then(function startHandler() {
      this.send('bam!')
    })
    bus.inject('start')
    bus.log.all()[1].worker.name.should.equal('startHandler')

    // TODO: Piggybacking on this test, needs cleanup
    bus.log.worker('startHandler').didLog('bam!')
      .should.be.false
  })

  it('using logging does NOT trigger handlers', function(){
    var triggers = 0
    bus.on('a').then(function() {
      triggers++
      this.log('a')
    })
    bus.inject('a', true)

    triggers.should.equal(1)

    bus.log.all()[1].deliveries[1].should.deep.equal({
      sent: true,
      logOnly: true,
      envelope: {
        address: 'a',
        message: true
      },
      couldDeliver: false
    })
  })

  describe('when aaron sends property object to b on a', function() {
    beforeEach(function() {
      bus
        .on('a')
        .then(function aaron() {
          this.send('b', { myProp: 'myVal' })
        })
        .inject('a')
    })

    describe('log worker helper will say that', function() {

      it('it did', function() {
        bus.log
          .worker('aaron')
          .didSend('b')
          .should.be.true
      })

      it('it did send the message that it did', function() {
        bus.log
          .worker('aaron')
          .didSend('b', { myProp: 'myVal' })
          .should.be.true
      })

      it('it did NOT if one property differs', function() {
        bus.log
          .worker('aaron')
          .didSend('b', { myProp: 'otherVal' })
          .should.be.false
      })

      it('it did NOT send a completely different delivery', function() {
        bus.log
          .worker('aaron')
          .didSend('c')
          .should.be.false
      })

      it('another worker did NOT send that message', function() {
        bus.log
          .worker('wayne')
          .didSend({ myProp: 'otherVal' })
          .should.be.false
      })

      it('the injector did send its message', function() {
        bus.log
          .worker('injector')
          .didSend('a')
          .should.be.true
      })

    })
  })

  describe('if a worker only logs a delivery', function() {
    beforeEach(function() {
      bus
       .on('say')
       .then(function eavesDropper(x) {
         this.log('someone-said', x)
       })
       .inject('say','hello!!')
    })

    it('didLog was true', function() {
      bus.log
        .worker('eavesDropper')
        .didLog('someone-said', 'hello!!')

        .should.be.true
    })

    it('wasLogged is true', function() {
      bus.log
        .wasLogged('someone-said', 'hello!!')
        .should.be.true
    })

    it('wasSent is false', function() {
      bus.log
        .wasSent('someone-said', 'hello!!')
        .should.be.false
    })

  })

  describe('when we send twice to an address', function() {
    beforeEach(function() {
      bus.on('a').then(function() {
        this.send('b', 3)
        this.send('b', 4)
      }).inject('a')
    })

    it('lastSent should equal the second value', function() {
      bus.log.lastSent('b').should.equal(4)
    })

    it('lastSent should be null on other addresses', function() {
      expect(bus.log.lastSent('c')).to.be.null
    })
  })

})

function dbg(bus) {
  console.log('')
  console.log('--- DEBUG ---')
  console.log(JSON.stringify(bus.log.all(), null, 2))
}<commit_msg>Removed done todo<commit_after>var createBus = require('./bus')
var assert = require('assert')
var chai = require('chai')
var expect = chai.expect
chai.should()

// TODO: Way too messy test suite, needs cleanup

// TODO: Wild / pure workers
// TODO: Disallow functions and regexp in as messages
// TODO: Disallow anything but string as addess

// TODO: Unhandled exceptions

// TODO: Circular references. See
// http://knockoutjs.com/documentation/computedObservables.html
//
// THOUGHT: Make log a bit less public, and encourage use of the
// helper functions

describe('BusThing', function() {
  var bus;
  beforeEach(function() {
    bus = createBus()
  })

  it('basic case', function(done) {
    bus.on('greeting').then(function(x) {
      assert(x, 'hello!')
      done()
    })
    bus.inject('greeting', 'hello!')
    bus.log.all()[0].should.deep.equal({
      worker: {
        name: 'injector'
      },
      deliveries: [
        {
          envelope: {
            address: 'greeting',
            message: 'hello!'
          },
          sent: true,
          couldDeliver: true
        }
      ]
    })
    bus.log.all()[1].should.deep.equal({
      deliveries: [{
        envelope: {
          address: 'greeting',
          message: 'hello!'
        },
        received: true,
        trigger: 'on'
      }],
      worker: {
        name: null
      }
    })
    bus.log.wasLogged('greeting','hello!').should.be.false
  })

  it('sends response', function() {
    bus.on('greeting').then(function(x) {
      this.send('render', x)
    })
    bus.inject('greeting', 'hai world')
    bus.log.all()[1].should.deep.equal({
      deliveries: [
        {
          received: true,
          trigger: 'on',
          envelope: {
            address: 'greeting',
            message: 'hai world'
          }
        },{
          sent: true,
          envelope: {
            address: 'render',
            message: 'hai world'
          },
          couldDeliver: false
        }
      ],
      worker: {
        name: null
      }
    })
    bus.log.all().length.should.equal(2)

  })

  it('dual messages', function() {
    var sent = []
    bus
      .on('addressA')
      .on('addressB')
      .then(function(a, b) {
        sent.push({ a: a, b: b })
      })
    bus.inject('addressA', 'messageA')
    bus.inject('addressB', 'messageB')
    sent[0].should.deep.equal({
      'a': 'messageA',
      'b': undefined
    })
    sent[1].should.deep.equal({
      'a': 'messageA',
      'b': 'messageB'
    })
  })

  it('dual messages should be logged on first entry', function() {
    bus
      .on('a').then(function() {
        this.send('b', true)
        this.send('c', true)
      })
      .on('b').then(function() {
        this.send('d')
      })
    bus.inject('a')
    bus.log.all()[1].deliveries.should.deep.equal([
      {
        received: true,
        trigger: 'on',
        envelope: {
          address: "a",
          message: true
        }
      },{
        sent: true,
        envelope: {
          address: 'b',
          message: true
        },
        couldDeliver: true
      },
      {
        sent: true,
        envelope: {
          address: 'c',
          message: true
        },
        couldDeliver: false
      },
    ])
  })

  it('change', function() {
    var sent = []
    bus
      .change('addressA')
      .on('addressB')
      .then(function(a, b) {
        sent.push({a:a,b:b})
      })

    bus.inject('addressA', 'messageA1')
    .inject('addressA', 'messageA1') // Same, should be ignored
    .inject('addressB', 'messageB1')
    .inject('addressB', 'messageB1')
    .inject('addressA', 'messageA2') // Is changed, should trigger

    sent[1].should.deep.equal({
      'a': 'messageA1',
      'b': 'messageB1'
    })
    sent[3].should.deep.equal({
      'a': 'messageA2',
      'b': 'messageB1'
    })
  })

  it('change (deep equals)', function() {
    var noDeliveries = 0
    bus
      .change('buy')
      .then(function() {
        noDeliveries++
      })

    bus.inject('buy', {
      orders: [
        { price: 123.2  },
        { price: 817.21 },
      ]
    })
    bus.inject('buy', {
      orders: [
        { price: 123.2  },
        { price: 817.21 },
      ]
    })

    noDeliveries.should.equal(1)
  })

  it('can also detect message in on', function() {
    bus.on('picky-handler', {
      arr: [
        { prop: 1 }
      ]
    }).then(function() {
      this.send('ok', true)
    })
    bus.inject('picky-handler', {
      arr: [
        { prop: 2 } // <- different
      ]
    })
    bus.log.all()[0].should.deep.equal({
      worker: {
        name: 'injector'
      },
      deliveries: [
        {
          sent: true,
          envelope: {
            address: 'picky-handler',
            message: {
              arr: [
                { prop: 2 } // <- different
              ]
            }
          },
          couldDeliver: false
        }
      ]
    })
    bus.inject('picky-handler', {
      arr: [
        { prop: 1 } // <- correct
      ]
    })
    bus.log.all()[2].deliveries[1].should.deep.equal({
      sent: true,
      envelope: {
        address: 'ok',
        message: true
      },
      couldDeliver: false
    })
  })

  it('next', function() {
    var greetings = []
    bus
      .next('greeting')
      .then(function(x) {greetings.push(x) })
    bus.inject('greeting', 'hello')
    bus.inject('greeting', 'hi') // <- should be ignored
    greetings.should.deep.equal([ 'hello' ])
  })

  it('when', function() {
    var sent = []
    bus
      .when('isReady')
      .then(function(ready) { sent.push(ready) })
    bus.inject('isReady', false)
    bus.inject('isReady', true)
    bus.inject('isReady', true)

    sent.should.deep.equal([true, true])
  })

  it('throws an error when accidentally using node callbacks', function() {
    (function() {
      bus.on('greeting', function(x) {
        // this would never have been executed
      })
    }).should.throw('Second argument to "on" was a function. Expected message matcher. You probably meant to use .then()')
  })

  it('errors when calling bus.inject from inside transform', function() {
    (function() {
      bus
        .on('greeting').then(function(x) {
          bus.inject('hej')
        })
        .inject('greeting')
    }).should.throw(
      'Illegal call to inject method from inside handler. ' +
      'Use this.send instead.')
  })

  it('should also watch change', function() {
    (function() {
      bus.change('greeting', function(x) {
        // this would never have been executed
      })
    }).should.throw('Second argument to "change" was a function. Expected message matcher.')
  })

  it('then accepts pure envelopes', function() {
    bus.on('cook').then('oven-on', true)
    bus.inject('cook')
    bus.log.all()[1].deliveries[1].should.deep.equal({
      sent: true,
      envelope: {
        address: 'oven-on',
        message: true
      },
      couldDeliver: false
    })
  })

  it('wasSent (true)', function() {
    bus.on('init').then(function() {
      this.send('greeting', { txt: ['hi!'] } )
    })
    bus.log.wasSent('greeting', { txt: ['hi!'] }).should.be.false
    bus.inject('init')
    bus.log.wasSent('greeting', { txt: ['hi!'] }).should.be.true
  })

  it('wasSent (false)', function() {
    bus.on('init').then(function() {
      this.send('greeting', { txt: ['hello!'] })
    })
    bus.inject('init')
    bus.log.wasSent('greeting', { txt: ['hi!'] }).should.be.false
  })

  it('wasSent (only address)', function() {
    bus.on('init').then(function() {
      this.send('greeting', 'irrelephant')
    })
    bus.log.wasSent('greeting').should.be.false
    bus.inject('init')
    bus.log.wasSent('greeting').should.be.true
  })

  it('undefined message should be implicit true (callback)', function(done) {
    bus.on('generic-message').then(function(msg) {
      msg.should.be.true
      done()
    })
    bus.inject('generic-message')
  })

  it('undefined message should be implicit true (log)', function(done) {
    bus.on('start').then(function(msg) {
      this.send('hai')
      done()
    })
    bus.inject('start')
    bus.log.all()[0].deliveries[0].should.deep.equal({
      sent: true,
      envelope: {
        address: 'start',
        message: true
      },
      couldDeliver: true
    })
    bus.log.all()[1].deliveries[1].should.deep.equal({
      sent: true,
      envelope: {
        address: 'hai',
        message: true
      },
      couldDeliver: false
    })

  })

  it('null should count as message payload', function(done) {
    bus.on('generic-message').then(function(msg) {
      expect(msg).to.be.null
      done()
    })
    bus.inject('generic-message', null)
  })

  it('null should count as message payload (log)', function(done) {
    bus.on('start').then(function(msg) {
      this.send('hai', null)
      done()
    })
    bus.inject('start', null)
    bus.log.all()[0].deliveries[0].should.deep.equal({
      sent: true,
      envelope: {
        address: 'start',
        message: null
      },
      couldDeliver: true
    })

    bus.log.all()[1].deliveries[1].should.deep.equal({
      sent: true,
      envelope: {
        address: 'hai',
        message: null
      },
      couldDeliver: false
    })

  })

  it('false should count as message payload ', function(done) {
    bus.on('generic-message').then(function(msg) {
      expect(msg).to.be.false
      done()
    })
    bus.inject('generic-message', false)
  })

  it('unhandled should show interpretation', function() {
    bus.on('a').then(function() { this.send('b') })
    bus.inject('a')
    bus.log.all()[1].deliveries[1].should.deep.equal({
      sent: true,
      couldDeliver: false,
      envelope: {
        address: 'b',
        message: true
      }
    })
  })

  it('logs function name as worker name', function() {
    bus.on('start').then(function startHandler() {
      this.send('bam!')
    })
    bus.inject('start')
    bus.log.all()[1].worker.name.should.equal('startHandler')

    // TODO: Piggybacking on this test, needs cleanup
    bus.log.worker('startHandler').didLog('bam!')
      .should.be.false
  })

  it('using logging does NOT trigger handlers', function(){
    var triggers = 0
    bus.on('a').then(function() {
      triggers++
      this.log('a')
    })
    bus.inject('a', true)

    triggers.should.equal(1)

    bus.log.all()[1].deliveries[1].should.deep.equal({
      sent: true,
      logOnly: true,
      envelope: {
        address: 'a',
        message: true
      },
      couldDeliver: false
    })
  })

  describe('when aaron sends property object to b on a', function() {
    beforeEach(function() {
      bus
        .on('a')
        .then(function aaron() {
          this.send('b', { myProp: 'myVal' })
        })
        .inject('a')
    })

    describe('log worker helper will say that', function() {

      it('it did', function() {
        bus.log
          .worker('aaron')
          .didSend('b')
          .should.be.true
      })

      it('it did send the message that it did', function() {
        bus.log
          .worker('aaron')
          .didSend('b', { myProp: 'myVal' })
          .should.be.true
      })

      it('it did NOT if one property differs', function() {
        bus.log
          .worker('aaron')
          .didSend('b', { myProp: 'otherVal' })
          .should.be.false
      })

      it('it did NOT send a completely different delivery', function() {
        bus.log
          .worker('aaron')
          .didSend('c')
          .should.be.false
      })

      it('another worker did NOT send that message', function() {
        bus.log
          .worker('wayne')
          .didSend({ myProp: 'otherVal' })
          .should.be.false
      })

      it('the injector did send its message', function() {
        bus.log
          .worker('injector')
          .didSend('a')
          .should.be.true
      })

    })
  })

  describe('if a worker only logs a delivery', function() {
    beforeEach(function() {
      bus
       .on('say')
       .then(function eavesDropper(x) {
         this.log('someone-said', x)
       })
       .inject('say','hello!!')
    })

    it('didLog was true', function() {
      bus.log
        .worker('eavesDropper')
        .didLog('someone-said', 'hello!!')

        .should.be.true
    })

    it('wasLogged is true', function() {
      bus.log
        .wasLogged('someone-said', 'hello!!')
        .should.be.true
    })

    it('wasSent is false', function() {
      bus.log
        .wasSent('someone-said', 'hello!!')
        .should.be.false
    })

  })

  describe('when we send twice to an address', function() {
    beforeEach(function() {
      bus.on('a').then(function() {
        this.send('b', 3)
        this.send('b', 4)
      }).inject('a')
    })

    it('lastSent should equal the second value', function() {
      bus.log.lastSent('b').should.equal(4)
    })

    it('lastSent should be null on other addresses', function() {
      expect(bus.log.lastSent('c')).to.be.null
    })
  })

})

function dbg(bus) {
  console.log('')
  console.log('--- DEBUG ---')
  console.log(JSON.stringify(bus.log.all(), null, 2))
}<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp');
var mocha = require('gulp-mocha');
var istanbul = require('gulp-istanbul');
var eslint = require('gulp-eslint');

gulp.task('coverage', function() {
  return gulp.src(['index.js', 'utils.js'])
    .pipe(istanbul({includeUntested: true}))
    .pipe(istanbul.hookRequire());
});

gulp.task('mocha', ['coverage'], function() {
  return gulp.src('test.js')
    .pipe(mocha())
    .pipe(istanbul.writeReports({
      reporters: ['html', 'text', 'text-summary'],
      reportOpts: {dir: 'coverage', file: 'summary.txt'}
    }));
});

gulp.task('eslint', function() {
  return gulp.src('*.js')
    .pipe(eslint())
    .pipe(eslint.format());
});

gulp.task('default', ['mocha', 'eslint']);
<commit_msg>get gulpfile set up<commit_after>'use strict';

var gulp = require('gulp');
var mocha = require('gulp-mocha');
var istanbul = require('gulp-istanbul');
var eslint = require('gulp-eslint');

gulp.task('coverage', function() {
  return gulp.src(['index.js', 'lib/**/*.js'])
    .pipe(istanbul({includeUntested: true}))
    .pipe(istanbul.hookRequire());
});

gulp.task('mocha', ['coverage'], function() {
  return gulp.src('test/*.js')
    .pipe(mocha())
    .pipe(istanbul.writeReports({
      reporters: ['html', 'text', 'text-summary'],
      reportOpts: {dir: 'coverage', file: 'summary.txt'}
    }));
});

gulp.task('eslint', function() {
  return gulp.src(['*.js', 'test/*.js', 'lib/**/*.js'])
    .pipe(eslint())
    .pipe(eslint.format());
});

gulp.task('default', ['eslint', 'mocha']);
<|endoftext|>


<commit_before>/**
 *
 */
function dialogoElegirArmaTodas() {
    var catArmas = [];

    for (var i=0; i<armas_set.length;i++) {
        var arma = armas_set[i];
        var categoria = arma.getCategoria();

        if (categoria != CAT_ARMA_MUNICION) {
            catArmas.push(categoria);
        }
    }
    dialogoElegirArma(catArmas, {principal:aplicarArma, isDisabled: alwaysEnabled},{})
}

function dialogoElegirTipoArma(categoriasPermitidas, callback, parametros) {
    var i;
    var j;
    var arrayOpciones = [];

    categorias:
    for (i=0; i<categoriasPermitidas.length;i++) {
        var categoria = categoriasPermitidas[i];

        for (j=0; j < arrayOpciones.length; j++) {
            if (categoria == arrayOpciones[j].etiqueta) {
                continue categorias;
            }
        }

        arrayOpciones.push(new OpcionMostrable(_l(categoria),categoria,""));
    }

    parametros.elegir = true;

    muestraDialogoElegirOpciones(arrayOpciones, parametros, callback, true);
}

/**
 *
 * @param {string[]} categoriasPermitidas
 * @param callback
 * @param parametros
 */
function dialogoElegirArma(categoriasPermitidas, callback, parametros) {
    var arrayArmas = [];
    var categorias = [];
    var i;
    var j;
    var k;

    for (i=0; i<armas_set.length;i++) {
        var arma = armas_set[i];
        var categoria = arma.getCategoria();
        var categoriaLoc = arma.getCategoriaLoc();

        var permitida = false;
        for (k = 0; k < categoriasPermitidas.length; k++) {
            if (categoria == categoriasPermitidas[k]) {
                permitida = true;
                break;
            }
        }
        if (!permitida) {
            continue;
        }
        var categoriaLimpia = categoria.replace("/","");

        var yaListada = false;
        for (j=0; j < categorias.length; j++) {
            if (categorias[j].etiqueta == categoria) {
                yaListada = true;
                break;
            }
        }

        if (!yaListada) {
            categorias.push(new OpcionMostrable(categoriaLoc,categoriaLimpia+"ElegirArma",categoriaLimpia+"ElegirArma"));
        }

        arrayArmas.push(new OpcionMostrable(_l(arma.nombre),arma.nombre,categoriaLimpia+"ElegirArma"));

    }

    parametros.elegir = true;

    muestraDialogoElegirOpciones(arrayArmas, parametros, callback, true, categorias);
}

function muestraVentanaCompraEquipo() {
    var dialogo = getDiv();
    var zonaActual;
    var contenidoDialogo;

    var actualizarDialogoEquipo = function(activo) {
        dialogo.empty();
        contenidoDialogo = getDiv("");

        for (var j = 0; j < categorias_equipo.length; j++) {
            var categ = categorias_equipo[j];
            var divCateg = getDiv("contenedorBotonesVentajas");
            var gridCateg = $("

").addClass("three_up tiles").addClass(CSS_TEXTO_SMALL);

            contenidoDialogo.append("
"+_l(categ)+"
");

            for (var i =0; i < equipo_set[j].length; i++) {
                if (!equipo_set[j][i].isNoComprable()) {
                    var item = equipo_set[j][i];
                    var itemNormal = new EquipoComprado(item,0,"");
                    var itemBueno = new EquipoComprado(item,5,"");
                    var itemMalo = new EquipoComprado(item,-5,"");
                    var labelNormal = itemNormal.toString() + " [" + itemNormal.getCosteDinero().toString() + "]";
                    var labelBueno = itemBueno.toString() + " [" + itemBueno.getCosteDinero().toString() + "]";
                    var labelMalo = itemMalo.toString() + " [" + itemMalo.getCosteDinero().toString() + "]";
                    var botonItemNormal = boton("big pretty primary btn",labelNormal,!personaje_actual.puedeGastarse(itemNormal.getCosteDinero())).addClass("botonDialogoOpciones").css("width","100%");
                    var botonItemBueno = boton("big pretty primary btn",labelBueno,!personaje_actual.puedeGastarse(itemBueno.getCosteDinero())).addClass("botonDialogoOpciones").css("width","100%");
                    var botonItemMalo = boton("big pretty primary btn",labelMalo,!personaje_actual.puedeGastarse(itemMalo.getCosteDinero())).addClass("botonDialogoOpciones").css("width","100%");

                    gridCateg.append($("

").append(botonItemMalo));
                    gridCateg.append($("

").append(botonItemNormal));
                    gridCateg.append($("

").append(botonItemBueno));

                    botonItemMalo.on("click",{item: item}, function(event) {
                        var item = event.data.item;
                        personaje_actual.compra(item, false, -5);
                    });
                    botonItemBueno.on("click",{item: item}, function(event) {
                        var item = event.data.item;
                        personaje_actual.compra(item, false, 5);
                    });
                    botonItemNormal.on("click",{item: item}, function(event) {
                        var item = event.data.item;
                        personaje_actual.compra(item, false, 0);
                    });

                }
            }
            divCateg.append(gridCateg);
            contenidoDialogo.append(divCateg);
        }

        dialogo.append(contenidoDialogo);

        contenidoDialogo.accordion({
            heightStyle: "content",
            active: activo,
            collapsible: true
        });
    };

    actualizarDialogoEquipo(false);

    dialogo.dialog({
        modal: true,
        autoOpen: true,
        resizable: true,
        draggable: true,
        title: _l(DIAG_COMPRA_EQUIPO),
        position: "center",
        width: ANCHO_DIALOGO,
        height: ALTO_DIALOGO,
        maxHeight: ALTO_DIALOGO,
        closeOnEscape: true
    });

    dialogo.on("close",function( event, ui ) {
        dialogo.empty();
        removeActualizador(EVENT_CHARACTER_SECCION_EQUIPO,actualizarDialogoEquipo);
    });

    addActualizador(EVENT_CHARACTER_SECCION_EQUIPO,function() {
        actualizarDialogoEquipo($(contenidoDialogo).accordion("option","active"));
    });
}

function muestraVentanaAñadirEquipo() {
    var dialogo = getDiv();
    var zonaActual;
    var contenidoDialogo;

    var actualizarDialogoEquipo = function(activo) {
        dialogo.empty();
        contenidoDialogo = getDiv("");

        for (var j = 0; j < categorias_equipo.length; j++) {
            var categ = categorias_equipo[j];
            var divCateg = getDiv("contenedorBotonesVentajas");
            var gridCateg = $("

").addClass("three_up tiles").addClass(CSS_TEXTO_SMALL);

            contenidoDialogo.append("
"+_l(categ)+"
");

            for (var i =0; i < equipo_set[j].length; i++) {
                if (!equipo_set[j][i].isNoComprable()) {

                    var item = equipo_set[j][i];
                    var label = item.toString();
                    var botonItem = boton("big pretty primary btn",label,false).addClass("botonDialogoOpciones").css("width","100%");

                    gridCateg.append($("

").append(botonItem));

                    botonItem.on("click",{item: item}, function(event) {
                        seleccionaBono(event.data.item);
                    });
                }
            }
            divCateg.append(gridCateg);
            contenidoDialogo.append(divCateg);
        }

        dialogo.append(contenidoDialogo);

        contenidoDialogo.accordion({
            heightStyle: "content",
            active: activo,
            collapsible: true
        });
    };

    actualizarDialogoEquipo(false);

    dialogo.dialog({
        modal: true,
        autoOpen: true,
        resizable: true,
        draggable: true,
        title: _l(DIAG_AÑADIR_EQUIPO),
        position: "center",
        width: ANCHO_DIALOGO,
        height: ALTO_DIALOGO,
        maxHeight: ALTO_DIALOGO,
        closeOnEscape: true
    });

    dialogo.on("close",function( event, ui ) {
        dialogo.empty();
        removeActualizador(EVENT_CHARACTER_SECCION_EQUIPO,actualizarDialogoEquipo);
    });

    addActualizador(EVENT_CHARACTER_SECCION_EQUIPO,function() {
        actualizarDialogoEquipo($(contenidoDialogo).accordion("option","active"));
    });
}

function seleccionaBono(item) {
    var arrayOpciones = [];
    arrayOpciones.push(new OpcionMostrable("-5","-5",""));
    arrayOpciones.push(new OpcionMostrable("+0","+0",""));
    arrayOpciones.push(new OpcionMostrable("+5","+5",""));
    arrayOpciones.push(new OpcionMostrable("+10","+10",""));
    arrayOpciones.push(new OpcionMostrable("+15","+15",""));
    arrayOpciones.push(new OpcionMostrable("+20","+20",""));
    arrayOpciones.push(new OpcionMostrable("+25","+25",""));

    muestraDialogoElegirOpciones(arrayOpciones,{item:item},{principal:añadirObjeto,isDisabled:alwaysEnabled},true);
}

function añadirObjeto(parametros) {
    personaje_actual.compra(parametros.item, true, parseInt(parametros.opcion))
}<commit_msg>arreglado #225 lista de armas iniciales mal en ingles<commit_after>/**
 *
 */
function dialogoElegirArmaTodas() {
    var catArmas = [];

    for (var i=0; i<armas_set.length;i++) {
        var arma = armas_set[i];
        var categoria = arma.getCategoria();

        if (categoria != CAT_ARMA_MUNICION) {
            catArmas.push(categoria);
        }
    }
    dialogoElegirArma(catArmas, {principal:aplicarArma, isDisabled: alwaysEnabled},{})
}

function dialogoElegirTipoArma(categoriasPermitidas, callback, parametros) {
    var i;
    var j;
    var arrayOpciones = [];

    categorias:
    for (i=0; i<categoriasPermitidas.length;i++) {
        var categoria = categoriasPermitidas[i];

        for (j=0; j < arrayOpciones.length; j++) {
            if (categoria == arrayOpciones[j].etiqueta) {
                continue categorias;
            }
        }

        arrayOpciones.push(new OpcionMostrable(_l(categoria),categoria,""));
    }

    parametros.elegir = true;

    muestraDialogoElegirOpciones(arrayOpciones, parametros, callback, true);
}

/**
 *
 * @param {string[]} categoriasPermitidas
 * @param callback
 * @param parametros
 */
function dialogoElegirArma(categoriasPermitidas, callback, parametros) {
    var arrayArmas = [];
    var categorias = [];
    var i;
    var j;
    var k;

    for (i=0; i<armas_set.length;i++) {
        var arma = armas_set[i];
        var categoria = arma.getCategoria();
        var categoriaLoc = arma.getCategoriaLoc();

        var permitida = false;
        for (k = 0; k < categoriasPermitidas.length; k++) {
            if (categoria == categoriasPermitidas[k]) {
                permitida = true;
                break;
            }
        }
        if (!permitida) {
            continue;
        }
        var categoriaLimpia = categoria.replace("/","");

        var yaListada = false;
        for (j=0; j < categorias.length; j++) {
            if (categorias[j].etiqueta == categoriaLoc) {
                yaListada = true;
                break;
            }
        }

        if (!yaListada) {
            categorias.push(new OpcionMostrable(categoriaLoc,categoriaLimpia+"ElegirArma",categoriaLimpia+"ElegirArma"));
        }

        arrayArmas.push(new OpcionMostrable(_l(arma.nombre),arma.nombre,categoriaLimpia+"ElegirArma"));

    }

    parametros.elegir = true;

    muestraDialogoElegirOpciones(arrayArmas, parametros, callback, true, categorias);
}

function muestraVentanaCompraEquipo() {
    var dialogo = getDiv();
    var zonaActual;
    var contenidoDialogo;

    var actualizarDialogoEquipo = function(activo) {
        dialogo.empty();
        contenidoDialogo = getDiv("");

        for (var j = 0; j < categorias_equipo.length; j++) {
            var categ = categorias_equipo[j];
            var divCateg = getDiv("contenedorBotonesVentajas");
            var gridCateg = $("

").addClass("three_up tiles").addClass(CSS_TEXTO_SMALL);

            contenidoDialogo.append("
"+_l(categ)+"
");

            for (var i =0; i < equipo_set[j].length; i++) {
                if (!equipo_set[j][i].isNoComprable()) {
                    var item = equipo_set[j][i];
                    var itemNormal = new EquipoComprado(item,0,"");
                    var itemBueno = new EquipoComprado(item,5,"");
                    var itemMalo = new EquipoComprado(item,-5,"");
                    var labelNormal = itemNormal.toString() + " [" + itemNormal.getCosteDinero().toString() + "]";
                    var labelBueno = itemBueno.toString() + " [" + itemBueno.getCosteDinero().toString() + "]";
                    var labelMalo = itemMalo.toString() + " [" + itemMalo.getCosteDinero().toString() + "]";
                    var botonItemNormal = boton("big pretty primary btn",labelNormal,!personaje_actual.puedeGastarse(itemNormal.getCosteDinero())).addClass("botonDialogoOpciones").css("width","100%");
                    var botonItemBueno = boton("big pretty primary btn",labelBueno,!personaje_actual.puedeGastarse(itemBueno.getCosteDinero())).addClass("botonDialogoOpciones").css("width","100%");
                    var botonItemMalo = boton("big pretty primary btn",labelMalo,!personaje_actual.puedeGastarse(itemMalo.getCosteDinero())).addClass("botonDialogoOpciones").css("width","100%");

                    gridCateg.append($("

").append(botonItemMalo));
                    gridCateg.append($("

").append(botonItemNormal));
                    gridCateg.append($("

").append(botonItemBueno));

                    botonItemMalo.on("click",{item: item}, function(event) {
                        var item = event.data.item;
                        personaje_actual.compra(item, false, -5);
                    });
                    botonItemBueno.on("click",{item: item}, function(event) {
                        var item = event.data.item;
                        personaje_actual.compra(item, false, 5);
                    });
                    botonItemNormal.on("click",{item: item}, function(event) {
                        var item = event.data.item;
                        personaje_actual.compra(item, false, 0);
                    });

                }
            }
            divCateg.append(gridCateg);
            contenidoDialogo.append(divCateg);
        }

        dialogo.append(contenidoDialogo);

        contenidoDialogo.accordion({
            heightStyle: "content",
            active: activo,
            collapsible: true
        });
    };

    actualizarDialogoEquipo(false);

    dialogo.dialog({
        modal: true,
        autoOpen: true,
        resizable: true,
        draggable: true,
        title: _l(DIAG_COMPRA_EQUIPO),
        position: "center",
        width: ANCHO_DIALOGO,
        height: ALTO_DIALOGO,
        maxHeight: ALTO_DIALOGO,
        closeOnEscape: true
    });

    dialogo.on("close",function( event, ui ) {
        dialogo.empty();
        removeActualizador(EVENT_CHARACTER_SECCION_EQUIPO,actualizarDialogoEquipo);
    });

    addActualizador(EVENT_CHARACTER_SECCION_EQUIPO,function() {
        actualizarDialogoEquipo($(contenidoDialogo).accordion("option","active"));
    });
}

function muestraVentanaAñadirEquipo() {
    var dialogo = getDiv();
    var zonaActual;
    var contenidoDialogo;

    var actualizarDialogoEquipo = function(activo) {
        dialogo.empty();
        contenidoDialogo = getDiv("");

        for (var j = 0; j < categorias_equipo.length; j++) {
            var categ = categorias_equipo[j];
            var divCateg = getDiv("contenedorBotonesVentajas");
            var gridCateg = $("

").addClass("three_up tiles").addClass(CSS_TEXTO_SMALL);

            contenidoDialogo.append("
"+_l(categ)+"
");

            for (var i =0; i < equipo_set[j].length; i++) {
                if (!equipo_set[j][i].isNoComprable()) {

                    var item = equipo_set[j][i];
                    var label = item.toString();
                    var botonItem = boton("big pretty primary btn",label,false).addClass("botonDialogoOpciones").css("width","100%");

                    gridCateg.append($("

").append(botonItem));

                    botonItem.on("click",{item: item}, function(event) {
                        seleccionaBono(event.data.item);
                    });
                }
            }
            divCateg.append(gridCateg);
            contenidoDialogo.append(divCateg);
        }

        dialogo.append(contenidoDialogo);

        contenidoDialogo.accordion({
            heightStyle: "content",
            active: activo,
            collapsible: true
        });
    };

    actualizarDialogoEquipo(false);

    dialogo.dialog({
        modal: true,
        autoOpen: true,
        resizable: true,
        draggable: true,
        title: _l(DIAG_AÑADIR_EQUIPO),
        position: "center",
        width: ANCHO_DIALOGO,
        height: ALTO_DIALOGO,
        maxHeight: ALTO_DIALOGO,
        closeOnEscape: true
    });

    dialogo.on("close",function( event, ui ) {
        dialogo.empty();
        removeActualizador(EVENT_CHARACTER_SECCION_EQUIPO,actualizarDialogoEquipo);
    });

    addActualizador(EVENT_CHARACTER_SECCION_EQUIPO,function() {
        actualizarDialogoEquipo($(contenidoDialogo).accordion("option","active"));
    });
}

function seleccionaBono(item) {
    var arrayOpciones = [];
    arrayOpciones.push(new OpcionMostrable("-5","-5",""));
    arrayOpciones.push(new OpcionMostrable("+0","+0",""));
    arrayOpciones.push(new OpcionMostrable("+5","+5",""));
    arrayOpciones.push(new OpcionMostrable("+10","+10",""));
    arrayOpciones.push(new OpcionMostrable("+15","+15",""));
    arrayOpciones.push(new OpcionMostrable("+20","+20",""));
    arrayOpciones.push(new OpcionMostrable("+25","+25",""));

    muestraDialogoElegirOpciones(arrayOpciones,{item:item},{principal:añadirObjeto,isDisabled:alwaysEnabled},true);
}

function añadirObjeto(parametros) {
    personaje_actual.compra(parametros.item, true, parseInt(parametros.opcion))
}<|endoftext|>


<commit_before>import { join, relative, sep, normalize } from 'path'
import WebpackDevMiddleware from 'webpack-dev-middleware'
import WebpackHotMiddleware from 'webpack-hot-middleware'
import errorOverlayMiddleware from './lib/error-overlay-middleware'
import del from 'del'
import onDemandEntryHandler, {normalizePage} from './on-demand-entry-handler'
import webpack from 'webpack'
import WebSocket from 'ws'
import getBaseWebpackConfig from '../build/webpack-config'
import {IS_BUNDLED_PAGE_REGEX, ROUTE_NAME_REGEX, BLOCKED_PAGES, CLIENT_STATIC_FILES_PATH} from 'next-server/constants'
import {route} from 'next-server/dist/server/router'

export async function renderScriptError (res, error) {
  // Asks CDNs and others to not to cache the errored page
  res.setHeader('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate')

  if (error.code === 'ENOENT' || error.message === 'INVALID_BUILD_ID') {
    res.statusCode = 404
    res.end('404 - Not Found')
    return
  }

  console.error(error.stack)
  res.statusCode = 500
  res.end('500 - Internal Error')
}

function addCorsSupport (req, res) {
  if (!req.headers.origin) {
    return { preflight: false }
  }

  res.setHeader('Access-Control-Allow-Origin', req.headers.origin)
  res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET')
  // Based on https://github.com/primus/access-control/blob/4cf1bc0e54b086c91e6aa44fb14966fa5ef7549c/index.js#L158
  if (req.headers['access-control-request-headers']) {
    res.setHeader('Access-Control-Allow-Headers', req.headers['access-control-request-headers'])
  }

  if (req.method === 'OPTIONS') {
    res.writeHead(200)
    res.end()
    return { preflight: true }
  }

  return { preflight: false }
}

const matchNextPageBundleRequest = route('/_next/static/:buildId/pages/:path*.js(.map)?')

// Recursively look up the issuer till it ends up at the root
function findEntryModule (issuer) {
  if (issuer.issuer) {
    return findEntryModule(issuer.issuer)
  }

  return issuer
}

function erroredPages (compilation, options = {enhanceName: (name) => name}) {
  const failedPages = {}
  for (const error of compilation.errors) {
    const entryModule = findEntryModule(error.origin)
    const {name} = entryModule
    if (!name) {
      continue
    }

    // Only pages have to be reloaded
    if (!IS_BUNDLED_PAGE_REGEX.test(name)) {
      continue
    }

    const enhancedName = options.enhanceName(name)

    if (!failedPages[enhancedName]) {
      failedPages[enhancedName] = []
    }

    failedPages[enhancedName].push(error)
  }

  return failedPages
}

export default class HotReloader {
  constructor (dir, { config, buildId } = {}) {
    this.buildId = buildId
    this.dir = dir
    this.middlewares = []
    this.webpackDevMiddleware = null
    this.webpackHotMiddleware = null
    this.initialized = false
    this.stats = null
    this.compilationErrors = null
    this.prevChunkNames = null
    this.prevFailedChunkNames = null
    this.prevChunkHashes = null
    this.serverPrevDocumentHash = null

    this.config = config
  }

  async run (req, res, parsedUrl) {
    // Usually CORS support is not needed for the hot-reloader (this is dev only feature)
    // With when the app runs for multi-zones support behind a proxy,
    // the current page is trying to access this URL via assetPrefix.
    // That's when the CORS support is needed.
    const { preflight } = addCorsSupport(req, res)
    if (preflight) {
      return
    }

    // When a request comes in that is a page bundle, e.g. /_next/static/<buildid>/pages/index.js
    // we have to compile the page using on-demand-entries, this middleware will handle doing that
    // by adding the page to on-demand-entries, waiting till it's done
    // and then the bundle will be served like usual by the actual route in server/index.js
    const handlePageBundleRequest = async (req, res, parsedUrl) => {
      const {pathname} = parsedUrl
      const params = matchNextPageBundleRequest(pathname)
      if (!params) {
        return {}
      }

      if (params.buildId !== this.buildId) {
        return
      }

      const page = `/${params.path.join('/')}`
      if (BLOCKED_PAGES.indexOf(page) === -1) {
        try {
          await this.ensurePage(page)
        } catch (error) {
          await renderScriptError(res, error)
          return {finished: true}
        }

        const errors = await this.getCompilationErrors(page)
        if (errors.length > 0) {
          await renderScriptError(res, errors[0])
          return {finished: true}
        }
      }

      return {}
    }

    const {finished} = await handlePageBundleRequest(req, res, parsedUrl)

    for (const fn of this.middlewares) {
      await new Promise((resolve, reject) => {
        fn(req, res, (err) => {
          if (err) return reject(err)
          resolve()
        })
      })
    }

    return {finished}
  }

  async clean () {
    return del(join(this.dir, this.config.distDir), { force: true })
  }

  addWsPort (configs) {
    configs[0].plugins.push(new webpack.DefinePlugin({
      'process.env.NEXT_WS_PORT': this.wsPort
    }))
  }

  async start () {
    await this.clean()

    await new Promise(resolve => {
      // create dynamic entries WebSocket
      this.wss = new WebSocket.Server({ port: 0 }, () => {
        this.wsPort = this.wss.address().port
        resolve()
      })
    })

    const configs = await Promise.all([
      getBaseWebpackConfig(this.dir, { dev: true, isServer: false, config: this.config, buildId: this.buildId }),
      getBaseWebpackConfig(this.dir, { dev: true, isServer: true, config: this.config, buildId: this.buildId })
    ])
    this.addWsPort(configs)

    const multiCompiler = webpack(configs)

    const buildTools = await this.prepareBuildTools(multiCompiler)
    this.assignBuildTools(buildTools)

    this.stats = (await this.waitUntilValid()).stats[0]
  }

  async stop (webpackDevMiddleware) {
    this.wss.close()
    const middleware = webpackDevMiddleware || this.webpackDevMiddleware
    if (middleware) {
      return new Promise((resolve, reject) => {
        middleware.close((err) => {
          if (err) return reject(err)
          resolve()
        })
      })
    }
  }

  async reload () {
    this.stats = null

    await this.clean()

    const configs = await Promise.all([
      getBaseWebpackConfig(this.dir, { dev: true, isServer: false, config: this.config, buildId: this.buildId }),
      getBaseWebpackConfig(this.dir, { dev: true, isServer: true, config: this.config, buildId: this.buildId })
    ])
    this.addWsPort(configs)

    const compiler = webpack(configs)

    const buildTools = await this.prepareBuildTools(compiler)
    this.stats = await this.waitUntilValid(buildTools.webpackDevMiddleware)

    const oldWebpackDevMiddleware = this.webpackDevMiddleware

    this.assignBuildTools(buildTools)
    await this.stop(oldWebpackDevMiddleware)
  }

  assignBuildTools ({ webpackDevMiddleware, webpackHotMiddleware, onDemandEntries }) {
    this.webpackDevMiddleware = webpackDevMiddleware
    this.webpackHotMiddleware = webpackHotMiddleware
    this.onDemandEntries = onDemandEntries
    this.wss.on('connection', this.onDemandEntries.wsConnection)
    this.middlewares = [
      webpackDevMiddleware,
      webpackHotMiddleware,
      errorOverlayMiddleware,
      onDemandEntries.middleware()
    ]
  }

  async prepareBuildTools (multiCompiler) {
    // This plugin watches for changes to _document.js and notifies the client side that it should reload the page
    multiCompiler.compilers[1].hooks.done.tap('NextjsHotReloaderForServer', (stats) => {
      if (!this.initialized) {
        return
      }

      const {compilation} = stats

      // We only watch `_document` for changes on the server compilation
      // the rest of the files will be triggered by the client compilation
      const documentChunk = compilation.chunks.find(c => c.name === normalize(`static/${this.buildId}/pages/_document.js`))
      // If the document chunk can't be found we do nothing
      if (!documentChunk) {
        console.warn('_document.js chunk not found')
        return
      }

      // Initial value
      if (this.serverPrevDocumentHash === null) {
        this.serverPrevDocumentHash = documentChunk.hash
        return
      }

      // If _document.js didn't change we don't trigger a reload
      if (documentChunk.hash === this.serverPrevDocumentHash) {
        return
      }

      // Notify reload to reload the page, as _document.js was changed (different hash)
      this.send('reload', '/_document')

      this.serverPrevDocumentHash = documentChunk.hash
    })

    multiCompiler.compilers[0].hooks.done.tap('NextjsHotReloaderForClient', (stats) => {
      const { compilation } = stats
      const chunkNames = new Set(
        compilation.chunks
          .map((c) => c.name)
          .filter(name => IS_BUNDLED_PAGE_REGEX.test(name))
      )

      const failedChunkNames = new Set(Object.keys(erroredPages(compilation)))

      const chunkHashes = new Map(
        compilation.chunks
          .filter(c => IS_BUNDLED_PAGE_REGEX.test(c.name))
          .map((c) => [c.name, c.hash])
      )

      if (this.initialized) {
        // detect chunks which have to be replaced with a new template
        // e.g, pages/index.js <-> pages/_error.js
        const added = diff(chunkNames, this.prevChunkNames)
        const removed = diff(this.prevChunkNames, chunkNames)
        const succeeded = diff(this.prevFailedChunkNames, failedChunkNames)

        // reload all failed chunks to replace the templace to the error ones,
        // and to update error content
        const failed = failedChunkNames

        const rootDir = join(CLIENT_STATIC_FILES_PATH, this.buildId, 'pages')

        for (const n of new Set([...added, ...succeeded, ...removed, ...failed])) {
          const route = toRoute(relative(rootDir, n))
          this.send('reload', route)
        }

        let changedPageRoutes = []

        for (const [n, hash] of chunkHashes) {
          if (!this.prevChunkHashes.has(n)) continue
          if (this.prevChunkHashes.get(n) === hash) continue

          const route = toRoute(relative(rootDir, n))

          changedPageRoutes.push(route)
        }

        // This means `/_app` is most likely included in the list, or a page was added/deleted in this compilation run.
        // This means we should filter out `/_app` because `/_app` will be re-rendered with the page reload.
        if (added.size !== 0 || removed.size !== 0 || changedPageRoutes.length > 1) {
          changedPageRoutes = changedPageRoutes.filter((route) => route !== '/_app' && route !== '/_document')
        }

        for (const changedPageRoute of changedPageRoutes) {
          // notify change to recover from runtime errors
          this.send('change', changedPageRoute)
        }
      }

      this.initialized = true
      this.stats = stats
      this.compilationErrors = null
      this.prevChunkNames = chunkNames
      this.prevFailedChunkNames = failedChunkNames
      this.prevChunkHashes = chunkHashes
    })

    // We don’t watch .git/ .next/ and node_modules for changes
    const ignored = [
      /[\\/]\.git[\\/]/,
      /[\\/]\.next[\\/]/,
      /[\\/]node_modules[\\/]/
    ]

    let webpackDevMiddlewareConfig = {
      publicPath: `/_next/static/webpack`,
      noInfo: true,
      logLevel: 'silent',
      watchOptions: { ignored },
      writeToDisk: true
    }

    if (this.config.webpackDevMiddleware) {
      console.log(`> Using "webpackDevMiddleware" config function defined in ${this.config.configOrigin}.`)
      webpackDevMiddlewareConfig = this.config.webpackDevMiddleware(webpackDevMiddlewareConfig)
    }

    const webpackDevMiddleware = WebpackDevMiddleware(multiCompiler, webpackDevMiddlewareConfig)

    const webpackHotMiddleware = WebpackHotMiddleware(multiCompiler.compilers[0], {
      path: '/_next/webpack-hmr',
      log: false,
      heartbeat: 2500
    })

    const onDemandEntries = onDemandEntryHandler(webpackDevMiddleware, multiCompiler, {
      dir: this.dir,
      buildId: this.buildId,
      dev: true,
      reload: this.reload.bind(this),
      pageExtensions: this.config.pageExtensions,
      wsPort: this.wsPort,
      ...this.config.onDemandEntries
    })

    return {
      webpackDevMiddleware,
      webpackHotMiddleware,
      onDemandEntries
    }
  }

  waitUntilValid (webpackDevMiddleware) {
    const middleware = webpackDevMiddleware || this.webpackDevMiddleware
    return new Promise((resolve) => {
      middleware.waitUntilValid(resolve)
    })
  }

  async getCompilationErrors (page) {
    const normalizedPage = normalizePage(page)
    // When we are reloading, we need to wait until it's reloaded properly.
    await this.onDemandEntries.waitUntilReloaded()

    if (this.stats.hasErrors()) {
      const {compilation} = this.stats
      const failedPages = erroredPages(compilation, {
        enhanceName (name) {
          return '/' + ROUTE_NAME_REGEX.exec(name)[1]
        }
      })

      // If there is an error related to the requesting page we display it instead of the first error
      if (failedPages[normalizedPage] && failedPages[normalizedPage].length > 0) {
        return failedPages[normalizedPage]
      }

      // If none were found we still have to show the other errors
      return this.stats.compilation.errors
    }

    return []
  }

  send (action, ...args) {
    this.webpackHotMiddleware.publish({ action, data: args })
  }

  async ensurePage (page) {
    // Make sure we don't re-build or dispose prebuilt pages
    if (page === '/_error' || page === '/_document' || page === '/_app') {
      return
    }
    await this.onDemandEntries.ensurePage(page)
  }
}

function diff (a, b) {
  return new Set([...a].filter((v) => !b.has(v)))
}

function toRoute (file) {
  const f = sep === '\\' ? file.replace(/\\/g, '/') : file
  return ('/' + f).replace(/(\/index)?\.js$/, '') || '/'
}
<commit_msg>Make sure WebSocket server port is always detected (#5894)<commit_after>import { join, relative, sep, normalize } from 'path'
import WebpackDevMiddleware from 'webpack-dev-middleware'
import WebpackHotMiddleware from 'webpack-hot-middleware'
import errorOverlayMiddleware from './lib/error-overlay-middleware'
import del from 'del'
import onDemandEntryHandler, {normalizePage} from './on-demand-entry-handler'
import webpack from 'webpack'
import WebSocket from 'ws'
import getBaseWebpackConfig from '../build/webpack-config'
import {IS_BUNDLED_PAGE_REGEX, ROUTE_NAME_REGEX, BLOCKED_PAGES, CLIENT_STATIC_FILES_PATH} from 'next-server/constants'
import {route} from 'next-server/dist/server/router'

export async function renderScriptError (res, error) {
  // Asks CDNs and others to not to cache the errored page
  res.setHeader('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate')

  if (error.code === 'ENOENT' || error.message === 'INVALID_BUILD_ID') {
    res.statusCode = 404
    res.end('404 - Not Found')
    return
  }

  console.error(error.stack)
  res.statusCode = 500
  res.end('500 - Internal Error')
}

function addCorsSupport (req, res) {
  if (!req.headers.origin) {
    return { preflight: false }
  }

  res.setHeader('Access-Control-Allow-Origin', req.headers.origin)
  res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET')
  // Based on https://github.com/primus/access-control/blob/4cf1bc0e54b086c91e6aa44fb14966fa5ef7549c/index.js#L158
  if (req.headers['access-control-request-headers']) {
    res.setHeader('Access-Control-Allow-Headers', req.headers['access-control-request-headers'])
  }

  if (req.method === 'OPTIONS') {
    res.writeHead(200)
    res.end()
    return { preflight: true }
  }

  return { preflight: false }
}

const matchNextPageBundleRequest = route('/_next/static/:buildId/pages/:path*.js(.map)?')

// Recursively look up the issuer till it ends up at the root
function findEntryModule (issuer) {
  if (issuer.issuer) {
    return findEntryModule(issuer.issuer)
  }

  return issuer
}

function erroredPages (compilation, options = {enhanceName: (name) => name}) {
  const failedPages = {}
  for (const error of compilation.errors) {
    const entryModule = findEntryModule(error.origin)
    const {name} = entryModule
    if (!name) {
      continue
    }

    // Only pages have to be reloaded
    if (!IS_BUNDLED_PAGE_REGEX.test(name)) {
      continue
    }

    const enhancedName = options.enhanceName(name)

    if (!failedPages[enhancedName]) {
      failedPages[enhancedName] = []
    }

    failedPages[enhancedName].push(error)
  }

  return failedPages
}

export default class HotReloader {
  constructor (dir, { config, buildId } = {}) {
    this.buildId = buildId
    this.dir = dir
    this.middlewares = []
    this.webpackDevMiddleware = null
    this.webpackHotMiddleware = null
    this.initialized = false
    this.stats = null
    this.compilationErrors = null
    this.prevChunkNames = null
    this.prevFailedChunkNames = null
    this.prevChunkHashes = null
    this.serverPrevDocumentHash = null

    this.config = config
  }

  async run (req, res, parsedUrl) {
    // Usually CORS support is not needed for the hot-reloader (this is dev only feature)
    // With when the app runs for multi-zones support behind a proxy,
    // the current page is trying to access this URL via assetPrefix.
    // That's when the CORS support is needed.
    const { preflight } = addCorsSupport(req, res)
    if (preflight) {
      return
    }

    // When a request comes in that is a page bundle, e.g. /_next/static/<buildid>/pages/index.js
    // we have to compile the page using on-demand-entries, this middleware will handle doing that
    // by adding the page to on-demand-entries, waiting till it's done
    // and then the bundle will be served like usual by the actual route in server/index.js
    const handlePageBundleRequest = async (req, res, parsedUrl) => {
      const {pathname} = parsedUrl
      const params = matchNextPageBundleRequest(pathname)
      if (!params) {
        return {}
      }

      if (params.buildId !== this.buildId) {
        return
      }

      const page = `/${params.path.join('/')}`
      if (BLOCKED_PAGES.indexOf(page) === -1) {
        try {
          await this.ensurePage(page)
        } catch (error) {
          await renderScriptError(res, error)
          return {finished: true}
        }

        const errors = await this.getCompilationErrors(page)
        if (errors.length > 0) {
          await renderScriptError(res, errors[0])
          return {finished: true}
        }
      }

      return {}
    }

    const {finished} = await handlePageBundleRequest(req, res, parsedUrl)

    for (const fn of this.middlewares) {
      await new Promise((resolve, reject) => {
        fn(req, res, (err) => {
          if (err) return reject(err)
          resolve()
        })
      })
    }

    return {finished}
  }

  async clean () {
    return del(join(this.dir, this.config.distDir), { force: true })
  }

  addWsPort (configs) {
    configs[0].plugins.push(new webpack.DefinePlugin({
      'process.env.NEXT_WS_PORT': this.wsPort
    }))
  }

  async start () {
    await this.clean()

    this.wsPort = await new Promise((resolve, reject) => {
      // create dynamic entries WebSocket
      this.wss = new WebSocket.Server({ port: 0 }, function (err) {
        if (err) {
          return reject(err)
        }

        const {port} = this.address()
        if (!port) {
          return reject(new Error('No websocket port could be detected'))
        }
        resolve(port)
      })
    })

    const configs = await Promise.all([
      getBaseWebpackConfig(this.dir, { dev: true, isServer: false, config: this.config, buildId: this.buildId }),
      getBaseWebpackConfig(this.dir, { dev: true, isServer: true, config: this.config, buildId: this.buildId })
    ])
    this.addWsPort(configs)

    const multiCompiler = webpack(configs)

    const buildTools = await this.prepareBuildTools(multiCompiler)
    this.assignBuildTools(buildTools)

    this.stats = (await this.waitUntilValid()).stats[0]
  }

  async stop (webpackDevMiddleware) {
    this.wss.close()
    const middleware = webpackDevMiddleware || this.webpackDevMiddleware
    if (middleware) {
      return new Promise((resolve, reject) => {
        middleware.close((err) => {
          if (err) return reject(err)
          resolve()
        })
      })
    }
  }

  async reload () {
    this.stats = null

    await this.clean()

    const configs = await Promise.all([
      getBaseWebpackConfig(this.dir, { dev: true, isServer: false, config: this.config, buildId: this.buildId }),
      getBaseWebpackConfig(this.dir, { dev: true, isServer: true, config: this.config, buildId: this.buildId })
    ])
    this.addWsPort(configs)

    const compiler = webpack(configs)

    const buildTools = await this.prepareBuildTools(compiler)
    this.stats = await this.waitUntilValid(buildTools.webpackDevMiddleware)

    const oldWebpackDevMiddleware = this.webpackDevMiddleware

    this.assignBuildTools(buildTools)
    await this.stop(oldWebpackDevMiddleware)
  }

  assignBuildTools ({ webpackDevMiddleware, webpackHotMiddleware, onDemandEntries }) {
    this.webpackDevMiddleware = webpackDevMiddleware
    this.webpackHotMiddleware = webpackHotMiddleware
    this.onDemandEntries = onDemandEntries
    this.wss.on('connection', this.onDemandEntries.wsConnection)
    this.middlewares = [
      webpackDevMiddleware,
      webpackHotMiddleware,
      errorOverlayMiddleware,
      onDemandEntries.middleware()
    ]
  }

  async prepareBuildTools (multiCompiler) {
    // This plugin watches for changes to _document.js and notifies the client side that it should reload the page
    multiCompiler.compilers[1].hooks.done.tap('NextjsHotReloaderForServer', (stats) => {
      if (!this.initialized) {
        return
      }

      const {compilation} = stats

      // We only watch `_document` for changes on the server compilation
      // the rest of the files will be triggered by the client compilation
      const documentChunk = compilation.chunks.find(c => c.name === normalize(`static/${this.buildId}/pages/_document.js`))
      // If the document chunk can't be found we do nothing
      if (!documentChunk) {
        console.warn('_document.js chunk not found')
        return
      }

      // Initial value
      if (this.serverPrevDocumentHash === null) {
        this.serverPrevDocumentHash = documentChunk.hash
        return
      }

      // If _document.js didn't change we don't trigger a reload
      if (documentChunk.hash === this.serverPrevDocumentHash) {
        return
      }

      // Notify reload to reload the page, as _document.js was changed (different hash)
      this.send('reload', '/_document')

      this.serverPrevDocumentHash = documentChunk.hash
    })

    multiCompiler.compilers[0].hooks.done.tap('NextjsHotReloaderForClient', (stats) => {
      const { compilation } = stats
      const chunkNames = new Set(
        compilation.chunks
          .map((c) => c.name)
          .filter(name => IS_BUNDLED_PAGE_REGEX.test(name))
      )

      const failedChunkNames = new Set(Object.keys(erroredPages(compilation)))

      const chunkHashes = new Map(
        compilation.chunks
          .filter(c => IS_BUNDLED_PAGE_REGEX.test(c.name))
          .map((c) => [c.name, c.hash])
      )

      if (this.initialized) {
        // detect chunks which have to be replaced with a new template
        // e.g, pages/index.js <-> pages/_error.js
        const added = diff(chunkNames, this.prevChunkNames)
        const removed = diff(this.prevChunkNames, chunkNames)
        const succeeded = diff(this.prevFailedChunkNames, failedChunkNames)

        // reload all failed chunks to replace the templace to the error ones,
        // and to update error content
        const failed = failedChunkNames

        const rootDir = join(CLIENT_STATIC_FILES_PATH, this.buildId, 'pages')

        for (const n of new Set([...added, ...succeeded, ...removed, ...failed])) {
          const route = toRoute(relative(rootDir, n))
          this.send('reload', route)
        }

        let changedPageRoutes = []

        for (const [n, hash] of chunkHashes) {
          if (!this.prevChunkHashes.has(n)) continue
          if (this.prevChunkHashes.get(n) === hash) continue

          const route = toRoute(relative(rootDir, n))

          changedPageRoutes.push(route)
        }

        // This means `/_app` is most likely included in the list, or a page was added/deleted in this compilation run.
        // This means we should filter out `/_app` because `/_app` will be re-rendered with the page reload.
        if (added.size !== 0 || removed.size !== 0 || changedPageRoutes.length > 1) {
          changedPageRoutes = changedPageRoutes.filter((route) => route !== '/_app' && route !== '/_document')
        }

        for (const changedPageRoute of changedPageRoutes) {
          // notify change to recover from runtime errors
          this.send('change', changedPageRoute)
        }
      }

      this.initialized = true
      this.stats = stats
      this.compilationErrors = null
      this.prevChunkNames = chunkNames
      this.prevFailedChunkNames = failedChunkNames
      this.prevChunkHashes = chunkHashes
    })

    // We don’t watch .git/ .next/ and node_modules for changes
    const ignored = [
      /[\\/]\.git[\\/]/,
      /[\\/]\.next[\\/]/,
      /[\\/]node_modules[\\/]/
    ]

    let webpackDevMiddlewareConfig = {
      publicPath: `/_next/static/webpack`,
      noInfo: true,
      logLevel: 'silent',
      watchOptions: { ignored },
      writeToDisk: true
    }

    if (this.config.webpackDevMiddleware) {
      console.log(`> Using "webpackDevMiddleware" config function defined in ${this.config.configOrigin}.`)
      webpackDevMiddlewareConfig = this.config.webpackDevMiddleware(webpackDevMiddlewareConfig)
    }

    const webpackDevMiddleware = WebpackDevMiddleware(multiCompiler, webpackDevMiddlewareConfig)

    const webpackHotMiddleware = WebpackHotMiddleware(multiCompiler.compilers[0], {
      path: '/_next/webpack-hmr',
      log: false,
      heartbeat: 2500
    })

    const onDemandEntries = onDemandEntryHandler(webpackDevMiddleware, multiCompiler, {
      dir: this.dir,
      buildId: this.buildId,
      dev: true,
      reload: this.reload.bind(this),
      pageExtensions: this.config.pageExtensions,
      wsPort: this.wsPort,
      ...this.config.onDemandEntries
    })

    return {
      webpackDevMiddleware,
      webpackHotMiddleware,
      onDemandEntries
    }
  }

  waitUntilValid (webpackDevMiddleware) {
    const middleware = webpackDevMiddleware || this.webpackDevMiddleware
    return new Promise((resolve) => {
      middleware.waitUntilValid(resolve)
    })
  }

  async getCompilationErrors (page) {
    const normalizedPage = normalizePage(page)
    // When we are reloading, we need to wait until it's reloaded properly.
    await this.onDemandEntries.waitUntilReloaded()

    if (this.stats.hasErrors()) {
      const {compilation} = this.stats
      const failedPages = erroredPages(compilation, {
        enhanceName (name) {
          return '/' + ROUTE_NAME_REGEX.exec(name)[1]
        }
      })

      // If there is an error related to the requesting page we display it instead of the first error
      if (failedPages[normalizedPage] && failedPages[normalizedPage].length > 0) {
        return failedPages[normalizedPage]
      }

      // If none were found we still have to show the other errors
      return this.stats.compilation.errors
    }

    return []
  }

  send (action, ...args) {
    this.webpackHotMiddleware.publish({ action, data: args })
  }

  async ensurePage (page) {
    // Make sure we don't re-build or dispose prebuilt pages
    if (page === '/_error' || page === '/_document' || page === '/_app') {
      return
    }
    await this.onDemandEntries.ensurePage(page)
  }
}

function diff (a, b) {
  return new Set([...a].filter((v) => !b.has(v)))
}

function toRoute (file) {
  const f = sep === '\\' ? file.replace(/\\/g, '/') : file
  return ('/' + f).replace(/(\/index)?\.js$/, '') || '/'
}
<|endoftext|>


<commit_before>$(document).ready(function() {

  configureDataTables();
  configureCodeBox();
  configureGolf();

  $("form#run-code button#approve-button").live("click", function(e) {
    e.preventDefault();
    if(confirm("Are you sure you want to mark this problem as approved?"))
      $(this).parents("form").attr("action", "/problem/approve").submit();
  });

  $("form#run-code button#reject-button").live("click", function(e) {
    e.preventDefault();
    if(confirm("Are you sure you want to reject this problem? It will be permanently deleted.")) {
      $(this).parents("form").attr("action", "/problem/reject").submit();
    }
  });

  $("form#run-code button#edit-button").live("click", function(e) {
    e.preventDefault();
    $(this).parents("form").attr("action", "/problem/edit").submit();
  });

});

function configureDataTables(){

    $('#problem-table').dataTable( {
        "iDisplayLength": 25,
        "aaSorting": [[ 3, "desc" ]],
        "aoColumns": [
            null,
            null,
            null,
            null,
            null
        ]
    } );

    $('#unapproved-problems').dataTable( {
        "iDisplayLength": 25,
        "aaSorting": [[ 2, "desc" ]],
        "aoColumns": [
            null,
            null,
            null
        ]
    } );

    $('#user-table').dataTable( {
        "iDisplayLength":25,
        "aaSorting": [[ 0, "asc" ]],
        "aoColumns": [
	    null,
            null,
            null
        ]
    } );
}

function configureCodeBox(){
    //For no javascript version we have the code-box text area
    //If we have javascript on then we remove it and replace it with
    //the proper div
    var oldBox = $('#code-box');
    var hiddenCodeInput = "<input type=\"hidden\" value=\"blank\" name=\"code\" id=\"code\">";
    oldBox.replaceWith("

" + oldBox.val() + "

"+hiddenCodeInput);

    if ($("#run-button").length){
       var editor = ace.edit("editor");
       editor.setTheme("ace/theme/textmate");

       var ClojureMode = require("ace/mode/clojure").Mode;
       var session = editor.getSession();

       var clickHandler = function() {
         var text = session.getValue(),
           id = $('#id').attr("value"),
           images = $(".testcases").find("img"),
           cont = true,
           high = false,
           time = 800,

           beforeSendCallback = function(data) {
             $("#message-text").text("Executing unit tests...");
             var anim = function() {
               if(cont) {
                 images.animate({
                   opacity: high ? 1.0 : 0.1,
                 }, time);
                 high = !high;
                 setTimeout(anim,time);
               }
             };
             anim();
           },
           successCallback = function(data) {
             var failingTest = data.failingTest;
             cont = false;

             images.stop(true);
             images.css({ opacity: 1.0, });
             images.each( function(index,element) {
               var color = "blue";
               if (index < failingTest) {
                 color = "green";
               } else if (index === failingTest) {
                 color = "red";
               }
               element.src = "/images/"+color+"light.png";
             });

             $("#message-text").html(data.message);
             $("#golfgraph").html(data.golfChart);
             $("#golfscore").html(data.golfScore);
             configureGolf();
           };

         $.ajax({type: "POST",
           url: "/rest/problem/"+id,
           dataType: "json",
           data: { id: id, code: text, },
           timout: 20000, // default clojail timeout is 10000
           beforeSend: beforeSendCallback,
           success: successCallback,
           error: function(data, str, error) {
             $("#message-text").text("An Error occured: "+error);
           },
         });
         return false;
       };

       $("#run-button").click(clickHandler);

       session.setMode(new ClojureMode());
       session.setUseSoftTabs(true);
       session.setTabSize(2);

       document.getElementById('editor').style.fontSize='13px';
       $("#run-button").click(function(){
         var text = editor.getSession().getValue();
         $('#code').val(text);
       });
    }
}

function configureGolf(){
  $('#graph-link').show();
  $('#golfgraph').hide();
  $('#graph-link').click(function() {
    $('#code-div').toggle('fast', function() {
      // Animation complete.
    });
    $('#golfgraph').toggle('fast', function() {
      // Animation complete.
    });
    var text = $('#graph-link').html();
    if (text && text == 'View Chart'){
       $('#graph-link').html("View Code");
    } else {
       $('#graph-link').html("View Chart");
    }

});

}
<commit_msg>Slow down the AJAX interface a little bit<commit_after>$(document).ready(function() {

  configureDataTables();
  configureCodeBox();
  configureGolf();

  $("form#run-code button#approve-button").live("click", function(e) {
    e.preventDefault();
    if(confirm("Are you sure you want to mark this problem as approved?"))
      $(this).parents("form").attr("action", "/problem/approve").submit();
  });

  $("form#run-code button#reject-button").live("click", function(e) {
    e.preventDefault();
    if(confirm("Are you sure you want to reject this problem? It will be permanently deleted.")) {
      $(this).parents("form").attr("action", "/problem/reject").submit();
    }
  });

  $("form#run-code button#edit-button").live("click", function(e) {
    e.preventDefault();
    $(this).parents("form").attr("action", "/problem/edit").submit();
  });

});

function configureDataTables(){

    $('#problem-table').dataTable( {
        "iDisplayLength": 25,
        "aaSorting": [[ 3, "desc" ]],
        "aoColumns": [
            null,
            null,
            null,
            null,
            null
        ]
    } );

    $('#unapproved-problems').dataTable( {
        "iDisplayLength": 25,
        "aaSorting": [[ 2, "desc" ]],
        "aoColumns": [
            null,
            null,
            null
        ]
    } );

    $('#user-table').dataTable( {
        "iDisplayLength":25,
        "aaSorting": [[ 0, "asc" ]],
        "aoColumns": [
	    null,
            null,
            null
        ]
    } );
}

function setIconColor(element, color, timeOut) {
  timeOut = (typeof timeOut == "undefined") ? 0 : timeOut
  setTimeout (function() {
      element.src = "/images/"+color+"light.png";
  }, timeOut);
}

function configureCodeBox(){
    //For no javascript version we have the code-box text area
    //If we have javascript on then we remove it and replace it with
    //the proper div
    var oldBox = $('#code-box');
    var hiddenCodeInput = "<input type=\"hidden\" value=\"blank\" name=\"code\" id=\"code\">";
    oldBox.replaceWith("

" + oldBox.val() + "

"+hiddenCodeInput);

    if ($("#run-button").length){
       var editor = ace.edit("editor");
       editor.setTheme("ace/theme/textmate");

       var ClojureMode = require("ace/mode/clojure").Mode;
       var session = editor.getSession();

       var clickHandler = function() {
         var text = session.getValue(),
           id = $('#id').attr("value"),
           images = $(".testcases").find("img"),
           cont = true,
           high = false,
           animationTime = 800,
           waitTimePerItem = 500,
           waitTime = waitTimePerItem,

           beforeSendCallback = function(data) {
             $("#message-text").text("Executing unit tests...");
             images.each( function(index, element) {
               setIconColor(element, "blue");
             });
             var anim = function() {
               if(cont) {
                 images.animate({
                   opacity: high ? 1.0 : 0.1,
                 }, animationTime);
                 high = !high;
                 setTimeout(anim,animationTime);
               }
             };
             anim();
           },
           successCallback = function(data) {
             var failingTest = data.failingTest
                 getColorFor = function(index) {
                     return index === failingTest ? "red" : "green";
                 },
                 testWasExecuted = function(index) {
                     return index <= failingTest;
                 },
                 setColor = function(index,element) {
                     var color = getColorFor(index);
                     waitTime = waitTimePerItem * (index+1);
                     setIconColor(element, color, waitTime);
                 },
                 setMessages = function() {
                     $("#message-text").html(data.message);
                     $("#golfgraph").html(data.golfChart);
                     $("#golfscore").html(data.golfScore);
                     configureGolf();
                 };

             cont = false;
             images.stop(true);
             images.css({ opacity: 1.0, });
             images.filter( testWasExecuted ).
                 each(setColor);

             setTimeout (setMessages, waitTime);
           };

         $.ajax({type: "POST",
           url: "/rest/problem/"+id,
           dataType: "json",
           data: { id: id, code: text, },
           timout: 20000, // default clojail timeout is 10000
           beforeSend: beforeSendCallback,
           success: successCallback,
           error: function(data, str, error) {
             $("#message-text").text("An Error occured: "+error);
           },
         });
         return false;
       };

       $("#run-button").click(clickHandler);

       session.setMode(new ClojureMode());
       session.setUseSoftTabs(true);
       session.setTabSize(2);

       document.getElementById('editor').style.fontSize='13px';
       $("#run-button").click(function(){
         var text = editor.getSession().getValue();
         $('#code').val(text);
       });
    }
}

function configureGolf(){
  $('#graph-link').show();
  $('#golfgraph').hide();
  $('#graph-link').click(function() {
    $('#code-div').toggle('fast', function() {
      // Animation complete.
    });
    $('#golfgraph').toggle('fast', function() {
      // Animation complete.
    });
    var text = $('#graph-link').html();
    if (text && text == 'View Chart'){
       $('#graph-link').html("View Code");
    } else {
       $('#graph-link').html("View Chart");
    }

});

}
<|endoftext|>


<commit_before>var totalBudget = 2;

var html = '

Current

 /  /  secs

Page Average

 /  /  secs

Resources

FileDuration

WebPageTest.org (3G)

First Byte:

Start Render:

Load Time:

Speed Index:

DOM Elements:

';
document.body.innerHTML += html;

function init() {
   var navigationTiming = performance.timing;
   var now = new Date().getTime();

   //get client page speed
   var clientBackend = ((navigationTiming.responseEnd-navigationTiming.requestStart)/1000).toFixed(2);
   var clientFrontend = ((now-navigationTiming.domLoading)/1000).toFixed(2);
   var clientTotal = ((now-navigationTiming.navigationStart)/1000).toFixed(2);
   var url = window.location.host + window.location.pathname;

   document.getElementById('webperf-clientBackend').innerHTML = clientBackend;
   document.getElementById('webperf-clientFrontend').innerHTML = clientFrontend;
   document.getElementById('webperf-clientTotal').innerHTML = clientTotal;
   if (clientTotal>totalBudget) {
     document.getElementById("webperf-clientTotal").className = "webperf-red";
   }
   else {
     document.getElementById("webperf-clientTotal").className = "webperf-green";
   }

   //send client page speed to server & get average page speed back
   var json = {
      backend : clientBackend,
      frontend : clientFrontend,
      total : clientTotal,
      url : url
    }
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
      if(xhr.readyState == 4 && xhr.status == 200) {
        var response = JSON.parse(xhr.responseText);
        document.getElementById('webperf-serverBackend').innerHTML = response.backend;
      document.getElementById('webperf-serverFrontend').innerHTML = response.frontend;
      document.getElementById('webperf-serverTotal').innerHTML = response.total;
      if (response.total>totalBudget) {
        document.getElementById("webperf-serverTotal").className = "webperf-red";
      }
     else {
        document.getElementById("webperf-serverTotal").className = "webperf-green";
      }
      }
    }
    xhr.open('POST', './webperfSubmit.php', true);
    xhr.send(JSON.stringify(json));
}

function toggleClass(element, className){
  if (!element || !className){
      return;
  }

  var classString = element.className, nameIndex = classString.indexOf(className);
  if (nameIndex == -1) {
      classString += ' ' + className;
  }
  else {
      classString = classString.substr(0, nameIndex) + classString.substr(nameIndex+className.length);
  }
  element.className = classString;
  }

  document.getElementById('webperf-resources').addEventListener('click', function() {
  toggleClass(document.getElementById('webperf-resourceInfo'), 'webperf-hide');
  });

  document.getElementById('webperf-webpagetest').addEventListener('click', function() {
  toggleClass(document.getElementById('webperf-webpagetestInfo'), 'webperf-hide');
  });

  window.addEventListener('load', function() {
  var resources = window.performance.getEntriesByType('resource');
  var list = '';

  for (i=0; i<resources.length; i++) {
    var name = /[^/]*$/.exec(resources[i].name)[0];
    if (name=="") {
      name=resources[i].name;
    }
    var duration = (resources[i].duration/1000).toFixed(2);
    list += '
' + name + ''+duration+' secs
';
  }
  document.getElementById('webperf-resourceInfo').innerHTML += list;
});

var jsonUrl = "";

//Add webpage test results
function getWebPageTestUrl() {
  var webpagetestxhr = new XMLHttpRequest();

  webpagetestxhr.open("GET", "./getWebPageTest.php?url="+window.location.host+window.location.pathname+"", true);
  webpagetestxhr.onreadystatechange = function() {
      if (webpagetestxhr.readyState == 4 && webpagetestxhr.status == 200) {
          var resp = JSON.parse(webpagetestxhr.responseText);
          console.log(resp);
          if (resp.statusCode==400) {
          	console.log("Too many requests made for the day.");
          }
          else if (resp.statusCode==200) {
          	data=resp.data.average.firstView;
            var firstByte = (data.TTFB/1000).toFixed(2);
            var speedIndex = data.SpeedIndex;
            var loadTime = (data.loadTime/1000).toFixed(2);
            var startRender = (data.render/1000).toFixed(2);
            var domElements = data.domElements;

            document.getElementById('wpt-firstByte').innerHTML = firstByte+" secs";
            document.getElementById('wpt-speedIndex').innerHTML = speedIndex;
            document.getElementById('wpt-loadTime').innerHTML = loadTime+" secs";
            document.getElementById('wpt-startRender').innerHTML = startRender+" secs";
            document.getElementById('wpt-domElements').innerHTML = domElements;
          }
          else {
            //run getWebPageTestResults();
          }
      }
  }
  webpagetestxhr.send();
}
getWebPageTestUrl();<commit_msg>Update webPerfResults.js<commit_after>var totalBudget = 2;

var html = '

Current

 /  /  secs

Page Average

 /  /  secs

Resources

FileDuration

WebPageTest.org (3G)

First Byte:

Start Render:

Load Time:

Speed Index:

DOM Elements:

';
document.body.innerHTML += html;

function init() {
   var navigationTiming = performance.timing;
   var now = new Date().getTime();

   //get client page speed
   var clientBackend = ((navigationTiming.responseEnd-navigationTiming.requestStart)/1000).toFixed(2);
   var clientFrontend = ((now-navigationTiming.domLoading)/1000).toFixed(2);
   var clientTotal = ((now-navigationTiming.navigationStart)/1000).toFixed(2);
   var url = window.location.host + window.location.pathname;

   document.getElementById('webperf-clientBackend').innerHTML = clientBackend;
   document.getElementById('webperf-clientFrontend').innerHTML = clientFrontend;
   document.getElementById('webperf-clientTotal').innerHTML = clientTotal;
   if (clientTotal>totalBudget) {
     document.getElementById("webperf-clientTotal").className = "webperf-red";
   }
   else {
     document.getElementById("webperf-clientTotal").className = "webperf-green";
   }

   //send client page speed to server & get average page speed back
   var json = {
      backend : clientBackend,
      frontend : clientFrontend,
      total : clientTotal,
      url : url
    }
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
      if(xhr.readyState == 4 && xhr.status == 200) {
        var response = JSON.parse(xhr.responseText);
        document.getElementById('webperf-serverBackend').innerHTML = response.backend;
      document.getElementById('webperf-serverFrontend').innerHTML = response.frontend;
      document.getElementById('webperf-serverTotal').innerHTML = response.total;
      if (response.total>totalBudget) {
        document.getElementById("webperf-serverTotal").className = "webperf-red";
      }
     else {
        document.getElementById("webperf-serverTotal").className = "webperf-green";
      }
      }
    }
    xhr.open('POST', './webperfSubmit.php', true);
    xhr.send(JSON.stringify(json));
}

function toggleClass(element, className){
  if (!element || !className){
      return;
  }

  var classString = element.className, nameIndex = classString.indexOf(className);
  if (nameIndex == -1) {
      classString += ' ' + className;
  }
  else {
      classString = classString.substr(0, nameIndex) + classString.substr(nameIndex+className.length);
  }
  element.className = classString;
  }

  document.getElementById('webperf-resources').addEventListener('click', function() {
  toggleClass(document.getElementById('webperf-resourceInfo'), 'webperf-hide');
  });

  document.getElementById('webperf-webpagetest').addEventListener('click', function() {
  toggleClass(document.getElementById('webperf-webpagetestInfo'), 'webperf-hide');
  });

  window.addEventListener('load', function() {
  var resources = window.performance.getEntriesByType('resource');
  var list = '';

  for (i=0; i<resources.length; i++) {
    var name = /[^/]*$/.exec(resources[i].name)[0];
    if (name=="") {
      name=resources[i].name;
    }
    var duration = (resources[i].duration/1000).toFixed(2);
    list += '
' + name + ''+duration+' secs
';
  }
  document.getElementById('webperf-resourceInfo').innerHTML += list;
});

var jsonUrl = "";

//Add webpage test results
function getWebPageTestUrl() {
	document.getElementById('wpt-firstByte').innerHTML = "waiting...";
	    document.getElementById('wpt-speedIndex').innerHTML = "waiting...";
	    document.getElementById('wpt-loadTime').innerHTML = "waiting...";
	    document.getElementById('wpt-startRender').innerHTML = "waiting...";
	    document.getElementById('wpt-domElements').innerHTML = "waiting...";

  var webpagetestxhr = new XMLHttpRequest();

  webpagetestxhr.open("GET", "./getWebPageTest.php?url="+window.location.host+window.location.pathname+"", true);
  webpagetestxhr.onreadystatechange = function() {
      if (webpagetestxhr.readyState == 4 && webpagetestxhr.status == 200) {
          var resp = JSON.parse(webpagetestxhr.responseText);
          if (resp.statusCode==400) {
          	console.log("Too many requests made for the day.");
          }
          else if (resp.statusCode==200) {
          	data=resp.data.runs['1'].firstView;
            var firstByte = (data.TTFB/1000).toFixed(2);
            var speedIndex = data.SpeedIndex;
            var loadTime = (data.loadTime/1000).toFixed(2);
            var startRender = (data.render/1000).toFixed(2);
            var domElements = data.domElements;

            document.getElementById('wpt-firstByte').innerHTML = firstByte+" secs";
            document.getElementById('wpt-speedIndex').innerHTML = speedIndex;
            document.getElementById('wpt-loadTime').innerHTML = loadTime+" secs";
            document.getElementById('wpt-startRender').innerHTML = startRender+" secs";
            document.getElementById('wpt-domElements').innerHTML = domElements;
          }
          else {
          	console.log("Try again...");
            setTimeout(function(){getWebPageTestUrl()},5000);
          }
      }
  }
  webpagetestxhr.send();
}
getWebPageTestUrl();
<|endoftext|>