<commit_before>'use strict'

var server = require('./server')
var stream = require('stream')
var fs = require('fs')
var request = require('../index')
var path = require('path')
var util = require('util')
var tape = require('tape')

var s = server.createServer()

s.on('/cat', function (req, res) {
  if (req.method === 'GET') {
    res.writeHead(200, {
      'content-type': 'text/plain-test',
      'content-length': 4
    })
    res.end('asdf')
  } else if (req.method === 'PUT') {
    var body = ''
    req.on('data', function (chunk) {
      body += chunk
    }).on('end', function () {
      res.writeHead(201)
      res.end()
      s.emit('catDone', req, res, body)
    })
  }
})

s.on('/doodle', function (req, res) {
  if (req.headers['x-oneline-proxy']) {
    res.setHeader('x-oneline-proxy', 'yup')
  }
  res.writeHead('200', { 'content-type': 'image/jpeg' })
  fs.createReadStream(path.join(__dirname, 'googledoodle.jpg')).pipe(res)
})

function ValidationStream (t, str) {
  this.str = str
  this.buf = ''
  this.on('data', function (data) {
    this.buf += data
  })
  this.on('end', function () {
    t.equal(this.str, this.buf)
  })
  this.writable = true
}

util.inherits(ValidationStream, stream.Stream)

ValidationStream.prototype.write = function (chunk) {
  this.emit('data', chunk)
}

ValidationStream.prototype.end = function (chunk) {
  if (chunk) {
    this.emit('data', chunk)
  }
  this.emit('end')
}

tape('setup', function (t) {
  s.listen(0, function () {
    t.end()
  })
})

tape('piping to a request object', function (t) {
  s.once('/push', server.createPostValidator('mydata'))

  var mydata = new stream.Stream()
  mydata.readable = true

  var r1 = request.put({
    url: s.url + '/push'
  }, function (err, res, body) {
    t.equal(err, null)
    t.equal(res.statusCode, 200)
    t.equal(body, 'mydata')
    t.end()
  })
  mydata.pipe(r1)

  mydata.emit('data', 'mydata')
  mydata.emit('end')
})

tape('piping to a request object with invalid uri', function (t) {
  var mybodydata = new stream.Stream()
  mybodydata.readable = true

  var r2 = request.put({
    url: '/bad-uri',
    json: true
  }, function (err, res, body) {
    t.ok(err instanceof Error)
    t.equal(err.message, 'Invalid URI "/bad-uri"')
    t.end()
  })
  mybodydata.pipe(r2)

  mybodydata.emit('data', JSON.stringify({ foo: 'bar' }))
  mybodydata.emit('end')
})

tape('piping to a request object with a json body', function (t) {
  var obj = {foo: 'bar'}
  var json = JSON.stringify(obj)
  s.once('/push-json', server.createPostValidator(json, 'application/json'))
  var mybodydata = new stream.Stream()
  mybodydata.readable = true

  var r2 = request.put({
    url: s.url + '/push-json',
    json: true
  }, function (err, res, body) {
    t.equal(err, null)
    t.equal(res.statusCode, 200)
    t.deepEqual(body, obj)
    t.end()
  })
  mybodydata.pipe(r2)

  mybodydata.emit('data', JSON.stringify({ foo: 'bar' }))
  mybodydata.emit('end')
})

tape('piping from a request object', function (t) {
  s.once('/pull', server.createGetResponse('mypulldata'))

  var mypulldata = new stream.Stream()
  mypulldata.writable = true

  request({
    url: s.url + '/pull'
  }).pipe(mypulldata)

  var d = ''

  mypulldata.write = function (chunk) {
    d += chunk
  }
  mypulldata.end = function () {
    t.equal(d, 'mypulldata')
    t.end()
  }
})

tape('pause when piping from a request object', function (t) {
  s.once('/chunks', function (req, res) {
    res.writeHead(200, {
      'content-type': 'text/plain'
    })
    res.write('Chunk 1')
    setTimeout(function () { res.end('Chunk 2') }, 10)
  })

  var chunkNum = 0
  var paused = false
  request({
    url: s.url + '/chunks'
  })
    .on('data', function (chunk) {
      var self = this

      t.notOk(paused, 'Only receive data when not paused')

      ++chunkNum
      if (chunkNum === 1) {
        t.equal(chunk.toString(), 'Chunk 1')
        self.pause()
        paused = true
        setTimeout(function () {
          paused = false
          self.resume()
        }, 100)
      } else {
        t.equal(chunk.toString(), 'Chunk 2')
      }
    })
    .on('end', t.end.bind(t))
})

tape('pause before piping from a request object', function (t) {
  s.once('/pause-before', function (req, res) {
    res.writeHead(200, {
      'content-type': 'text/plain'
    })
    res.end('Data')
  })

  var paused = true
  var r = request({
    url: s.url + '/pause-before'
  })
  r.pause()
  r.on('data', function (data) {
    t.notOk(paused, 'Only receive data when not paused')
    t.equal(data.toString(), 'Data')
  })
  r.on('end', t.end.bind(t))

  setTimeout(function () {
    paused = false
    r.resume()
  }, 100)
})

var fileContents = fs.readFileSync(__filename)
function testPipeFromFile (testName, hasContentLength) {
  tape(testName, function (t) {
    s.once('/pushjs', function (req, res) {
      if (req.method === 'PUT') {
        t.equal(req.headers['content-type'], 'application/javascript')
        t.equal(
          req.headers['content-length'],
          (hasContentLength ? '' + fileContents.length : undefined))
        var body = ''
        req.setEncoding('utf8')
        req.on('data', function (data) {
          body += data
        })
        req.on('end', function () {
          res.end()
          t.equal(body, fileContents.toString())
          t.end()
        })
      } else {
        res.end()
      }
    })
    var r = request.put(s.url + '/pushjs')
    fs.createReadStream(__filename).pipe(r)
    if (hasContentLength) {
      r.setHeader('content-length', fileContents.length)
    }
  })
}

// TODO Piping from a file does not send content-length header
testPipeFromFile('piping from a file', false)
testPipeFromFile('piping from a file with content-length', true)

tape('piping to and from same URL', function (t) {
  s.once('catDone', function (req, res, body) {
    t.equal(req.headers['content-type'], 'text/plain-test')
    t.equal(req.headers['content-length'], '4')
    t.equal(body, 'asdf')
    t.end()
  })
  request.get(s.url + '/cat')
    .pipe(request.put(s.url + '/cat'))
})

tape('piping between urls', function (t) {
  s.once('/catresp', function (req, res) {
    request.get(s.url + '/cat').pipe(res)
  })

  request.get(s.url + '/catresp', function (err, res, body) {
    t.equal(err, null)
    t.equal(res.headers['content-type'], 'text/plain-test')
    t.equal(res.headers['content-length'], '4')
    t.end()
  })
})

tape('writing to file', function (t) {
  var doodleWrite = fs.createWriteStream(path.join(__dirname, 'test.jpg'))

  request.get(s.url + '/doodle').pipe(doodleWrite)

  doodleWrite.on('close', function () {
    t.deepEqual(
      fs.readFileSync(path.join(__dirname, 'googledoodle.jpg')),
      fs.readFileSync(path.join(__dirname, 'test.jpg')))
    fs.unlinkSync(path.join(__dirname, 'test.jpg'))
    t.end()
  })
})

tape('one-line proxy', function (t) {
  s.once('/onelineproxy', function (req, res) {
    var x = request(s.url + '/doodle')
    req.pipe(x)
    x.pipe(res)
  })

  request.get({
    uri: s.url + '/onelineproxy',
    headers: { 'x-oneline-proxy': 'nope' }
  }, function (err, res, body) {
    t.equal(err, null)
    t.equal(res.headers['x-oneline-proxy'], 'yup')
    t.notEqual(body, null)
    t.end()
  })
})

tape('piping after response', function (t) {
  s.once('/afterresponse', function (req, res) {
    res.write('d')
    res.end()
  })

  var rAfterRes = request.post(s.url + '/afterresponse')

  rAfterRes.on('response', function () {
    var v = new ValidationStream(t, 'd')
    rAfterRes.pipe(v)
    v.on('end', function () {
      t.end()
    })
  })
})

tape('piping through a redirect', function (t) {
  s.once('/forward1', function (req, res) {
    res.writeHead(302, { location: '/forward2' })
    res.end()
  })
  s.once('/forward2', function (req, res) {
    res.writeHead('200', { 'content-type': 'image/png' })
    res.write('d')
    res.end()
  })

  var validateForward = new ValidationStream(t, 'd')

  request.get(s.url + '/forward1').pipe(validateForward)

  validateForward.on('end', function () {
    t.end()
  })
})

tape('pipe options', function (t) {
  s.once('/opts', server.createGetResponse('opts response'))

  var optsStream = new stream.Stream()
  var optsData = ''

  optsStream.writable = true
  optsStream.write = function (buf) {
    optsData += buf
    if (optsData === 'opts response') {
      setTimeout(function () {
        t.end()
      }, 10)
    }
  }
  optsStream.end = function () {
    t.fail('end called')
  }

  request({
    url: s.url + '/opts'
  }).pipe(optsStream, { end: false })
})

tape('request.pipefilter is called correctly', function (t) {
  s.once('/pipefilter', function (req, res) {
    res.end('d')
  })
  var validatePipeFilter = new ValidationStream(t, 'd')

  var r3 = request.get(s.url + '/pipefilter')
  r3.pipe(validatePipeFilter)
  r3.pipefilter = function (res, dest) {
    t.equal(res, r3.response)
    t.equal(dest, validatePipeFilter)
    t.end()
  }
})

tape('cleanup', function (t) {
  s.close(function () {
    t.end()
  })
})
<commit_msg>chore: ensure piped body is exactly the same (#3064)<commit_after>'use strict'

var server = require('./server')
var stream = require('stream')
var fs = require('fs')
var request = require('../index')
var path = require('path')
var util = require('util')
var tape = require('tape')

var s = server.createServer()

s.on('/cat', function (req, res) {
  if (req.method === 'GET') {
    res.writeHead(200, {
      'content-type': 'text/plain-test',
      'content-length': 4
    })
    res.end('asdf')
  } else if (req.method === 'PUT') {
    var body = ''
    req.on('data', function (chunk) {
      body += chunk
    }).on('end', function () {
      res.writeHead(201)
      res.end()
      s.emit('catDone', req, res, body)
    })
  }
})

s.on('/doodle', function (req, res) {
  if (req.headers['x-oneline-proxy']) {
    res.setHeader('x-oneline-proxy', 'yup')
  }
  res.writeHead('200', { 'content-type': 'image/jpeg' })
  fs.createReadStream(path.join(__dirname, 'googledoodle.jpg')).pipe(res)
})

function ValidationStream (t, str) {
  this.str = str
  this.buf = ''
  this.on('data', function (data) {
    this.buf += data
  })
  this.on('end', function () {
    t.equal(this.str, this.buf)
  })
  this.writable = true
}

util.inherits(ValidationStream, stream.Stream)

ValidationStream.prototype.write = function (chunk) {
  this.emit('data', chunk)
}

ValidationStream.prototype.end = function (chunk) {
  if (chunk) {
    this.emit('data', chunk)
  }
  this.emit('end')
}

tape('setup', function (t) {
  s.listen(0, function () {
    t.end()
  })
})

tape('piping to a request object', function (t) {
  s.once('/push', server.createPostValidator('mydata'))

  var mydata = new stream.Stream()
  mydata.readable = true

  var r1 = request.put({
    url: s.url + '/push'
  }, function (err, res, body) {
    t.equal(err, null)
    t.equal(res.statusCode, 200)
    t.equal(body, 'mydata')
    t.end()
  })
  mydata.pipe(r1)

  mydata.emit('data', 'mydata')
  mydata.emit('end')
})

tape('piping to a request object with invalid uri', function (t) {
  var mybodydata = new stream.Stream()
  mybodydata.readable = true

  var r2 = request.put({
    url: '/bad-uri',
    json: true
  }, function (err, res, body) {
    t.ok(err instanceof Error)
    t.equal(err.message, 'Invalid URI "/bad-uri"')
    t.end()
  })
  mybodydata.pipe(r2)

  mybodydata.emit('data', JSON.stringify({ foo: 'bar' }))
  mybodydata.emit('end')
})

tape('piping to a request object with a json body', function (t) {
  var obj = {foo: 'bar'}
  var json = JSON.stringify(obj)
  s.once('/push-json', server.createPostValidator(json, 'application/json'))
  var mybodydata = new stream.Stream()
  mybodydata.readable = true

  var r2 = request.put({
    url: s.url + '/push-json',
    json: true
  }, function (err, res, body) {
    t.equal(err, null)
    t.equal(res.statusCode, 200)
    t.deepEqual(body, obj)
    t.end()
  })
  mybodydata.pipe(r2)

  mybodydata.emit('data', JSON.stringify({ foo: 'bar' }))
  mybodydata.emit('end')
})

tape('piping from a request object', function (t) {
  s.once('/pull', server.createGetResponse('mypulldata'))

  var mypulldata = new stream.Stream()
  mypulldata.writable = true

  request({
    url: s.url + '/pull'
  }).pipe(mypulldata)

  var d = ''

  mypulldata.write = function (chunk) {
    d += chunk
  }
  mypulldata.end = function () {
    t.equal(d, 'mypulldata')
    t.end()
  }
})

tape('pause when piping from a request object', function (t) {
  s.once('/chunks', function (req, res) {
    res.writeHead(200, {
      'content-type': 'text/plain'
    })
    res.write('Chunk 1')
    setTimeout(function () { res.end('Chunk 2') }, 10)
  })

  var chunkNum = 0
  var paused = false
  request({
    url: s.url + '/chunks'
  })
    .on('data', function (chunk) {
      var self = this

      t.notOk(paused, 'Only receive data when not paused')

      ++chunkNum
      if (chunkNum === 1) {
        t.equal(chunk.toString(), 'Chunk 1')
        self.pause()
        paused = true
        setTimeout(function () {
          paused = false
          self.resume()
        }, 100)
      } else {
        t.equal(chunk.toString(), 'Chunk 2')
      }
    })
    .on('end', t.end.bind(t))
})

tape('pause before piping from a request object', function (t) {
  s.once('/pause-before', function (req, res) {
    res.writeHead(200, {
      'content-type': 'text/plain'
    })
    res.end('Data')
  })

  var paused = true
  var r = request({
    url: s.url + '/pause-before'
  })
  r.pause()
  r.on('data', function (data) {
    t.notOk(paused, 'Only receive data when not paused')
    t.equal(data.toString(), 'Data')
  })
  r.on('end', t.end.bind(t))

  setTimeout(function () {
    paused = false
    r.resume()
  }, 100)
})

var fileContents = fs.readFileSync(__filename)
function testPipeFromFile (testName, hasContentLength) {
  tape(testName, function (t) {
    s.once('/pushjs', function (req, res) {
      if (req.method === 'PUT') {
        t.equal(req.headers['content-type'], 'application/javascript')
        t.equal(
          req.headers['content-length'],
          (hasContentLength ? '' + fileContents.length : undefined))
        var body = ''
        req.setEncoding('utf8')
        req.on('data', function (data) {
          body += data
        })
        req.on('end', function () {
          res.end()
          t.equal(body, fileContents.toString())
          t.end()
        })
      } else {
        res.end()
      }
    })
    var r = request.put(s.url + '/pushjs')
    fs.createReadStream(__filename).pipe(r)
    if (hasContentLength) {
      r.setHeader('content-length', fileContents.length)
    }
  })
}

// TODO Piping from a file does not send content-length header
testPipeFromFile('piping from a file', false)
testPipeFromFile('piping from a file with content-length', true)

tape('piping to and from same URL', function (t) {
  s.once('catDone', function (req, res, body) {
    t.equal(req.headers['content-type'], 'text/plain-test')
    t.equal(req.headers['content-length'], '4')
    t.equal(body, 'asdf')
    t.end()
  })
  request.get(s.url + '/cat')
    .pipe(request.put(s.url + '/cat'))
})

tape('piping between urls', function (t) {
  s.once('/catresp', function (req, res) {
    request.get(s.url + '/cat').pipe(res)
  })

  request.get(s.url + '/catresp', function (err, res, body) {
    t.equal(err, null)
    t.equal(res.headers['content-type'], 'text/plain-test')
    t.equal(res.headers['content-length'], '4')
    t.end()
  })
})

tape('writing to file', function (t) {
  var doodleWrite = fs.createWriteStream(path.join(__dirname, 'test.jpg'))

  request.get(s.url + '/doodle').pipe(doodleWrite)

  doodleWrite.on('close', function () {
    t.deepEqual(
      fs.readFileSync(path.join(__dirname, 'googledoodle.jpg')),
      fs.readFileSync(path.join(__dirname, 'test.jpg')))
    fs.unlinkSync(path.join(__dirname, 'test.jpg'))
    t.end()
  })
})

tape('one-line proxy', function (t) {
  s.once('/onelineproxy', function (req, res) {
    var x = request(s.url + '/doodle')
    req.pipe(x)
    x.pipe(res)
  })

  request.get({
    uri: s.url + '/onelineproxy',
    headers: { 'x-oneline-proxy': 'nope' }
  }, function (err, res, body) {
    t.equal(err, null)
    t.equal(res.headers['x-oneline-proxy'], 'yup')
    t.equal(body, fs.readFileSync(path.join(__dirname, 'googledoodle.jpg')).toString())
    t.end()
  })
})

tape('piping after response', function (t) {
  s.once('/afterresponse', function (req, res) {
    res.write('d')
    res.end()
  })

  var rAfterRes = request.post(s.url + '/afterresponse')

  rAfterRes.on('response', function () {
    var v = new ValidationStream(t, 'd')
    rAfterRes.pipe(v)
    v.on('end', function () {
      t.end()
    })
  })
})

tape('piping through a redirect', function (t) {
  s.once('/forward1', function (req, res) {
    res.writeHead(302, { location: '/forward2' })
    res.end()
  })
  s.once('/forward2', function (req, res) {
    res.writeHead('200', { 'content-type': 'image/png' })
    res.write('d')
    res.end()
  })

  var validateForward = new ValidationStream(t, 'd')

  request.get(s.url + '/forward1').pipe(validateForward)

  validateForward.on('end', function () {
    t.end()
  })
})

tape('pipe options', function (t) {
  s.once('/opts', server.createGetResponse('opts response'))

  var optsStream = new stream.Stream()
  var optsData = ''

  optsStream.writable = true
  optsStream.write = function (buf) {
    optsData += buf
    if (optsData === 'opts response') {
      setTimeout(function () {
        t.end()
      }, 10)
    }
  }
  optsStream.end = function () {
    t.fail('end called')
  }

  request({
    url: s.url + '/opts'
  }).pipe(optsStream, { end: false })
})

tape('request.pipefilter is called correctly', function (t) {
  s.once('/pipefilter', function (req, res) {
    res.end('d')
  })
  var validatePipeFilter = new ValidationStream(t, 'd')

  var r3 = request.get(s.url + '/pipefilter')
  r3.pipe(validatePipeFilter)
  r3.pipefilter = function (res, dest) {
    t.equal(res, r3.response)
    t.equal(dest, validatePipeFilter)
    t.end()
  }
})

tape('cleanup', function (t) {
  s.close(function () {
    t.end()
  })
})
<|endoftext|>


<commit_before>const async = require('async')
const Web3 = require('web3')
const assert = require('assert')

let Compiler = require('../src/compiler.js')
let Deployer = require('../src/deployer.js')
let TestRunner = require('../src/testRunner.js')

function compileAndDeploy (filename, callback) {
  let web3 = new Web3()
  web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'))

  async.waterfall([
    function compile (next) {
      Compiler.compileFileOrFiles(filename, false, next)
    },
    function deployAllContracts (compilationResult, next) {
      Deployer.deployAll(compilationResult, web3, next)
    }
  ], function (_err, contracts) {
    callback(null, contracts)
  })
}

describe('testRunner', function () {
  describe('test with beforeAll', function () {
    let filename = 'tests/examples_1/simple_storage_test.sol'
    let tests = [], results = {}

    before(function (done) {
      compileAndDeploy(filename, function (_err, contracts) {
        var testCallback = function (test) {
          tests.push(test)
        }
        var resultsCallback = function (_err, _results) {
          results = _results
          done()
        }
        TestRunner.runTest('MyTest', contracts.MyTest, testCallback, resultsCallback)
      })
    })

    it('should 1 passing test', function () {
      assert.equal(results.passingNum, 1)
    })

    it('should 1 failing test', function () {
      assert.equal(results.failureNum, 1)
    })

    it('should returns 3 messages', function () {
      assert.deepEqual(tests, [
        { type: 'contract',    value: 'MyTest' },
        { type: 'testPass',    value: 'Initial value should be100', time: 1 },
        { type: 'testFailure', value: 'Initial value should be200', time: 1 }
      ])
    })
  })

  describe('test with beforeEach', function () {
    let filename = 'tests/examples_2/simple_storage_test.sol'
    let tests = [], results = {}

    before(function (done) {
      compileAndDeploy(filename, function (_err, contracts) {
        var testCallback = function (test) {
          tests.push(test)
        }
        var resultsCallback = function (_err, _results) {
          results = _results
          done()
        }
        TestRunner.runTest('MyTest', contracts.MyTest, testCallback, resultsCallback)
      })
    })

    it('should 2 passing tests', function () {
      assert.equal(results.passingNum, 2)
    })

    it('should 0 failing tests', function () {
      assert.equal(results.failureNum, 0)
    })

    it('should returns 3 messages', function () {
      assert.deepEqual(tests, [
        { type: 'contract', value: 'MyTest' },
        { type: 'testPass', value: 'Initial value should be100', time: 1 },
        { type: 'testPass', value: 'Initial value should be200', time: 1 }
      ])
    })
  })
})
<commit_msg>add another describe to the test to reflect the method being tested<commit_after>const async = require('async')
const Web3 = require('web3')
const assert = require('assert')

let Compiler = require('../src/compiler.js')
let Deployer = require('../src/deployer.js')
let TestRunner = require('../src/testRunner.js')

function compileAndDeploy (filename, callback) {
  let web3 = new Web3()
  web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'))

  async.waterfall([
    function compile (next) {
      Compiler.compileFileOrFiles(filename, false, next)
    },
    function deployAllContracts (compilationResult, next) {
      Deployer.deployAll(compilationResult, web3, next)
    }
  ], function (_err, contracts) {
    callback(null, contracts)
  })
}

describe('testRunner', function () {
  describe('#runTest', function() {
    describe('test with beforeAll', function () {
      let filename = 'tests/examples_1/simple_storage_test.sol'
      let tests = [], results = {}

      before(function (done) {
        compileAndDeploy(filename, function (_err, contracts) {
          var testCallback = function (test) {
            tests.push(test)
          }
          var resultsCallback = function (_err, _results) {
            results = _results
            done()
          }
          TestRunner.runTest('MyTest', contracts.MyTest, testCallback, resultsCallback)
        })
      })

      it('should 1 passing test', function () {
        assert.equal(results.passingNum, 1)
      })

      it('should 1 failing test', function () {
        assert.equal(results.failureNum, 1)
      })

      it('should returns 3 messages', function () {
        assert.deepEqual(tests, [
          { type: 'contract',    value: 'MyTest' },
          { type: 'testPass',    value: 'Initial value should be100', time: 1 },
          { type: 'testFailure', value: 'Initial value should be200', time: 1 }
        ])
      })
    })

    describe('test with beforeEach', function () {
      let filename = 'tests/examples_2/simple_storage_test.sol'
      let tests = [], results = {}

      before(function (done) {
        compileAndDeploy(filename, function (_err, contracts) {
          var testCallback = function (test) {
            tests.push(test)
          }
          var resultsCallback = function (_err, _results) {
            results = _results
            done()
          }
          TestRunner.runTest('MyTest', contracts.MyTest, testCallback, resultsCallback)
        })
      })

      it('should 2 passing tests', function () {
        assert.equal(results.passingNum, 2)
      })

      it('should 0 failing tests', function () {
        assert.equal(results.failureNum, 0)
      })

      it('should returns 3 messages', function () {
        assert.deepEqual(tests, [
          { type: 'contract', value: 'MyTest' },
          { type: 'testPass', value: 'Initial value should be100', time: 1 },
          { type: 'testPass', value: 'Initial value should be200', time: 1 }
        ])
      })
    })
  })
})
<|endoftext|>


<commit_before>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
var async = require("async");
var Tapable = require("tapable");
var NormalModule = require("./NormalModule");
var RawModule = require("./RawModule");
var Parser = require("./Parser");
var RuleSet = require("./RuleSet");

function loaderToIdent(data) {
	if(!data.options)
		return data.loader;
	if(typeof data.options === "string")
		return data.loader + "?" + data.options;
	if(typeof data.options !== "object")
		throw new Error("loader options must be string or object");
	if(data.ident)
		return data.loader + "??" + data.ident;
	return data.loader + "?" + JSON.stringify(data.options);
}

function identToLoaderRequest(resultString) {
	var idx = resultString.indexOf("?");
	var options;

	if(idx >= 0) {
		options = resultString.substr(idx + 1);
		resultString = resultString.substr(0, idx);

		return {
			loader: resultString,
			options: options
		};
	} else {
		return {
			loader: resultString
		};
	}
}

function NormalModuleFactory(context, resolvers, options) {
	Tapable.call(this);
	this.resolvers = resolvers;
	this.ruleSet = new RuleSet(options.rules || options.loaders);
	this.cachePredicate = typeof options.unsafeCache === "function" ? options.unsafeCache : Boolean.bind(null, options.unsafeCache);
	this.context = context || "";
	this.parserCache = {};
	this.plugin("factory", function() {
		var _this = this;
		return function(result, callback) {
			var resolver = _this.applyPluginsWaterfall0("resolver", null);

			// Ignored
			if(!resolver) return callback();

			resolver(result, function onDoneResolving(err, data) {
				if(err) return callback(err);

				// Ignored
				if(!data) return callback();

				// direct module
				if(typeof data.source === "function")
					return callback(null, data);

				_this.applyPluginsAsyncWaterfall("after-resolve", data, function(err, result) {
					if(err) return callback(err);

					// Ignored
					if(!result) return callback();

					var createdModule = _this.applyPluginsBailResult("create-module", result);
					if(!createdModule) {

						if(!result.request) {
							return callback(new Error("Empty dependency (no request)"));
						}

						createdModule = new NormalModule(
							result.request,
							result.userRequest,
							result.rawRequest,
							result.loaders,
							result.resource,
							result.parser
						);
					}

					createdModule = _this.applyPluginsWaterfall0("module", createdModule);

					return callback(null, createdModule);
				});
			});
		};
	});
	this.plugin("resolver", function() {
		var _this = this;
		return function(data, callback) {
			var contextInfo = data.contextInfo;
			var context = data.context;
			var request = data.request;
			var resolveContextInfo = {};

			var noAutoLoaders = /^-?!/.test(request);
			var noPrePostAutoLoaders = /^!!/.test(request);
			var noPostAutoLoaders = /^-!/.test(request);
			var elements = request.replace(/^-?!+/, "").replace(/!!+/g, "!").split("!");
			var resource = elements.pop();
			elements = elements.map(identToLoaderRequest);

			async.parallel([
				function(callback) {
					_this.resolveRequestArray(resolveContextInfo, context, elements, _this.resolvers.loader, callback);
				},
				function(callback) {
					if(resource === "" || resource[0] === "?")
						return callback(null, resource);
					_this.resolvers.normal.resolve(resolveContextInfo, context, resource, function(err, resource, result) {
						if(err) return callback(err);
						callback(null, Object.assign({}, result, {
							resource: resource,
						}));
					});
				}
			], function(err, results) {
				if(err) return callback(err);
				var loaders = results[0];
				var resolverResult = results[1];
				resource = resolverResult.resource;

				// translate option idents
				try {
					loaders.forEach(function(item) {
						if(typeof item.options === "string" && /^\?/.test(item.options)) {
							item.options = _this.ruleSet.findOptionsByIdent(item.options.substr(1));
						}
					});
				} catch(e) {
					return callback(e);
				}

				if(resource === false)
					return callback(null,
						new RawModule("/* (ignored) */",
							"ignored " + context + " " + request,
							request + " (ignored)")); // ignored

				var userRequest = loaders.map(loaderToIdent).concat([resource]).join("!");

				var resourcePath = resource;
				var resourceQuery = "";
				var queryIndex = resourcePath.indexOf("?");
				if(queryIndex >= 0) {
					resourceQuery = resourcePath.substr(queryIndex);
					resourcePath = resourcePath.substr(0, queryIndex);
				}

				var result = _this.ruleSet.exec({
					resource: resourcePath,
					resourceQuery: resourceQuery,
					issuer: contextInfo.issuer
				});
				var settings = {};
				var useLoadersPost = [];
				var useLoaders = [];
				var useLoadersPre = [];
				result.forEach(function(r) {
					if(r.type === "use") {
						if(r.enforce === "post" && !noPostAutoLoaders && !noPrePostAutoLoaders)
							useLoadersPost.push(r.value);
						else if(r.enforce === "pre" && !noPrePostAutoLoaders)
							useLoadersPre.push(r.value);
						else if(!r.enforce && !noAutoLoaders && !noPrePostAutoLoaders)
							useLoaders.push(r.value);
					} else {
						settings[r.type] = r.value;
					}
				});
				async.parallel([
					_this.resolveRequestArray.bind(_this, resolveContextInfo, _this.context, useLoadersPost, _this.resolvers.loader),
					_this.resolveRequestArray.bind(_this, resolveContextInfo, _this.context, useLoaders, _this.resolvers.loader),
					_this.resolveRequestArray.bind(_this, resolveContextInfo, _this.context, useLoadersPre, _this.resolvers.loader)
				], function(err, results) {
					if(err) return callback(err);
					loaders = results[0].concat(loaders).concat(results[1]).concat(results[2]);
					process.nextTick(onDoneResolving);
				});

				function onDoneResolving() {
					callback(null, {
						context: context,
						request: loaders.map(loaderToIdent).concat([resource]).join("!"),
						dependencies: data.dependencies,
						userRequest: userRequest,
						rawRequest: request,
						loaders: loaders,
						resource: resource,
						resolverResult: resolverResult,
						parser: _this.getParser(settings.parser)
					});
				}
			});
		};
	});
}
module.exports = NormalModuleFactory;

NormalModuleFactory.prototype = Object.create(Tapable.prototype);
NormalModuleFactory.prototype.constructor = NormalModuleFactory;

NormalModuleFactory.prototype.create = function(data, callback) {
	var _this = this;
	var dependencies = data.dependencies;
	var cacheEntry = dependencies[0].__NormalModuleFactoryCache;
	if(cacheEntry) return callback(null, cacheEntry);
	var context = data.context || this.context;
	var request = dependencies[0].request;
	var contextInfo = data.contextInfo || {};
	_this.applyPluginsAsyncWaterfall("before-resolve", {
		contextInfo: contextInfo,
		context: context,
		request: request,
		dependencies: dependencies
	}, function(err, result) {
		if(err) return callback(err);

		// Ignored
		if(!result) return callback();

		var factory = _this.applyPluginsWaterfall0("factory", null);

		// Ignored
		if(!factory) return callback();

		factory(result, function(err, module) {
			if(err) return callback(err);

			if(module && _this.cachePredicate(module)) {
				dependencies.forEach(function(d) {
					d.__NormalModuleFactoryCache = module;
				});
			}

			callback(null, module);
		});

	});
};

NormalModuleFactory.prototype.resolveRequestArray = function resolveRequestArray(contextInfo, context, array, resolver, callback) {
	if(array.length === 0) return callback(null, []);
	async.map(array, function(item, callback) {
		resolver.resolve(contextInfo, context, item.loader, function(err, result) {
			if(err && /^[^/]*$/.test(item.loader) && !/-loader$/.test(item.loader)) {
				return resolver.resolve(contextInfo, context, item.loader + "-loader", function(err2) {
					if(!err2) {
						err.message = err.message + "\n" +
							"BREAKING CHANGE: It's no longer allowed to omit the '-loader' suffix when using loaders.\n" +
							"                 You need to specify '" + item.loader + "-loader' instead of '" + item.loader + "',\n" +
							"                 see https://webpack.js.org/guides/migrating/#automatic-loader-module-name-extension-removed";
					}
					callback(err);
				});
			}
			if(err) return callback(err);

			var optionsOnly = item.options ? {
				options: item.options
			} : undefined;
			return callback(null, Object.assign({}, item, identToLoaderRequest(result), optionsOnly));
		});
	}, callback);
};

NormalModuleFactory.prototype.getParser = function getParser(parserOptions) {
	var ident = "null";
	if(parserOptions) {
		if(parserOptions.ident)
			ident = parserOptions.ident;
		else
			ident = JSON.stringify(parserOptions);
	}
	var parser = this.parserCache[ident];
	if(parser)
		return parser;
	return this.parserCache[ident] = this.createParser(parserOptions);
};

NormalModuleFactory.prototype.createParser = function createParser(parserOptions) {
	var parser = new Parser();
	this.applyPlugins2("parser", parser, parserOptions || {});
	return parser;
};
<commit_msg>fix tests<commit_after>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
var async = require("async");
var Tapable = require("tapable");
var NormalModule = require("./NormalModule");
var RawModule = require("./RawModule");
var Parser = require("./Parser");
var RuleSet = require("./RuleSet");

function loaderToIdent(data) {
	if(!data.options)
		return data.loader;
	if(typeof data.options === "string")
		return data.loader + "?" + data.options;
	if(typeof data.options !== "object")
		throw new Error("loader options must be string or object");
	if(data.ident)
		return data.loader + "??" + data.ident;
	return data.loader + "?" + JSON.stringify(data.options);
}

function identToLoaderRequest(resultString) {
	var idx = resultString.indexOf("?");
	var options;

	if(idx >= 0) {
		options = resultString.substr(idx + 1);
		resultString = resultString.substr(0, idx);

		return {
			loader: resultString,
			options: options
		};
	} else {
		return {
			loader: resultString
		};
	}
}

function NormalModuleFactory(context, resolvers, options) {
	Tapable.call(this);
	this.resolvers = resolvers;
	this.ruleSet = new RuleSet(options.rules || options.loaders);
	this.cachePredicate = typeof options.unsafeCache === "function" ? options.unsafeCache : Boolean.bind(null, options.unsafeCache);
	this.context = context || "";
	this.parserCache = {};
	this.plugin("factory", function() {
		var _this = this;
		return function(result, callback) {
			var resolver = _this.applyPluginsWaterfall0("resolver", null);

			// Ignored
			if(!resolver) return callback();

			resolver(result, function onDoneResolving(err, data) {
				if(err) return callback(err);

				// Ignored
				if(!data) return callback();

				// direct module
				if(typeof data.source === "function")
					return callback(null, data);

				_this.applyPluginsAsyncWaterfall("after-resolve", data, function(err, result) {
					if(err) return callback(err);

					// Ignored
					if(!result) return callback();

					var createdModule = _this.applyPluginsBailResult("create-module", result);
					if(!createdModule) {

						if(!result.request) {
							return callback(new Error("Empty dependency (no request)"));
						}

						createdModule = new NormalModule(
							result.request,
							result.userRequest,
							result.rawRequest,
							result.loaders,
							result.resource,
							result.parser
						);
					}

					createdModule = _this.applyPluginsWaterfall0("module", createdModule);

					return callback(null, createdModule);
				});
			});
		};
	});
	this.plugin("resolver", function() {
		var _this = this;
		return function(data, callback) {
			var contextInfo = data.contextInfo;
			var context = data.context;
			var request = data.request;
			var resolveContextInfo = {};

			var noAutoLoaders = /^-?!/.test(request);
			var noPrePostAutoLoaders = /^!!/.test(request);
			var noPostAutoLoaders = /^-!/.test(request);
			var elements = request.replace(/^-?!+/, "").replace(/!!+/g, "!").split("!");
			var resource = elements.pop();
			elements = elements.map(identToLoaderRequest);

			async.parallel([
				function(callback) {
					_this.resolveRequestArray(resolveContextInfo, context, elements, _this.resolvers.loader, callback);
				},
				function(callback) {
					if(resource === "" || resource[0] === "?")
						return callback(null, { resource: resource });

					_this.resolvers.normal.resolve(resolveContextInfo, context, resource, function(err, resource, result) {
						if(err) return callback(err);
						callback(null, Object.assign({}, result, {
							resource: resource,
						}));
					});
				}
			], function(err, results) {
				if(err) return callback(err);
				var loaders = results[0];
				var resolverResult = results[1];
				resource = resolverResult.resource;

				// translate option idents
				try {
					loaders.forEach(function(item) {
						if(typeof item.options === "string" && /^\?/.test(item.options)) {
							item.options = _this.ruleSet.findOptionsByIdent(item.options.substr(1));
						}
					});
				} catch(e) {
					return callback(e);
				}

				if(resource === false)
					return callback(null,
						new RawModule("/* (ignored) */",
							"ignored " + context + " " + request,
							request + " (ignored)")); // ignored

				var userRequest = loaders.map(loaderToIdent).concat([resource]).join("!");

				var resourcePath = resource;
				var resourceQuery = "";
				var queryIndex = resourcePath.indexOf("?");
				if(queryIndex >= 0) {
					resourceQuery = resourcePath.substr(queryIndex);
					resourcePath = resourcePath.substr(0, queryIndex);
				}

				var result = _this.ruleSet.exec({
					resource: resourcePath,
					resourceQuery: resourceQuery,
					issuer: contextInfo.issuer
				});
				var settings = {};
				var useLoadersPost = [];
				var useLoaders = [];
				var useLoadersPre = [];
				result.forEach(function(r) {
					if(r.type === "use") {
						if(r.enforce === "post" && !noPostAutoLoaders && !noPrePostAutoLoaders)
							useLoadersPost.push(r.value);
						else if(r.enforce === "pre" && !noPrePostAutoLoaders)
							useLoadersPre.push(r.value);
						else if(!r.enforce && !noAutoLoaders && !noPrePostAutoLoaders)
							useLoaders.push(r.value);
					} else {
						settings[r.type] = r.value;
					}
				});
				async.parallel([
					_this.resolveRequestArray.bind(_this, resolveContextInfo, _this.context, useLoadersPost, _this.resolvers.loader),
					_this.resolveRequestArray.bind(_this, resolveContextInfo, _this.context, useLoaders, _this.resolvers.loader),
					_this.resolveRequestArray.bind(_this, resolveContextInfo, _this.context, useLoadersPre, _this.resolvers.loader)
				], function(err, results) {
					if(err) return callback(err);
					loaders = results[0].concat(loaders).concat(results[1]).concat(results[2]);
					process.nextTick(onDoneResolving);
				});

				function onDoneResolving() {
					callback(null, {
						context: context,
						request: loaders.map(loaderToIdent).concat([resource]).join("!"),
						dependencies: data.dependencies,
						userRequest: userRequest,
						rawRequest: request,
						loaders: loaders,
						resource: resource,
						resolverResult: resolverResult,
						parser: _this.getParser(settings.parser)
					});
				}
			});
		};
	});
}
module.exports = NormalModuleFactory;

NormalModuleFactory.prototype = Object.create(Tapable.prototype);
NormalModuleFactory.prototype.constructor = NormalModuleFactory;

NormalModuleFactory.prototype.create = function(data, callback) {
	var _this = this;
	var dependencies = data.dependencies;
	var cacheEntry = dependencies[0].__NormalModuleFactoryCache;
	if(cacheEntry) return callback(null, cacheEntry);
	var context = data.context || this.context;
	var request = dependencies[0].request;
	var contextInfo = data.contextInfo || {};
	_this.applyPluginsAsyncWaterfall("before-resolve", {
		contextInfo: contextInfo,
		context: context,
		request: request,
		dependencies: dependencies
	}, function(err, result) {
		if(err) return callback(err);

		// Ignored
		if(!result) return callback();

		var factory = _this.applyPluginsWaterfall0("factory", null);

		// Ignored
		if(!factory) return callback();

		factory(result, function(err, module) {
			if(err) return callback(err);

			if(module && _this.cachePredicate(module)) {
				dependencies.forEach(function(d) {
					d.__NormalModuleFactoryCache = module;
				});
			}

			callback(null, module);
		});

	});
};

NormalModuleFactory.prototype.resolveRequestArray = function resolveRequestArray(contextInfo, context, array, resolver, callback) {
	if(array.length === 0) return callback(null, []);
	async.map(array, function(item, callback) {
		resolver.resolve(contextInfo, context, item.loader, function(err, result) {
			if(err && /^[^/]*$/.test(item.loader) && !/-loader$/.test(item.loader)) {
				return resolver.resolve(contextInfo, context, item.loader + "-loader", function(err2) {
					if(!err2) {
						err.message = err.message + "\n" +
							"BREAKING CHANGE: It's no longer allowed to omit the '-loader' suffix when using loaders.\n" +
							"                 You need to specify '" + item.loader + "-loader' instead of '" + item.loader + "',\n" +
							"                 see https://webpack.js.org/guides/migrating/#automatic-loader-module-name-extension-removed";
					}
					callback(err);
				});
			}
			if(err) return callback(err);

			var optionsOnly = item.options ? {
				options: item.options
			} : undefined;
			return callback(null, Object.assign({}, item, identToLoaderRequest(result), optionsOnly));
		});
	}, callback);
};

NormalModuleFactory.prototype.getParser = function getParser(parserOptions) {
	var ident = "null";
	if(parserOptions) {
		if(parserOptions.ident)
			ident = parserOptions.ident;
		else
			ident = JSON.stringify(parserOptions);
	}
	var parser = this.parserCache[ident];
	if(parser)
		return parser;
	return this.parserCache[ident] = this.createParser(parserOptions);
};

NormalModuleFactory.prototype.createParser = function createParser(parserOptions) {
	var parser = new Parser();
	this.applyPlugins2("parser", parser, parserOptions || {});
	return parser;
};
<|endoftext|>


<commit_before>describe('Constraints', function () {
  var db;
  beforeEach(function () {
    db = new loki();
  });

  it('should retrieve records with by()', function () {
    var coll = db.addCollection('users', {
      unique: ['username']
    });
    coll.insert({
      username: 'joe',
      name: 'Joe'
    });
    coll.insert({
      username: 'jack',
      name: 'Jack'
    });
    expect(coll.by('username', 'joe').name).toEqual('Joe');

    var byUsername = coll.by('username');
    expect(byUsername('jack').name).toEqual('Jack');

    var joe = coll.get(1);
    joe.username = 'jack';
    coll.update(joe);
    expect(coll.get(1).username).toEqual('joe');

  });
})
<commit_msg>unique index insert and remove complete, update WIP<commit_after>describe('Constraints', function () {
  var db;
  beforeEach(function () {
    db = new loki();
  });

  it('should retrieve records with by()', function () {
    var coll = db.addCollection('users', {
      unique: ['username']
    });
    coll.insert({
      username: 'joe',
      name: 'Joe'
    });
    coll.insert({
      username: 'jack',
      name: 'Jack'
    });
    expect(coll.by('username', 'joe').name).toEqual('Joe');

    var byUsername = coll.by('username');
    expect(byUsername('jack').name).toEqual('Jack');

  });
});
<|endoftext|>


<commit_before>/**
* Copyright 2012-2016, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var Ternary = require('./ternary');

var Plots = require('../../plots/plots');

exports.name = 'ternary';

exports.attr = 'subplot';

exports.idRoot = 'ternary';

exports.idRegex = /^ternary([2-9]|[1-9][0-9]+)?$/;

exports.attrRegex = /^ternary([2-9]|[1-9][0-9]+)?$/;

exports.attributes = require('./layout/attributes');

exports.layoutAttributes = require('./layout/layout_attributes');

exports.supplyLayoutDefaults = require('./layout/defaults');

exports.plot = function plotTernary(gd) {
    var fullLayout = gd._fullLayout,
        fullData = gd._fullData,
        ternaryIds = Plots.getSubplotIds(fullLayout, 'ternary');

    for(var i = 0; i < ternaryIds.length; i++) {
        var ternaryId = ternaryIds[i],
            fullTernaryData = Plots.getSubplotData(fullData, 'ternary', ternaryId),
            ternary = fullLayout[ternaryId]._ternary;

        // If ternary is not instantiated, create one!
        if(ternary === undefined) {
            ternary = new Ternary({
                id: ternaryId,
                graphDiv: gd,
                container: fullLayout._ternarylayer.node()
            },
                fullLayout
            );

            fullLayout[ternaryId]._ternary = ternary;
        }

        ternary.plot(fullTernaryData, fullLayout, gd._promises);
    }
};

exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout) {
    var oldTernaryKeys = Plots.getSubplotIds(oldFullLayout, 'ternary');

    for(var i = 0; i < oldTernaryKeys.length; i++) {
        var oldTernaryKey = oldTernaryKeys[i];
        var oldTernary = oldFullLayout[oldTernaryKey]._ternary;

        if(!newFullLayout[oldTernaryKey] && !!oldTernary) {
            oldTernary.plotContainer.remove();
            oldTernary.clipDef.remove();
        }
    }
};
<commit_msg>store ref to ternary subplot object in fullLayout.ternary?._subplot<commit_after>/**
* Copyright 2012-2016, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var Ternary = require('./ternary');

var Plots = require('../../plots/plots');

exports.name = 'ternary';

exports.attr = 'subplot';

exports.idRoot = 'ternary';

exports.idRegex = /^ternary([2-9]|[1-9][0-9]+)?$/;

exports.attrRegex = /^ternary([2-9]|[1-9][0-9]+)?$/;

exports.attributes = require('./layout/attributes');

exports.layoutAttributes = require('./layout/layout_attributes');

exports.supplyLayoutDefaults = require('./layout/defaults');

exports.plot = function plotTernary(gd) {
    var fullLayout = gd._fullLayout,
        fullData = gd._fullData,
        ternaryIds = Plots.getSubplotIds(fullLayout, 'ternary');

    for(var i = 0; i < ternaryIds.length; i++) {
        var ternaryId = ternaryIds[i],
            fullTernaryData = Plots.getSubplotData(fullData, 'ternary', ternaryId),
            ternary = fullLayout[ternaryId]._ternary;

        // If ternary is not instantiated, create one!
        if(ternary === undefined) {
            ternary = new Ternary({
                id: ternaryId,
                graphDiv: gd,
                container: fullLayout._ternarylayer.node()
            },
                fullLayout
            );

            fullLayout[ternaryId]._subplot = ternary;
        }

        ternary.plot(fullTernaryData, fullLayout, gd._promises);
    }
};

exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout) {
    var oldTernaryKeys = Plots.getSubplotIds(oldFullLayout, 'ternary');

    for(var i = 0; i < oldTernaryKeys.length; i++) {
        var oldTernaryKey = oldTernaryKeys[i];
        var oldTernary = oldFullLayout[oldTernaryKey]._ternary;

        if(!newFullLayout[oldTernaryKey] && !!oldTernary) {
            oldTernary.plotContainer.remove();
            oldTernary.clipDef.remove();
        }
    }
};
<|endoftext|>


<commit_before>// install   : cordova plugin add https://github.com/sidneys/cordova-plugin-nativeaudio.git
// link      : https://github.com/sidneys/cordova-plugin-nativeaudio

angular.module('ngCordova.plugins.nativeAudio', [])

  .factory('$cordovaNativeAudio', ['$q', '$window', function ($q, $window) {

    return {
      preloadSimple: function (id, assetPath) {
        var q = $q.defer();
        $window.plugins.NativeAudio.preloadSimple(id, assetPath, function (result) {
          q.resolve(result);
        }, function (err) {
          q.reject(err);
        });

        return q.promise;
      },

      preloadComplex: function (id, assetPath, volume, voices) {
        var q = $q.defer();
        $window.plugins.NativeAudio.preloadComplex(id, assetPath, volume, voices, function (result) {
          q.resolve(result);
        }, function (err) {
          q.reject(err);
        });

        return q.promise;
      },

      play: function (id, completeCallback) {
        var q = $q.defer();
        $window.plugins.NativeAudio.play(id, completeCallback, function (result) {
          q.resolve(result);
        }, function (err) {
          q.reject(err);
        });

        return q.promise;
      },

      stop: function (id) {
        var q = $q.defer();
        $window.plugins.NativeAudio.stop(id, function (result) {
          q.resolve(result);
        }, function (err) {
          q.reject(err);
        });
        return q.promise;
      },

      loop: function (id) {
        var q = $q.defer();
        $window.plugins.NativeAudio.loop(id, function (result) {
          q.resolve(result);
        }, function (err) {
          q.reject(err);
        });

        return q.promise;
      },

      unload: function (id) {
        var q = $q.defer();
        $window.plugins.NativeAudio.unload(id, function (result) {
          q.resolve(result);
        }, function (err) {
          q.reject(err);
        });

        return q.promise;
      },

      setVolumeForComplexAsset: function (id, volume) {
        var q = $q.defer();
        $window.plugins.NativeAudio.setVolumeForComplexAsset(id, volume, function (result) {
          q.resolve(result);
        }, function (err) {
          q.reject(err);
        });

        return q.promise;
      }
    };
  }]);
<commit_msg>fix(plugin:nativeAudio): Adding delay parameter to preloadComplex and fixing argument order in play<commit_after>// install   : cordova plugin add https://github.com/sidneys/cordova-plugin-nativeaudio.git
// link      : https://github.com/sidneys/cordova-plugin-nativeaudio

angular.module('ngCordova.plugins.nativeAudio', [])

  .factory('$cordovaNativeAudio', ['$q', '$window', function ($q, $window) {

    return {
      preloadSimple: function (id, assetPath) {
        var q = $q.defer();
        $window.plugins.NativeAudio.preloadSimple(id, assetPath, function (result) {
          q.resolve(result);
        }, function (err) {
          q.reject(err);
        });

        return q.promise;
      },

      preloadComplex: function (id, assetPath, volume, voices, delay) {
        var q = $q.defer();
        $window.plugins.NativeAudio.preloadComplex(id, assetPath, volume, voices, delay, function (result) {
          q.resolve(result);
        }, function (err) {
          q.reject(err);
        });

        return q.promise;
      },

      play: function (id, completeCallback) {
        var q = $q.defer();
        $window.plugins.NativeAudio.play(id, function (result) {
          q.resolve(result);
        }, function (err) {
          q.reject(err);
        }, completeCallback);

        return q.promise;
      },

      stop: function (id) {
        var q = $q.defer();
        $window.plugins.NativeAudio.stop(id, function (result) {
          q.resolve(result);
        }, function (err) {
          q.reject(err);
        });
        return q.promise;
      },

      loop: function (id) {
        var q = $q.defer();
        $window.plugins.NativeAudio.loop(id, function (result) {
          q.resolve(result);
        }, function (err) {
          q.reject(err);
        });

        return q.promise;
      },

      unload: function (id) {
        var q = $q.defer();
        $window.plugins.NativeAudio.unload(id, function (result) {
          q.resolve(result);
        }, function (err) {
          q.reject(err);
        });

        return q.promise;
      },

      setVolumeForComplexAsset: function (id, volume) {
        var q = $q.defer();
        $window.plugins.NativeAudio.setVolumeForComplexAsset(id, volume, function (result) {
          q.resolve(result);
        }, function (err) {
          q.reject(err);
        });

        return q.promise;
      }
    };
  }]);
<|endoftext|>


<commit_before>'use strict'

const mikealRequest = require('request')
const { test } = require('tap')
const url = require('url')
const nock = require('..')
const got = require('./got_client')

require('./cleanup_after_each')()

test('query() matches a query string of the same name=value', t => {
  nock('http://example.test')
    .get('/')
    .query({ foo: 'bar' })
    .reply(200)

  mikealRequest('http://example.test/?foo=bar', function(err, res) {
    if (err) throw err
    t.equal(res.statusCode, 200)
    t.end()
  })
})

test('query() matches multiple query strings of the same name=value', t => {
  nock('http://example.test')
    .get('/')
    .query({ foo: 'bar', baz: 'foz' })
    .reply(200)

  mikealRequest('http://example.test/?foo=bar&baz=foz', function(err, res) {
    if (err) throw err
    t.equal(res.statusCode, 200)
    t.end()
  })
})

test('literal query params have the same behavior as calling query() directly', async t => {
  const scope = nock('http://example.test')
    .get('/foo?bar=baz')
    .reply()

  const { statusCode } = await got('http://example.test/foo?bar=baz')

  t.is(statusCode, 200)
  scope.done()
})

test('query() matches multiple query strings of the same name=value regardless of order', t => {
  nock('http://example.test')
    .get('/')
    .query({ foo: 'bar', baz: 'foz' })
    .reply(200)

  mikealRequest('http://example.test/?baz=foz&foo=bar', function(err, res) {
    if (err) throw err
    t.equal(res.statusCode, 200)
    t.end()
  })
})

test('query() matches query values regardless of their type of declaration', t => {
  nock('http://example.test')
    .get('/')
    .query({ num: 1, bool: true, empty: null, str: 'fou' })
    .reply(200)

  mikealRequest('http://example.test/?num=1&bool=true&empty=&str=fou', function(
    err,
    res
  ) {
    if (err) throw err
    t.equal(res.statusCode, 200)
    t.end()
  })
})

test("query() doesn't match query values of requests without query string", t => {
  nock('http://example.test')
    .get('/')
    .query({ num: 1, bool: true, empty: null, str: 'fou' })
    .reply(200, 'scope1')

  nock('http://example.test')
    .get('/')
    .reply(200, 'scope2')

  mikealRequest('http://example.test', function(err, res) {
    if (err) throw err
    t.equal(res.statusCode, 200)
    t.equal(res.body, 'scope2')
    t.end()
  })
})

test('query() matches a query string using regexp', t => {
  nock('http://example.test')
    .get('/')
    .query({ foo: /.*/ })
    .reply(200)

  mikealRequest('http://example.test/?foo=bar', function(err, res) {
    if (err) throw err
    t.equal(res.statusCode, 200)
    t.end()
  })
})

test('query() accepts URLSearchParams as input', async t => {
  const params = new url.URLSearchParams({
    foo: 'bar',
  })

  const scope = nock('http://example.test')
    .get('/')
    .query(params)
    .reply()

  const { statusCode } = await got('http://example.test?foo=bar')

  t.is(statusCode, 200)
  scope.done()
})

test('query() throws if query params have already been defined', async t => {
  const interceptor = nock('http://example.test').get('/?foo=bar')

  t.throws(
    () => {
      interceptor.query({ foo: 'baz' })
    },
    {
      message: 'Query parameters have already been defined',
    }
  )
})

test('query() throws if query() was already called', async t => {
  const interceptor = nock('http://example.test')
    .get('/')
    .query({ foo: 'bar' })

  t.throws(
    () => {
      interceptor.query({ baz: 'qux' })
    },
    {
      message: 'Query parameters have already been defined',
    }
  )
})

test('query() throws for invalid arguments', t => {
  const interceptor = nock('http://example.test').get('/')

  t.throws(
    () => {
      interceptor.query('foo=bar')
    },
    {
      message: 'Argument Error: foo=bar',
    }
  )
  t.done()
})

test('query() matches a query string that contains special RFC3986 characters', t => {
  nock('http://example.test')
    .get('/')
    .query({ 'foo&bar': 'hello&world' })
    .reply(200)

  const options = {
    uri: 'http://example.test',
    qs: {
      'foo&bar': 'hello&world',
    },
  }

  mikealRequest(options, function(err, res) {
    if (err) throw err
    t.equal(res.statusCode, 200)
    t.end()
  })
})

test('query() expects unencoded query params', t => {
  nock('http://example.test')
    .get('/')
    .query({ foo: 'hello%20world' })
    .reply(200)

  mikealRequest('http://example.test?foo=hello%20world', function(err, res) {
    t.similar(err.toString(), /Error: Nock: No match for request/)
    t.end()
  })
})

test('query() matches a query string with pre-encoded values', t => {
  nock('http://example.test', { encodedQueryParams: true })
    .get('/')
    .query({ foo: 'hello%20world' })
    .reply(200)

  mikealRequest('http://example.test?foo=hello%20world', function(err, res) {
    if (err) throw err
    t.equal(res.statusCode, 200)
    t.end()
  })
})

test('query() with "true" will allow all query strings to pass', t => {
  nock('http://example.test')
    .get('/')
    .query(true)
    .reply(200)

  mikealRequest('http://example.test/?foo=bar&a=1&b=2', function(err, res) {
    if (err) throw err
    t.equal(res.statusCode, 200)
    t.end()
  })
})

test('query() with "{}" will allow a match against ending in ?', t => {
  nock('http://example.test')
    .get('/noquerystring')
    .query({})
    .reply(200)

  mikealRequest('http://example.test/noquerystring?', function(err, res) {
    if (err) throw err
    t.equal(res.statusCode, 200)
    t.end()
  })
})

test('query() with a function, function called with actual queryObject', t => {
  let queryObject

  const queryValidator = function(qs) {
    queryObject = qs
    return true
  }

  nock('http://example.test')
    .get('/')
    .query(queryValidator)
    .reply(200)

  mikealRequest('http://example.test/?foo=bar&a=1&b=2', function(err, res) {
    if (err) throw err
    t.deepEqual(queryObject, { foo: 'bar', a: '1', b: '2' })
    t.equal(res.statusCode, 200)
    t.end()
  })
})

test('query() with a function, function return true the query treat as matched', t => {
  const alwasyTrue = function() {
    return true
  }

  nock('http://example.test')
    .get('/')
    .query(alwasyTrue)
    .reply(200)

  mikealRequest('http://example.test/?igore=the&actual=query', function(
    err,
    res
  ) {
    if (err) throw err
    t.equal(res.statusCode, 200)
    t.end()
  })
})

test('query() with a function, function return false the query treat as Un-matched', t => {
  const alwayFalse = function() {
    return false
  }

  nock('http://example.test')
    .get('/')
    .query(alwayFalse)
    .reply(200)

  mikealRequest('http://example.test/?i=should&pass=?', function(err, res) {
    t.equal(
      err.message.trim(),
      `Nock: No match for request ${JSON.stringify(
        {
          method: 'GET',
          url: 'http://example.test/?i=should&pass=?',
          headers: { host: 'example.test' },
        },
        null,
        2
      )}`
    )
    t.end()
  })
})

test('query() will not match when a query string does not match name=value', t => {
  nock('https://example.test')
    .get('/b')
    .query({ foo: 'bar' })
    .reply(200)

  mikealRequest('https://example.test/b?foo=baz', function(err, res) {
    t.equal(
      err.message.trim(),
      `Nock: No match for request ${JSON.stringify(
        {
          method: 'GET',
          url: 'https://example.test/b?foo=baz',
          headers: { host: 'example.test' },
        },
        null,
        2
      )}`
    )
    t.end()
  })
})

test('query() will not match when a query string is present that was not registered', t => {
  nock('https://example.test')
    .get('/c')
    .query({ foo: 'bar' })
    .reply(200)

  mikealRequest('https://example.test/c?foo=bar&baz=foz', function(err) {
    t.equal(
      err.message.trim(),
      `Nock: No match for request ${JSON.stringify(
        {
          method: 'GET',
          url: 'https://example.test/c?foo=bar&baz=foz',
          headers: { host: 'example.test' },
        },
        null,
        2
      )}`
    )
    t.end()
  })
})

test('query() will not match when a query string is malformed', t => {
  nock('https://example.test')
    .get('/d')
    .query({ foo: 'bar' })
    .reply(200)

  mikealRequest('https://example.test/d?foobar', function(err, res) {
    t.equal(
      err.message.trim(),
      `Nock: No match for request ${JSON.stringify(
        {
          method: 'GET',
          url: 'https://example.test/d?foobar',
          headers: { host: 'example.test' },
        },
        null,
        2
      )}`
    )
    t.end()
  })
})

test('query() will not match when a query string has fewer correct values than expected', t => {
  nock('http://example.test')
    .get('/')
    .query({
      num: 1,
      bool: true,
      empty: null,
      str: 'fou',
    })
    .reply(200)

  mikealRequest('http://example.test/?num=1str=fou', function(err, res) {
    t.equal(
      err.message.trim(),
      `Nock: No match for request ${JSON.stringify(
        {
          method: 'GET',
          url: 'http://example.test/?num=1str=fou',
          headers: { host: 'example.test' },
        },
        null,
        2
      )}`
    )
    t.end()
  })
})

test('query(true) will match when the path has no query', t => {
  nock('http://example.test')
    .get('/')
    .query(true)
    .reply(200)

  mikealRequest('http://example.test', function(err, res) {
    t.ok(!err, 'no error')
    t.ok(res)
    t.equal(res.statusCode, 200)
    t.end()
  })
})

test('query matching should not consider request arrays equal to comma-separated expectations', t => {
  nock('http://example.test')
    .get('/')
    .query({
      foo: 'bar,baz',
    })
    .reply()

  t.rejects(got('http://example.test?foo[]=bar&foo[]=baz'), {
    name: 'RequestError',
    message: 'Nock: No match for request',
  })

  t.done()
})

test('query matching should not consider comma-separated requests equal to array expectations', t => {
  nock('http://example.test')
    .get('/')
    .query({
      foo: ['bar', 'baz'],
    })
    .reply()

  t.rejects(got('http://example.test?foo=bar%2Cbaz'), {
    name: 'RequestError',
    message: 'Nock: No match for request',
  })

  t.done()
})
<commit_msg>refactor: Rewrite test_query using got, async, and chai (#1788)<commit_after>'use strict'

const { test } = require('tap')
const { expect } = require('chai')
const sinon = require('sinon')
const url = require('url')
const nock = require('..')
const got = require('./got_client')
const assertRejects = require('assert-rejects')

require('./cleanup_after_each')()
require('./setup')

test('query() matches a query string of the same name=value', async t => {
  const scope = nock('http://example.test')
    .get('/')
    .query({ foo: 'bar' })
    .reply()

  const { statusCode } = await got('http://example.test/?foo=bar')

  expect(statusCode).to.equal(200)
  scope.done()
})

test('query() matches multiple query strings of the same name=value', async t => {
  const scope = nock('http://example.test')
    .get('/')
    .query({ foo: 'bar', baz: 'foz' })
    .reply()

  const { statusCode } = await got('http://example.test/?foo=bar&baz=foz')

  expect(statusCode).to.equal(200)
  scope.done()
})

test('query() matches multiple query strings of the same name=value regardless of order', async t => {
  const scope = nock('http://example.test')
    .get('/')
    .query({ foo: 'bar', baz: 'foz' })
    .reply()

  const { statusCode } = await got('http://example.test/?baz=foz&foo=bar')

  expect(statusCode).to.equal(200)
  scope.done()
})

test('literal query params have the same behavior as calling query() directly', async t => {
  const scope = nock('http://example.test')
    .get('/foo?bar=baz')
    .reply()

  const { statusCode } = await got('http://example.test/foo?bar=baz')

  expect(statusCode).to.equal(200)
  scope.done()
})

test('query() matches query values regardless of their type of declaration', async t => {
  const scope = nock('http://example.test')
    .get('/')
    .query({ num: 1, bool: true, empty: null, str: 'fou' })
    .reply()

  const { statusCode } = await got(
    'http://example.test/?num=1&bool=true&empty=&str=fou'
  )

  expect(statusCode).to.equal(200)
  scope.done()
})

test("query() doesn't match query values of requests without query string", async t => {
  const scope1 = nock('http://example.test')
    .get('/')
    .query({ num: 1, bool: true, empty: null, str: 'fou' })
    .reply(200, 'scope1')

  const scope2 = nock('http://example.test')
    .get('/')
    .reply(200, 'scope2')

  const { statusCode, body } = await got('http://example.test/')

  expect(statusCode).to.equal(200)
  expect(body).to.equal('scope2')
  scope2.done()
  expect(scope1.isDone()).to.be.false()
})

test('query() matches a query string using regexp', async t => {
  const scope = nock('http://example.test')
    .get('/')
    .query({ foo: /.*/ })
    .reply()

  const { statusCode } = await got('http://example.test/?foo=bar')

  expect(statusCode).to.equal(200)
  scope.done()
})

test('query() accepts URLSearchParams as input', async t => {
  const params = new url.URLSearchParams({ foo: 'bar' })

  const scope = nock('http://example.test')
    .get('/')
    .query(params)
    .reply()

  const { statusCode } = await got('http://example.test?foo=bar')

  expect(statusCode).to.equal(200)
  scope.done()
})

test('query() throws if query params have already been defined', t => {
  const interceptor = nock('http://example.test').get('/?foo=bar')

  expect(() => {
    interceptor.query({ foo: 'baz' })
  }).to.throw(Error, 'Query parameters have already been defined')

  t.done()
})

test('query() throws if query() was already called', t => {
  const interceptor = nock('http://example.test')
    .get('/')
    .query({ foo: 'bar' })

  expect(() => {
    interceptor.query({ baz: 'qux' })
  }).to.throw(Error, 'Query parameters have already been defined')

  t.done()
})

test('query() throws for invalid arguments', t => {
  const interceptor = nock('http://example.test').get('/')

  expect(() => {
    interceptor.query('foo=bar')
  }).to.throw(Error, 'Argument Error: foo=bar')

  t.done()
})

test('query() matches a query string that contains special RFC3986 characters', async t => {
  const scope = nock('http://example.test')
    .get('/')
    .query({ 'foo&bar': 'hello&world' })
    .reply()

  const { statusCode } = await got('http://example.test/', {
    query: { 'foo&bar': 'hello&world' },
  })

  expect(statusCode).to.equal(200)
  scope.done()
})

test('query() expects unencoded query params', async t => {
  const scope = nock('http://example.test')
    .get('/')
    .query({ foo: 'hello%20world' })
    .reply()

  await assertRejects(
    got('http://example.test/?foo=hello%20world'),
    Error,
    'Nock: No match for request'
  )

  const { statusCode } = await got('http://example.test/?foo=hello%2520world')
  expect(statusCode).to.equal(200)
  scope.done()
})

test('query() matches a query string with pre-encoded values', async t => {
  const scope = nock('http://example.test', { encodedQueryParams: true })
    .get('/')
    .query({ foo: 'hello%20world' })
    .reply()

  const { statusCode } = await got('http://example.test/?foo=hello%20world')
  expect(statusCode).to.equal(200)
  scope.done()
})

test('query() with "true" will allow all query strings to pass', async t => {
  const scope = nock('http://example.test')
    .get('/')
    .query(true)
    .reply()

  const { statusCode } = await got('http://example.test/?foo=hello%20world')
  expect(statusCode).to.equal(200)
  scope.done()
})

test('query() with "{}" will allow a match against ending in ?', async t => {
  const scope = nock('http://example.test')
    .get('/noquerystring')
    .query({})
    .reply()

  const { statusCode } = await got('http://example.test/noquerystring?')
  expect(statusCode).to.equal(200)
  scope.done()
})

test('query() with a function, function called with actual queryObject', async t => {
  const queryFn = sinon.stub().returns(true)
  const scope = nock('http://example.test')
    .get('/')
    .query(queryFn)
    .reply()

  const { statusCode } = await got('http://example.test/?foo=bar&a=1&b=2')
  expect(statusCode).to.equal(200)

  expect(queryFn).to.have.been.calledOnceWithExactly({
    foo: 'bar',
    a: '1',
    b: '2',
  })

  scope.done()
})

test('query() with a function, function return true the query treat as matched', async t => {
  const scope = nock('http://example.test')
    .get('/')
    .query(() => true)
    .reply()

  const { statusCode } = await got(
    'http://example.test/?ignore=the&actual=query'
  )
  expect(statusCode).to.equal(200)
  scope.done()
})

test('query() with a function, function return false the query treat as Un-matched', async t => {
  nock('http://example.test')
    .get('/')
    .query(() => false)
    .reply()

  await assertRejects(
    got('http://example.test/?i=should&pass=?'),
    Error,
    'Nock: No match for request'
  )
})

test('query() will not match when a query string does not match name=value', async t => {
  nock('http://example.test')
    .get('/')
    .query({ foo: 'bar' })
    .reply()

  await assertRejects(
    got('http://example.test/?foo=baz'),
    Error,
    'Nock: No match for request'
  )
})

test('query() will not match when a query string is present that was not registered', async t => {
  nock('http://example.test')
    .get('/')
    .query({ foo: 'bar' })
    .reply()

  await assertRejects(
    got('http://example.test/?foo=bar&baz=foz'),
    Error,
    'Nock: No match for request'
  )
})

test('query() will not match when a query string is malformed', async t => {
  // This is a valid query string so it's not really malformed, just not
  // matching. Should this test be removed?
  nock('http://example.test')
    .get('/')
    .query({ foo: 'bar' })
    .reply()

  await assertRejects(
    got('http://example.test/?foobar'),
    Error,
    'Nock: No match for request'
  )
})

test('query() will not match when a query string has fewer correct values than expected', async t => {
  nock('http://example.test')
    .get('/')
    .query({
      num: 1,
      bool: true,
      empty: null,
      str: 'fou',
    })
    .reply()

  await assertRejects(
    got('http://example.test/?num=1str=fou'),
    Error,
    'Nock: No match for request'
  )
})

test('query(true) will match when the path has no query', async t => {
  const scope = nock('http://example.test')
    .get('/')
    .query(true)
    .reply()

  const { statusCode } = await got('http://example.test/')
  expect(statusCode).to.equal(200)
  scope.done()
})

test('query matching should not consider request arrays equal to comma-separated expectations', async t => {
  nock('http://example.test')
    .get('/')
    .query({
      foo: 'bar,baz',
    })
    .reply()

  await assertRejects(
    got('http://example.test?foo[]=bar&foo[]=baz'),
    got.RequestError,
    'Nock: No match for request'
  )
})

test('query matching should not consider comma-separated requests equal to array expectations', async t => {
  nock('http://example.test')
    .get('/')
    .query({
      foo: ['bar', 'baz'],
    })
    .reply()

  await assertRejects(
    got('http://example.test?foo=bar%2Cbaz'),
    got.RequestError,
    'Nock: No match for request'
  )
})
<|endoftext|>


<commit_before>/* @flow */
import isObservable from 'is-observable'
import StyleRule from '../rules/StyleRule'
import createRule from '../utils/createRule'
import type {Observable, Rule, RuleOptions, JssStyle} from '../types'

export default {
  onCreateRule(name: string, decl: JssStyle | Observable<{[string]: string}>, options: RuleOptions) {
    if (isObservable(decl)) {
      const rule = createRule(name, {}, options);

      decl.subscribe(
        (currentProps) => {
          Object.entries(currentProps).forEach(
            ([key, value]) => rule.prop(key, value)
          );
        }
      );

      return rule;
    }
  },

  onProcessRule(rule: Rule) {
    if (!(rule instanceof StyleRule)) return
    const {style} = rule
    for (const prop in style) {
      const value = style[prop]
      if (!isObservable(value)) continue
      value.subscribe({
        next: (nextValue) => {
          // $FlowFixMe
          rule.prop(prop, nextValue)
        }
      })
    }
  }
}
<commit_msg>fix flow types for Observable rule plugin<commit_after>/* @flow */
import isObservable from 'is-observable'
import StyleRule from '../rules/StyleRule'
import createRule from '../utils/createRule'
import type {Observable, Rule, RuleOptions, JssStyle} from '../types'

export default {
  onCreateRule(name: string, decl: JssStyle, options: RuleOptions): Rule | null {
    if (isObservable(decl)) {
      // Cast `decl` to `Observable`, since it passed the type guard
      const props$ = (decl: Observable<{[string]: string}>);

      // We know `rule` is a `StyleRule`, and the other types don't have a
      // `prop` method, so we must explicitly cast to `StyleRule`
      const rule = ((createRule(name, {}, options): any): StyleRule);

      // `stream.subscribe()` returns a subscription, which should be explicitly
      // unsubscribed from when we know this sheet is no longer needed, but I
      // don't see any hooks to do that in the plugin API.  The Observable props
      // implementation doesn't store its subscription either, so this is a TODO
      // for both.
      props$.subscribe(
        (props) => {
          Object.entries(props).forEach(
            // The typing here is gross because `Object.entries` is typed as
            // `[string, mixed]`, even though `props` is `{[string]: string}`
            ([key, value]) => rule.prop(key, ((value: any): string))
          );
        }
      );

      return rule;
    } else {
      return null;
    }
  },

  onProcessRule(rule: Rule) {
    if (!(rule instanceof StyleRule)) return
    const {style} = rule
    for (const prop in style) {
      const value = style[prop]
      if (!isObservable(value)) continue
      value.subscribe({
        next: (nextValue) => {
          // $FlowFixMe
          rule.prop(prop, nextValue)
        }
      })
    }
  }
}
<|endoftext|>


<commit_before>/*global mxConstants */

/*global mxUtils */

/*global graphs */

/*global namespace */

/**
 * Namespace containing methods that help create and manage a graph drawing
 * widget, covering some holes in public interface of mxGraph.
 *
 * @namespace graphs.utils
 */
namespace("graphs.utils");

/**
 * Calculates the angle formed by terminals of an edge.
 *
 * @param {mxGraph} graph A graph.
 * @param {mxCell} edge An edge in graph.
 * @returns {number} Angle in degrees.
 */
graphs.utils.calculateEdgeAngle = function calculateEdgeAngle(graph, edge) {
    "use strict";

    var view = graph.view;
    var sourceState = view.getState(edge).getVisibleTerminalState(true);
    var targetState = view.getState(edge).getVisibleTerminalState(false);
    var dy = targetState.y - sourceState.y;
    var dx = targetState.x - sourceState.x;
    var atan = Math.atan2(dy, dx);
    return mxUtils.toDegree(atan) % 360;
};

/**
 * A less exotic and more straight-forward version of `mxUtils.setStyleFlag`.
 * Changes value of key in an inline style using format defined by mxGraph.
 *
 * @param {string} style An inline style of mxGraph.
 * @param {string} key Key in style.
 * @param {*} value New value of key in style.
 * @returns {string} New inline style with updated key.
 */
graphs.utils.setStyleKey = function setStyleKey(style, key, value) {
    "use strict";

    if (value === true) {
        value = "1";
    } else if (value === false) {
        value = "0";
    }

    if (style === null || style === undefined || style.length === 0) {
        style = key + "=" + value;
    } else {
        var index = style.indexOf(key + "=");

        if (index < 0) {
            var sep = style.charAt(style.length - 1) === ";" ? "" : ";";
            style = style + sep + key + "=" + value;
        } else {
            var cont = style.indexOf(";", index);

            style =
                style.substring(0, index) +
                key +
                "=" +
                value +
                (cont >= 0 ? style.substring(cont) : "");
        }
    }

    return style;
};

/**
 * Removes the given key in an inline style.
 *
 * @param {string} style An inline style of mxGraph.
 * @param {string} key Key in style.
 * @returns {string} New inline style with the key removed.
 */
graphs.utils.removeStyleKey = function removeStyleKey (style, key) {
    "use strict";

    if (style === null || style === undefined || style.length === 0)
    {
        return style;
    }

    var index = style.indexOf(key+'=');

    if (index >= 0)
    {
        var parts = style.split(';')
        for (var i = 0; i < parts.length; ++i) {
          var current = parts[i];
          if (current.split('=')[0] == key) {
              break;
          }
        }
        style = parts.slice(0, i).concat(parts.slice(i+1, parts.length)).join(';');
    }
    return style;
};

/**
 * Obtain decoration style, with most up-to-date rotation.
 *
 * Decorations have their rotation define as a style, as
 * `rotate` method of mxGeometry didn't produce reliable results. Rotation
 * is determined by angle of terminals of parent edge. Not rotations aren't
 * cumulative, a marker updating its rotation r' will replace former rotation r.
 *
 * @param {mxGraph} graph A graph.
 * @param {mxCell} edge Edge that contains decoration.
 * @param {string} baseStyle Inline style to be used as base for decoration.
 * @returns {string} Inline style for a decoration.
 */
graphs.utils.obtainDecorationStyle = function obtainDecorationStyle(graph, edge, baseStyle) {
    "use strict";

    var rotation = graphs.utils.calculateEdgeAngle(graph, edge);

    // Obtain customized base rotation in the element's style
    // TODO: handle multiple names (overrides) in the baseStyle for obtaining desired style
    var styleName = baseStyle.split(";")[0];
    var styleSheet = graph.stylesheet.styles[styleName];

    // + 90 as rotation of objects in mxGraph, or at least when using rotation
    // by style, have 0 degrees concurrent with X axis.
    var baseRotation = mxUtils.getValue(styleSheet, mxConstants.STYLE_DECORATION_BASE_ROTATION, 90);

    rotation = (rotation + baseRotation) % 360;

    // Rotation style must be integers in [0, 360] interval.
    if (rotation < 0) {
        rotation += 360;
    }
    rotation = Math.round(rotation);
    return graphs.utils.setStyleKey(baseStyle, "rotation", rotation);
};

/**
 * Converts from screen coordinates to graph coordinates, taking in account
 * scale and translation of graph.
 *
 * TODO: there may be some method for this in mxGraph, but I couldn't figure it out so far
 *
 * @param {mxGraph} graph A graph.
 * @param {number} x X coordinate in screen coordinates
 * @param {number} y Y coordinate in screen coordinates
 * @returns {{x: number, y: number}} Converted coordinates.
 */
graphs.utils.adjustCoordinates = function adjustCoordinates(graph, x, y) {
    "use strict";

    // Take in account scroll position to convert screen-to-graph-coordinates
    var dx = (window.pageXOffset || document.scrollLeft) - (document.clientLeft || 0);
    if (isNaN(dx)) {
        dx = 0;
    }

    var dy = (window.pageYOffset || document.scrollTop) - (document.clientTop || 0);
    if (isNaN(dy)) {
        dy = 0;
    }

    // Now take in account graph's own translation and scale (changed by
    // use of outline tool, for instance)
    var finalX = (x + dx) / graph.view.scale - graph.view.translate.x;
    var finalY = (y + dy) / graph.view.scale - graph.view.translate.y;

    return { x: finalX, y: finalY };
};

/**
 * Determines it some value is an object not some build-in. Relies on {@link Object#toString}
 * having the default value
 *
 * @param {*} value The value tested.
 * @returns {boolean}
 */
graphs.utils.isObject = function isObject(value) {
    "use strict";
    return Object.prototype.toString.call(value) === "[object Object]";
};

/**
 * Returns the chosen attribute from the given object.
 *
 * @param {Object} object The object containing the selected property.
 * @param {string} attrName The name of the property.
 * @param {*} [defaultValue=undefined] If the chosen property in not present in the given object
 * this value is returned.
 * @returns {*} The property value or `defaultValue`.
 */
graphs.utils.getValue = function getValue(object, attrName, defaultValue) {
    "use strict";
    return attrName in object ? object[attrName] : defaultValue;
};

/**
 * The description of a table contents.
 *
 * @typedef {Object} graphs.utils.TableDescription
 * @property {string} [tag='table'] The html tag used to create the table.
 * @property {graphs.utils.TableRowDescription[]} contents The row that compose the table.
 */

/**
 * The description of a table row contents.
 *
 * @typedef {Object} graphs.utils.TableRowDescription
 * @property {string} [tag='tr'] The html tag used to create the table row. Normal {@link string}
 * elements will be interpreted as {@link graphs.utils.TableDataDescription) elements with all the
 * default values and it's contents equal to a tuple of one element (the {@link string} used).
 * @property {(string|graphs.utils.TableDataDescription)[]} contents The cells that compose the row.
 */

/**
 * The description of a table cell that could span over multiple columns or rows.
 *
 * @typedef {Object} graphs.utils.TableDataDescription
 * @property {string} [tag='td'] The html tag used to create the table cell.
 * @property {(string|graphs.utils.ImageDescription)[]} contents The elements that compose the cells. Plain
 * strings are escaped to properly render in the generated HTML and all the content is concatenated.
 * @property {number} [colspan=1] The number of columns this cell span over.
 * @property {number} [rowspan=1] The number of rows this cell span over (value of 0 means over
 * all remaining table rows).
 */

/**
 * The description of a image.
 *
 * @typedef {Object} graphs.utils.ImageDescription
 * @property {string} tag The html tag used to create the image element. This value must be "img".
 * @property {string} src  The URI of the resource. Special characters can be used an will be
 * properly escaped.
 * @property {number} width The desired width for the image.
 * @property {number} height The desired height for the image.
 */

/**
 * @param {graphs.utils.TableDescription} contents A description of the table contents.
 * @param {string} title Title of table.
 * @returns {string} A HTML table that contains given contents and title.
 */
graphs.utils.createTableElement = function createTableElement(contents, title) {
    "use strict";

    var isObject = graphs.utils.isObject;
    var escapeHtml = graphs.utils.escapeHtml;

    /**
     * @param {string|graphs.utils.TableDataDescription} data
     */
    var createTableData = function createTableDataContents(data) {
        if (!isObject(data)) {
            return "" + escapeHtml(data) + "	";
        }

        var td_defaults = [
            ["colspan", 1],
            ["rowspan", 1],
            ["style", null],
        ];
        var result = "<td";
        for (var i = 0; i < td_defaults.length; ++i) {
            var attr_name = td_defaults[i][0];
            if (data[attr_name] !== td_defaults[i][1]) {
                result += " " + attr_name + '="' + data[attr_name] + '"';
            }
        }
        result += ">";
        var dataContents = data.contents;
        for (var index = 0; index < dataContents.length; ++index) {
            var element = dataContents[index];
            if (isObject(element)) {
                result += '';
            } else {
                result += escapeHtml(element);
            }
        }
        result += "	";
        return result;
    };

    var table = '
';
    table += '
' + title + "
";
    table += "
";
    table +=
        '
' +
        '
';

    var tableContents = contents.contents;
    for (var rowIndex = 0; rowIndex < tableContents.length; ++rowIndex) {
        var rowContents = tableContents[rowIndex].contents;
        table += "
";
        for (var colIndex = 0; colIndex < rowContents.length; ++colIndex) {
            table += createTableData(rowContents[colIndex]);
        }
        table += "
";
    }
    table += "
";
    table += "
";

    return table;
};

/**
 * Replace html "unsafe" characters on a given string.
 * From https://stackoverflow.com/a/4835406/783219
 *
 * @param {string} text The string to be escaped.
 * @returns {string}
 */
graphs.utils.escapeHtml = function escapeHtml(text) {
    "use strict";
    var map = {
        "&": "&",
        "<": "<",
        ">": ">",
        '"': """,
        "'": "'",
    };
    return String(text).replace(/[&<>"']/g, function (m) {
        return map[m];
    });
};
<commit_msg>Fix setStyleKey to avoid overwriting wrong keys (foobar=3;bar=7 called with bar=5 would update foobar instead)<commit_after>/*global mxConstants */

/*global mxUtils */

/*global graphs */

/*global namespace */

/**
 * Namespace containing methods that help create and manage a graph drawing
 * widget, covering some holes in public interface of mxGraph.
 *
 * @namespace graphs.utils
 */
namespace("graphs.utils");

/**
 * Calculates the angle formed by terminals of an edge.
 *
 * @param {mxGraph} graph A graph.
 * @param {mxCell} edge An edge in graph.
 * @returns {number} Angle in degrees.
 */
graphs.utils.calculateEdgeAngle = function calculateEdgeAngle(graph, edge) {
    "use strict";

    var view = graph.view;
    var sourceState = view.getState(edge).getVisibleTerminalState(true);
    var targetState = view.getState(edge).getVisibleTerminalState(false);
    var dy = targetState.y - sourceState.y;
    var dx = targetState.x - sourceState.x;
    var atan = Math.atan2(dy, dx);
    return mxUtils.toDegree(atan) % 360;
};

/**
 * A less exotic and more straight-forward version of `mxUtils.setStyleFlag`.
 * Changes value of key in an inline style using format defined by mxGraph.
 *
 * @param {string} style An inline style of mxGraph.
 * @param {string} key Key in style.
 * @param {*} value New value of key in style.
 * @returns {string} New inline style with updated key.
 */
graphs.utils.setStyleKey = function setStyleKey(style, key, value) {
    "use strict";

    if (value === true) {
        value = "1";
    } else if (value === false) {
        value = "0";
    }

    if (style === null || style === undefined || style.length === 0)
    {
        style = key + '=' + value;
    }
    else
    {
        var index = style.indexOf(key+'=');

        if (index < 0)
        {
            var sep = (style.charAt(style.length-1) === ';') ? '' : ';';
            style = style + sep + key + '=' + value;
        }
        else
        {
            var parts = style.split(';')
            for (var i = 0; i < parts.length; ++i)
            {
                var current = parts[i];
                var current_key = current.split('=')[0];
                if (current_key == key)
                {
                    // Just to find the key index
                    break;
                }
            }

            var updated_key_value = key + '=' + value;
            style = parts.slice(0, i).concat(updated_key_value).concat(parts.slice(i+1, parts.length)).join(';');
        }
    }

    return style;
};

/**
 * Removes the given key in an inline style.
 *
 * @param {string} style An inline style of mxGraph.
 * @param {string} key Key in style.
 * @returns {string} New inline style with the key removed.
 */
graphs.utils.removeStyleKey = function removeStyleKey (style, key) {
    "use strict";

    if (style === null || style === undefined || style.length === 0)
    {
        return style;
    }

    var index = style.indexOf(key+'=');

    if (index >= 0)
    {
        var parts = style.split(';')
        for (var i = 0; i < parts.length; ++i) {
          var current = parts[i];
          if (current.split('=')[0] == key) {
              break;
          }
        }
        style = parts.slice(0, i).concat(parts.slice(i+1, parts.length)).join(';');
    }
    return style;
};

/**
 * Obtain decoration style, with most up-to-date rotation.
 *
 * Decorations have their rotation define as a style, as
 * `rotate` method of mxGeometry didn't produce reliable results. Rotation
 * is determined by angle of terminals of parent edge. Not rotations aren't
 * cumulative, a marker updating its rotation r' will replace former rotation r.
 *
 * @param {mxGraph} graph A graph.
 * @param {mxCell} edge Edge that contains decoration.
 * @param {string} baseStyle Inline style to be used as base for decoration.
 * @returns {string} Inline style for a decoration.
 */
graphs.utils.obtainDecorationStyle = function obtainDecorationStyle(graph, edge, baseStyle) {
    "use strict";

    var rotation = graphs.utils.calculateEdgeAngle(graph, edge);

    // Obtain customized base rotation in the element's style
    // TODO: handle multiple names (overrides) in the baseStyle for obtaining desired style
    var styleName = baseStyle.split(";")[0];
    var styleSheet = graph.stylesheet.styles[styleName];

    // + 90 as rotation of objects in mxGraph, or at least when using rotation
    // by style, have 0 degrees concurrent with X axis.
    var baseRotation = mxUtils.getValue(styleSheet, mxConstants.STYLE_DECORATION_BASE_ROTATION, 90);

    rotation = (rotation + baseRotation) % 360;

    // Rotation style must be integers in [0, 360] interval.
    if (rotation < 0) {
        rotation += 360;
    }
    rotation = Math.round(rotation);
    return graphs.utils.setStyleKey(baseStyle, "rotation", rotation);
};

/**
 * Converts from screen coordinates to graph coordinates, taking in account
 * scale and translation of graph.
 *
 * TODO: there may be some method for this in mxGraph, but I couldn't figure it out so far
 *
 * @param {mxGraph} graph A graph.
 * @param {number} x X coordinate in screen coordinates
 * @param {number} y Y coordinate in screen coordinates
 * @returns {{x: number, y: number}} Converted coordinates.
 */
graphs.utils.adjustCoordinates = function adjustCoordinates(graph, x, y) {
    "use strict";

    // Take in account scroll position to convert screen-to-graph-coordinates
    var dx = (window.pageXOffset || document.scrollLeft) - (document.clientLeft || 0);
    if (isNaN(dx)) {
        dx = 0;
    }

    var dy = (window.pageYOffset || document.scrollTop) - (document.clientTop || 0);
    if (isNaN(dy)) {
        dy = 0;
    }

    // Now take in account graph's own translation and scale (changed by
    // use of outline tool, for instance)
    var finalX = (x + dx) / graph.view.scale - graph.view.translate.x;
    var finalY = (y + dy) / graph.view.scale - graph.view.translate.y;

    return { x: finalX, y: finalY };
};

/**
 * Determines it some value is an object not some build-in. Relies on {@link Object#toString}
 * having the default value
 *
 * @param {*} value The value tested.
 * @returns {boolean}
 */
graphs.utils.isObject = function isObject(value) {
    "use strict";
    return Object.prototype.toString.call(value) === "[object Object]";
};

/**
 * Returns the chosen attribute from the given object.
 *
 * @param {Object} object The object containing the selected property.
 * @param {string} attrName The name of the property.
 * @param {*} [defaultValue=undefined] If the chosen property in not present in the given object
 * this value is returned.
 * @returns {*} The property value or `defaultValue`.
 */
graphs.utils.getValue = function getValue(object, attrName, defaultValue) {
    "use strict";
    return attrName in object ? object[attrName] : defaultValue;
};

/**
 * The description of a table contents.
 *
 * @typedef {Object} graphs.utils.TableDescription
 * @property {string} [tag='table'] The html tag used to create the table.
 * @property {graphs.utils.TableRowDescription[]} contents The row that compose the table.
 */

/**
 * The description of a table row contents.
 *
 * @typedef {Object} graphs.utils.TableRowDescription
 * @property {string} [tag='tr'] The html tag used to create the table row. Normal {@link string}
 * elements will be interpreted as {@link graphs.utils.TableDataDescription) elements with all the
 * default values and it's contents equal to a tuple of one element (the {@link string} used).
 * @property {(string|graphs.utils.TableDataDescription)[]} contents The cells that compose the row.
 */

/**
 * The description of a table cell that could span over multiple columns or rows.
 *
 * @typedef {Object} graphs.utils.TableDataDescription
 * @property {string} [tag='td'] The html tag used to create the table cell.
 * @property {(string|graphs.utils.ImageDescription)[]} contents The elements that compose the cells. Plain
 * strings are escaped to properly render in the generated HTML and all the content is concatenated.
 * @property {number} [colspan=1] The number of columns this cell span over.
 * @property {number} [rowspan=1] The number of rows this cell span over (value of 0 means over
 * all remaining table rows).
 */

/**
 * The description of a image.
 *
 * @typedef {Object} graphs.utils.ImageDescription
 * @property {string} tag The html tag used to create the image element. This value must be "img".
 * @property {string} src  The URI of the resource. Special characters can be used an will be
 * properly escaped.
 * @property {number} width The desired width for the image.
 * @property {number} height The desired height for the image.
 */

/**
 * @param {graphs.utils.TableDescription} contents A description of the table contents.
 * @param {string} title Title of table.
 * @returns {string} A HTML table that contains given contents and title.
 */
graphs.utils.createTableElement = function createTableElement(contents, title) {
    "use strict";

    var isObject = graphs.utils.isObject;
    var escapeHtml = graphs.utils.escapeHtml;

    /**
     * @param {string|graphs.utils.TableDataDescription} data
     */
    var createTableData = function createTableDataContents(data) {
        if (!isObject(data)) {
            return "" + escapeHtml(data) + "	";
        }

        var td_defaults = [
            ["colspan", 1],
            ["rowspan", 1],
            ["style", null],
        ];
        var result = "<td";
        for (var i = 0; i < td_defaults.length; ++i) {
            var attr_name = td_defaults[i][0];
            if (data[attr_name] !== td_defaults[i][1]) {
                result += " " + attr_name + '="' + data[attr_name] + '"';
            }
        }
        result += ">";
        var dataContents = data.contents;
        for (var index = 0; index < dataContents.length; ++index) {
            var element = dataContents[index];
            if (isObject(element)) {
                result += '';
            } else {
                result += escapeHtml(element);
            }
        }
        result += "	";
        return result;
    };

    var table = '
';
    table += '
' + title + "
";
    table += "
";
    table +=
        '
' +
        '
';

    var tableContents = contents.contents;
    for (var rowIndex = 0; rowIndex < tableContents.length; ++rowIndex) {
        var rowContents = tableContents[rowIndex].contents;
        table += "
";
        for (var colIndex = 0; colIndex < rowContents.length; ++colIndex) {
            table += createTableData(rowContents[colIndex]);
        }
        table += "
";
    }
    table += "
";
    table += "
";

    return table;
};

/**
 * Replace html "unsafe" characters on a given string.
 * From https://stackoverflow.com/a/4835406/783219
 *
 * @param {string} text The string to be escaped.
 * @returns {string}
 */
graphs.utils.escapeHtml = function escapeHtml(text) {
    "use strict";
    var map = {
        "&": "&",
        "<": "<",
        ">": ">",
        '"': """,
        "'": "'",
    };
    return String(text).replace(/[&<>"']/g, function (m) {
        return map[m];
    });
};
<|endoftext|>