<commit_before>#!/usr/bin/env node

var airplay = require('airplay-js')
var chromecast = require('chromecast-js')
var clivas = require('clivas')
var cp = require('child_process')
var fs = require('fs')
var minimist = require('minimist')
var moment = require('moment')
var networkAddress = require('network-address')
var path = require('path')
var prettysize = require('prettysize')
var WebTorrent = require('../')
var xbmc = require('nodebmc')

process.title = 'WebTorrent'

process.on('exit', function (code) {
  if (code !== 0) {
    clivas.line('{red:ERROR:} If you think this is a bug in webtorrent, report it!')
    console.log('=====>                                               <=====')
    console.log('=====>  https://github.com/feross/webtorrent/issues  <=====')
    console.log('=====>                                               <=====')
  }
})

var argv = minimist(process.argv.slice(2), {
  alias: {
    p: 'port',
    b: 'blocklist',
    t: 'subtitles',
    l: 'list',
    n: 'no-quit',
    r: 'remove',
    q: 'quiet',
    h: 'help',
    v: 'version'
  },
  boolean: [ // options that are always boolean
    'vlc',
    'mplayer',
    'mpv',
    'airplay',
    'chromecast',
    'xbmc',
    'list',
    'no-quit',
    'remove',
    'quiet',
    'help',
    'version'
  ],
  default: {
    port: 9000
  }
})

if (argv.version) {
  console.log(require('../package.json').version)
  process.exit(0)
}

var torrentId = argv._[0]

if (argv.help || !torrentId) {
  fs.readFileSync(path.join(__dirname, 'ascii-logo.txt'), 'utf8')
    .split('\n')
    .forEach(function (line) {
      clivas.line('{bold:' + line.substring(0, 20) + '}{red:' + line.substring(20) + '}')
    })

  console.log(function () {/*
  Usage:
      webtorrent <options> <torrent>

      Download the torrent, given as:
          * magnet uri
          * http url to .torrent file
          * filesystem path to .torrent file
          * info hash (hex string)

  Streaming options:
      --airplay               stream to Apple TV (AirPlay)
      --chromecast            stream to Chromecast
      --mplayer               stream to MPlayer
      --mpv                   stream to MPV
      --omx [jack]            stream to omx (jack=local|hdmi)
      --vlc                   stream to VLC
      --xbmc                  stream to XBMC

  Options:
      -p, --port [number]     change the http port [default: 9000]
      -b, --blocklist [path]  use the specified blocklist
      -t, --subtitles [file]  load subtitles file
      -l, --list              list available files in torrent
      -n, --no-quit           do not quit webtorrent on vlc exit
      -r, --remove            remove downloaded files on exit
      -q, --quiet             silence stdout
      -h, --help              display this help message
      -v, --version           print the current version

  Please report bugs!  https://github.com/feross/webtorrent/issues

    */}.toString().split(/\n/).slice(1, -1).join('\n'))
  process.exit(0)
}

if (process.env.DEBUG) {
  argv.quiet = argv.q = true
}

var VLC_ARGS = process.env.DEBUG
  ? '-q --play-and-exit'
  : '--play-and-exit --extraintf=http:logger --verbose=2 --file-logging --logfile=vlc-log.txt'
var MPLAYER_EXEC = 'mplayer -ontop -really-quiet -noidx -loop 0'
var MPV_EXEC = 'mpv --ontop --really-quiet --loop=no'
var OMX_EXEC = 'omxplayer -r -o ' + (typeof argv.omx === 'string')
  ? argv.omx
  : 'hdmi'

if (argv.subtitles) {
  VLC_ARGS += ' --sub-file=' + argv.subtitles
  MPLAYER_EXEC += ' -sub ' + argv.subtitles
  MPV_EXEC += ' --sub-file=' + argv.subtitles
  OMX_EXEC += ' --subtitles ' + argv.subtitles
}

function error (err) {
  clivas.line('{red:ERROR:} ' + (err.message || err))
}

function errorAndExit (err) {
  error(err)
  process.exit(1)
}

var started = Date.now()
function getRuntime () {
  return Math.floor((Date.now() - started) / 1000)
}

var client = new WebTorrent({
  list: argv.list,
  blocklist: argv.blocklist,
  port: argv.port
})
.on('error', errorAndExit)

if (argv.remove) {
  process.on('SIGINT', remove)
  process.on('SIGTERM', remove)
}

function remove (cb) {
  process.removeListener('SIGINT', remove)
  process.removeListener('SIGTERM', remove)
  client.destroy(cb)
}

var torrent = client.add(torrentId)

torrent.on('infoHash', function () {
  function updateMetadata () {
    var numPeers = torrent.swarm.numPeers
    clivas.clear()
    clivas.line('{green:fetching torrent metadata from} {bold:'+numPeers+'} {green:peers}')
  }

  if (!argv.quiet && !argv.list) {
    torrent.swarm.on('wire', updateMetadata)
    torrent.on('metadata', function () {
      torrent.swarm.removeListener('wire', updateMetadata)
    })
    updateMetadata()
  }
})

client.on('torrent', function (torrent) {
  if (client.listening) onTorrent(torrent)
  else client.on('listening', onTorrent)
})

var filename, swarm, wires

function onTorrent (torrent) {
  filename = torrent.name
  swarm = torrent.swarm
  wires = torrent.swarm.wires

  torrent.on('verifying', function (data) {
    if (argv.quiet || argv.list) return
    clivas.clear()
    clivas.line(
      '{green:verifying existing torrent} {bold:'+Math.floor(data.percentDone)+'%} ' +
      '({bold:'+Math.floor(data.percentVerified)+'%} {green:passed verification})'
    )
  })

  torrent.on('done', function () {
    if (argv.list) return

    if (!argv.quiet) {
      // TODO: expose this data from bittorrent-swarm
      var numActiveWires = torrent.swarm.wires.reduce(function (num, wire) {
        return num + (wire.downloaded > 0)
      }, 0)
      clivas.line('torrent downloaded {green:successfully} from {bold:'+numActiveWires+'/'+torrent.swarm.wires.length+'} {green:peers} in {bold:'+getRuntime()+'s}!')
    }

    if (argv.remove) {
      remove(maybeExit)
    } else {
      maybeExit()
    }

    function maybeExit () {
      if (!client.server) {
        process.exit(0)
      }
    }
  })

  if (argv.list) {
    torrent.files.forEach(function (file, i) {
      clivas.line('{3+bold:' + i + '} : {magenta:' + file.name + '}')
    })
    process.exit(0)
  }

  var href
  if (client.server) {
    href = 'http://' + networkAddress() + ':' + client.server.address().port + '/'
  }

  var cmd, player
  var playerName = argv.airplay ? 'Airplay'
    : argv.chromecast ? 'Chromecast'
    : argv.xbmc ? 'XBMC'
    : argv.vlc ? 'VLC'
    : argv.mplayer ? 'MPlayer'
    : argv.mpv ? 'mpv'
    : argv.omx ? 'OMXPlayer'
    : null

  if (argv.vlc && process.platform === 'win32') {
    var registry = require('windows-no-runnable').registry
    var key
    if (process.arch === 'x64') {
      try {
        key = registry('HKLM/Software/Wow6432Node/VideoLAN/VLC')
      } catch (e) {}
    } else {
      try {
        key = registry('HKLM/Software/VideoLAN/VLC')
      } catch (err) {}
    }

    if (key) {
      var vlcPath = key.InstallDir.value + path.sep + 'vlc'
      VLC_ARGS = VLC_ARGS.split(' ')
      VLC_ARGS.unshift(href)
      cp.execFile(vlcPath, VLC_ARGS, errorAndExit)
    }
  } else if (argv.vlc) {
    var root = '/Applications/VLC.app/Contents/MacOS/VLC'
    var home = (process.env.HOME || '') + root
    cmd = 'vlc ' + href + ' ' + VLC_ARGS + ' || ' +
      root + ' ' + href + ' ' + VLC_ARGS + ' || ' +
      home + ' ' + href + ' ' + VLC_ARGS
  } else if (argv.mplayer) {
    cmd = MPLAYER_EXEC + ' ' + href
  } else if (argv.mpv) {
    cmd = MPV_EXEC + ' ' + href
  } else if (argv.omx) {
    cmd = OMX_EXEC + ' ' + href
  }

  if (cmd) {
    player = cp.exec(cmd, errorAndExit)
      .on('exit', function () {
        if (!argv['no-quit']) process.exit(0)
      })
  }

  if (argv.airplay) {
    airplay.createBrowser()
      .on('deviceOn', function (device) {
        device.play(href, 0, function () {})
      })
      .start()
    // TODO: handle case where user closes airplay. do same thing as when VLC is closed
  }

  if (argv.chromecast) {
    ;(new chromecast.Browser())
      .on('deviceOn', function (device) {
        device.connect()
        device.on('connected', function () {
          device.play(href)
        })
      })
  }

  if (argv.xbmc) {
    ;(new xbmc.Browser())
      .on('deviceOn', function (device) {
          device.play(href, function () {})
      })
  }

  var hotswaps = 0
  torrent.on('hotswap', function () {
    hotswaps += 1
  })

  if (!argv.quiet) {
    process.stdout.write(new Buffer('G1tIG1sySg==', 'base64')) // clear for drawing

    setInterval(draw, 500)
  }

  function active (wire) {
    return !wire.peerChoking
  }

  function bytes (num) {
    return prettysize(num)
  }

  function draw () {
    var unchoked = wires.filter(active)
    var linesremaining = clivas.height
    var peerslisted = 0
    var speed = swarm.downloadSpeed()
    var estimatedSecondsRemaining = Math.max(0, torrent.length - swarm.downloaded) / (speed > 0 ? speed : -1)
    var estimate = moment.duration(estimatedSecondsRemaining, 'seconds').humanize()

    clivas.clear()

    if (playerName)
      clivas.line('{green:Streaming to} {bold:' + playerName + '}')
    if (client.server)
      clivas.line('{green:server running at} {bold:' + href + '}')

    clivas.line('')
    clivas.line('{green:downloading:} {bold:' + filename + '}')
    clivas.line(
      '{green:speed: }{bold:' + bytes(speed) + '/s}  ' +
      '{green:downloaded:} {bold:' + bytes(swarm.downloaded) + '}' +
      '/{bold:' + bytes(torrent.length) + '}  ' +
      '{green:uploaded:} {bold:' + bytes(swarm.uploaded) + '}  ' +
      '{green:peers:} {bold:' + unchoked.length + '/' + wires.length + '}  ' +
      '{green:hotswaps:} {bold:' + hotswaps + '}'
    )
    clivas.line(
      '{green:time remaining:} {bold:' + estimate + ' remaining}  ' +
      '{green:total time:} {bold:' + getRuntime() + 's}  ' +
      '{green:queued peers:} {bold:' + swarm.numQueued + '}  ' +
      '{green:blocked:} {bold:' + torrent.numBlockedPeers + '}'
    )
    clivas.line('{80:}')
    linesremaining -= 8

    wires.every(function (wire) {
      var tags = []
      if (wire.peerChoking) tags.push('choked')
      clivas.line(
        '{25+magenta:' + wire.remoteAddress + '} {10:'+bytes(wire.downloaded)+'} ' +
        '{10+cyan:' + bytes(wire.downloadSpeed()) + '/s} ' +
        '{15+grey:' + tags.join(', ') + '}'
      )
      peerslisted++
      return linesremaining - peerslisted > 4
    })
    linesremaining -= peerslisted

    if (wires.length > peerslisted) {
      clivas.line('{80:}')
      clivas.line('... and '+(wires.length - peerslisted)+' more')
    }

    clivas.line('{80:}')
    clivas.flush(true)
  }
}
<commit_msg>fix --list option (#95)<commit_after>#!/usr/bin/env node

var airplay = require('airplay-js')
var chromecast = require('chromecast-js')
var clivas = require('clivas')
var cp = require('child_process')
var fs = require('fs')
var minimist = require('minimist')
var moment = require('moment')
var networkAddress = require('network-address')
var path = require('path')
var prettysize = require('prettysize')
var WebTorrent = require('../')
var xbmc = require('nodebmc')

process.title = 'WebTorrent'

process.on('exit', function (code) {
  if (code !== 0) {
    clivas.line('{red:ERROR:} If you think this is a bug in webtorrent, report it!')
    console.log('=====>                                               <=====')
    console.log('=====>  https://github.com/feross/webtorrent/issues  <=====')
    console.log('=====>                                               <=====')
  }
})

var argv = minimist(process.argv.slice(2), {
  alias: {
    p: 'port',
    b: 'blocklist',
    t: 'subtitles',
    l: 'list',
    n: 'no-quit',
    r: 'remove',
    q: 'quiet',
    h: 'help',
    v: 'version'
  },
  boolean: [ // options that are always boolean
    'vlc',
    'mplayer',
    'mpv',
    'airplay',
    'chromecast',
    'xbmc',
    'list',
    'no-quit',
    'remove',
    'quiet',
    'help',
    'version'
  ],
  default: {
    port: 9000
  }
})

if (argv.version) {
  console.log(require('../package.json').version)
  process.exit(0)
}

var torrentId = argv._[0]

if (argv.help || !torrentId) {
  fs.readFileSync(path.join(__dirname, 'ascii-logo.txt'), 'utf8')
    .split('\n')
    .forEach(function (line) {
      clivas.line('{bold:' + line.substring(0, 20) + '}{red:' + line.substring(20) + '}')
    })

  console.log(function () {/*
  Usage:
      webtorrent <options> <torrent>

      Download the torrent, given as:
          * magnet uri
          * http url to .torrent file
          * filesystem path to .torrent file
          * info hash (hex string)

  Streaming options:
      --airplay               stream to Apple TV (AirPlay)
      --chromecast            stream to Chromecast
      --mplayer               stream to MPlayer
      --mpv                   stream to MPV
      --omx [jack]            stream to omx (jack=local|hdmi)
      --vlc                   stream to VLC
      --xbmc                  stream to XBMC

  Options:
      -p, --port [number]     change the http port [default: 9000]
      -b, --blocklist [path]  use the specified blocklist
      -t, --subtitles [file]  load subtitles file
      -l, --list              list available files in torrent
      -n, --no-quit           do not quit webtorrent on vlc exit
      -r, --remove            remove downloaded files on exit
      -q, --quiet             silence stdout
      -h, --help              display this help message
      -v, --version           print the current version

  Please report bugs!  https://github.com/feross/webtorrent/issues

    */}.toString().split(/\n/).slice(1, -1).join('\n'))
  process.exit(0)
}

if (process.env.DEBUG) {
  argv.quiet = argv.q = true
}

var VLC_ARGS = process.env.DEBUG
  ? '-q --play-and-exit'
  : '--play-and-exit --extraintf=http:logger --verbose=2 --file-logging --logfile=vlc-log.txt'
var MPLAYER_EXEC = 'mplayer -ontop -really-quiet -noidx -loop 0'
var MPV_EXEC = 'mpv --ontop --really-quiet --loop=no'
var OMX_EXEC = 'omxplayer -r -o ' + (typeof argv.omx === 'string')
  ? argv.omx
  : 'hdmi'

if (argv.subtitles) {
  VLC_ARGS += ' --sub-file=' + argv.subtitles
  MPLAYER_EXEC += ' -sub ' + argv.subtitles
  MPV_EXEC += ' --sub-file=' + argv.subtitles
  OMX_EXEC += ' --subtitles ' + argv.subtitles
}

function error (err) {
  clivas.line('{red:ERROR:} ' + (err.message || err))
}

function errorAndExit (err) {
  error(err)
  process.exit(1)
}

var started = Date.now()
function getRuntime () {
  return Math.floor((Date.now() - started) / 1000)
}

var client = new WebTorrent({
  blocklist: argv.blocklist,
  port: !argv.list && argv.port
})
.on('error', errorAndExit)

if (argv.remove) {
  process.on('SIGINT', remove)
  process.on('SIGTERM', remove)
}

function remove (cb) {
  process.removeListener('SIGINT', remove)
  process.removeListener('SIGTERM', remove)
  client.destroy(cb)
}

var torrent = client.add(torrentId)

torrent.on('infoHash', function () {
  function updateMetadata () {
    var numPeers = torrent.swarm.numPeers
    clivas.clear()
    clivas.line('{green:fetching torrent metadata from} {bold:'+numPeers+'} {green:peers}')
  }

  if (!argv.quiet && !argv.list) {
    torrent.swarm.on('wire', updateMetadata)
    torrent.on('metadata', function () {
      torrent.swarm.removeListener('wire', updateMetadata)
    })
    updateMetadata()
  }
})

torrent.on('ready', function () {
  if (client.listening || argv.list) onTorrent(torrent)
  else client.on('listening', onTorrent)
})

var filename, swarm, wires

function onTorrent (torrent) {
  filename = torrent.name
  swarm = torrent.swarm
  wires = torrent.swarm.wires

  if (argv.list) {
    torrent.files.forEach(function (file, i) {
      clivas.line('{3+bold:' + i + '} : {magenta:' + file.name + '}')
    })
    process.exit(0)
  }

  torrent.on('verifying', function (data) {
    if (argv.quiet) return
    clivas.clear()
    clivas.line(
      '{green:verifying existing torrent} {bold:'+Math.floor(data.percentDone)+'%} ' +
      '({bold:'+Math.floor(data.percentVerified)+'%} {green:passed verification})'
    )
  })

  torrent.on('done', function () {
    if (!argv.quiet) {
      // TODO: expose this data from bittorrent-swarm
      var numActiveWires = torrent.swarm.wires.reduce(function (num, wire) {
        return num + (wire.downloaded > 0)
      }, 0)
      clivas.line('torrent downloaded {green:successfully} from {bold:'+numActiveWires+'/'+torrent.swarm.wires.length+'} {green:peers} in {bold:'+getRuntime()+'s}!')
    }

    if (argv.remove) {
      remove(maybeExit)
    } else {
      maybeExit()
    }

    function maybeExit () {
      if (!client.server) {
        process.exit(0)
      }
    }
  })

  var href
  if (client.server) {
    href = 'http://' + networkAddress() + ':' + client.server.address().port + '/'
  }

  var cmd, player
  var playerName = argv.airplay ? 'Airplay'
    : argv.chromecast ? 'Chromecast'
    : argv.xbmc ? 'XBMC'
    : argv.vlc ? 'VLC'
    : argv.mplayer ? 'MPlayer'
    : argv.mpv ? 'mpv'
    : argv.omx ? 'OMXPlayer'
    : null

  if (argv.vlc && process.platform === 'win32') {
    var registry = require('windows-no-runnable').registry
    var key
    if (process.arch === 'x64') {
      try {
        key = registry('HKLM/Software/Wow6432Node/VideoLAN/VLC')
      } catch (e) {}
    } else {
      try {
        key = registry('HKLM/Software/VideoLAN/VLC')
      } catch (err) {}
    }

    if (key) {
      var vlcPath = key.InstallDir.value + path.sep + 'vlc'
      VLC_ARGS = VLC_ARGS.split(' ')
      VLC_ARGS.unshift(href)
      cp.execFile(vlcPath, VLC_ARGS, errorAndExit)
    }
  } else if (argv.vlc) {
    var root = '/Applications/VLC.app/Contents/MacOS/VLC'
    var home = (process.env.HOME || '') + root
    cmd = 'vlc ' + href + ' ' + VLC_ARGS + ' || ' +
      root + ' ' + href + ' ' + VLC_ARGS + ' || ' +
      home + ' ' + href + ' ' + VLC_ARGS
  } else if (argv.mplayer) {
    cmd = MPLAYER_EXEC + ' ' + href
  } else if (argv.mpv) {
    cmd = MPV_EXEC + ' ' + href
  } else if (argv.omx) {
    cmd = OMX_EXEC + ' ' + href
  }

  if (cmd) {
    player = cp.exec(cmd, errorAndExit)
      .on('exit', function () {
        if (!argv['no-quit']) process.exit(0)
      })
  }

  if (argv.airplay) {
    airplay.createBrowser()
      .on('deviceOn', function (device) {
        device.play(href, 0, function () {})
      })
      .start()
    // TODO: handle case where user closes airplay. do same thing as when VLC is closed
  }

  if (argv.chromecast) {
    ;(new chromecast.Browser())
      .on('deviceOn', function (device) {
        device.connect()
        device.on('connected', function () {
          device.play(href)
        })
      })
  }

  if (argv.xbmc) {
    ;(new xbmc.Browser())
      .on('deviceOn', function (device) {
          device.play(href, function () {})
      })
  }

  var hotswaps = 0
  torrent.on('hotswap', function () {
    hotswaps += 1
  })

  if (!argv.quiet) {
    process.stdout.write(new Buffer('G1tIG1sySg==', 'base64')) // clear for drawing

    setInterval(draw, 500)
  }

  function active (wire) {
    return !wire.peerChoking
  }

  function bytes (num) {
    return prettysize(num)
  }

  function draw () {
    var unchoked = wires.filter(active)
    var linesremaining = clivas.height
    var peerslisted = 0
    var speed = swarm.downloadSpeed()
    var estimatedSecondsRemaining = Math.max(0, torrent.length - swarm.downloaded) / (speed > 0 ? speed : -1)
    var estimate = moment.duration(estimatedSecondsRemaining, 'seconds').humanize()

    clivas.clear()

    if (playerName)
      clivas.line('{green:Streaming to} {bold:' + playerName + '}')
    if (client.server)
      clivas.line('{green:server running at} {bold:' + href + '}')

    clivas.line('')
    clivas.line('{green:downloading:} {bold:' + filename + '}')
    clivas.line(
      '{green:speed: }{bold:' + bytes(speed) + '/s}  ' +
      '{green:downloaded:} {bold:' + bytes(swarm.downloaded) + '}' +
      '/{bold:' + bytes(torrent.length) + '}  ' +
      '{green:uploaded:} {bold:' + bytes(swarm.uploaded) + '}  ' +
      '{green:peers:} {bold:' + unchoked.length + '/' + wires.length + '}  ' +
      '{green:hotswaps:} {bold:' + hotswaps + '}'
    )
    clivas.line(
      '{green:time remaining:} {bold:' + estimate + ' remaining}  ' +
      '{green:total time:} {bold:' + getRuntime() + 's}  ' +
      '{green:queued peers:} {bold:' + swarm.numQueued + '}  ' +
      '{green:blocked:} {bold:' + torrent.numBlockedPeers + '}'
    )
    clivas.line('{80:}')
    linesremaining -= 8

    wires.every(function (wire) {
      var tags = []
      if (wire.peerChoking) tags.push('choked')
      clivas.line(
        '{25+magenta:' + wire.remoteAddress + '} {10:'+bytes(wire.downloaded)+'} ' +
        '{10+cyan:' + bytes(wire.downloadSpeed()) + '/s} ' +
        '{15+grey:' + tags.join(', ') + '}'
      )
      peerslisted++
      return linesremaining - peerslisted > 4
    })
    linesremaining -= peerslisted

    if (wires.length > peerslisted) {
      clivas.line('{80:}')
      clivas.line('... and '+(wires.length - peerslisted)+' more')
    }

    clivas.line('{80:}')
    clivas.flush(true)
  }
}
<|endoftext|>


<commit_before>exports.serve = function(userArgs) {
  parseFile(userArgs[0], function(err, data) {
    if (err) throw err;

    server = require('./server.js');
    server.run(data);
  });
};

exports.build = function(userArgs) {
  parseFile(userArgs[0], function(err, data) {
    if (err) throw err;

    var fs = require('fs');
    fs.writeFile('./concatr.html', data, function(err) {
      if (err) throw err;
    });
  });
}

function parseFile(filename, cb) {
  if (filename === undefined) {
    cb("No filename specified", null);
  } else {
    var fs = require('fs');
    fs.readFile(filename, cb);
  }
}
<commit_msg>Parse include statements<commit_after>exports.serve = function(userArgs) {
  parseFile(userArgs[0], function(err, data) {
    if (err) throw err;

    server = require('./server.js');
    server.run(data);
  });
};

exports.build = function(userArgs) {
  parseFile(userArgs[0], function(err, data) {
    if (err) throw err;

    var fs = require('fs');
    fs.writeFile('./concatr.html', data, function(err) {
      if (err) throw err;
    });
  });
}

function parseFile(filename, cb) {
  if (filename === undefined) {
    cb("No filename specified", null);
  } else {
    var fs = require('fs');
    fs.readFile(filename, function(err, data) {
      if (err) cb(err);

      var lines = data.toString().split("\n");
      for (var i=0;i<lines.length;i++) {
        var re = /@include\(([A-Za-z0-9\. \/]+)\)/g;
        lines[i] = lines[i].replace(re, function(match, p, offset, string) {
          return "[" + p + "]";
        });
      }
      var newData = lines.join("\n");
      cb(err, newData);
    });
  }
}
<|endoftext|>


<commit_before>//var clock = new THREE.Clock();

//var container, stats;

var camera, cameraTarget, scene, renderer, controls;

init();
animate();

function init() {
    //define a few colors
    var colWhite = new THREE.Color("rgb(100%, 100%, 100%)");
    var colMetal = new THREE.Color("rgb(70%, 70%, 70%)");
    var colConcrete = new THREE.Color("rgb(30%, 30%, 30%)");

    //make materials
    var matConcrete = new THREE.MeshPhongMaterial( { color: colConcrete , specular: 0x111111, shininess: 50 } );
    var matAluminium = new THREE.MeshPhongMaterial( { color: colMetal , specular: 0x111111, shininess: 200 } );
    var matMelamine = new THREE.MeshPhongMaterial( { color: colWhite , specular: 0x111111, shininess: 100 } );

    //dimensions
    //main base
    var basL = 1900;
    var basW = 1000;
    var basH = 18;

    //x carriage angle
    var xCAL = 300;
    var xCAW = 76.2;
    var xCAH = 101.6;
    var xCAT = 6.35;

    //side bed (which the xRails and x ballscrew are seated on
    var sideBedL = basL;
    var sideBedW = 75;
    var sideBedH = 15;
    var sideBedO = 0;(xCAW - xCAT); //amount the sideBed overhangs the sides of the base by. Assumes inset by inner width of xCarAngl - for easy measuring

    //x rail
    var xRL = 1900;
    var xRD = 20;

    //x rail angle
    var xRAL = xRL;
    var xRAW = 50.8;
    var xRAH = 63.5;
    var xRAT = 6.35;

    //x ballscrew
    var xBSD = 20;
    var xBSL = 1900;

    //Gantry side
    var gSL = 300; //gantry side length
    var gSX = 100; //x-location of the gantry

    //y rail
    var yRL = 1004;
    var yRD = 16;

    //y ballscrew
    var yBSD = 16;
    var yBSL = 1000;

    //html container div - to house the WebGL content
    //already made in index.html... an alternative would be to make on the fly here
    var container = document.getElementById("container");

    //renderer
    renderer = new THREE.WebGLRenderer( { antialias: true } );
    renderer.setSize(window.innerWidth, window.innerHeight);
    container.appendChild( renderer.domElement );

    //create scene (global scope)
    scene = new THREE.Scene();
    scene.background = colWhite ;//new THREE.Color( 0xffffff );
    scene.add(new THREE.AxisHelper(3000)); //axis helper

    //create camera (global scope)
    //and add to scene
    camera = new THREE.PerspectiveCamera( 45, container.offsetWidth / container.offsetHeight, 1, 10000 );
    camera.position.y = -1500;
    //camera.lookAt(new THREE.Vector3(0,0,0));
    //camera.position.z = 200;
    scene.add( camera );

    //add TrackBall controls to the camera
    controls = new THREE.TrackballControls( camera);
    controls.position0.set( -200, -1500, 400 ); // set a new desired position
    controls.target0.set(0,0,100);
    controls.up0.set( 0, 0, 1 ); // set a new up vector
    controls.reset();
    controls.rotateSpeed = 10.0;
    controls.zoomSpeed = 1.2;
    controls.panSpeed = 1;
    controls.noZoom = false;
    controls.noPan = false;
    controls.staticMoving = false;
    controls.dynamicDampingFactor = 0.3;
    controls.minDistance = 1.1;
    controls.maxDistance = 10000;
    controls.keys = [ 16, 17, 18 ]; // [ rotateKey, zoomKey, panKey ]

    //create light(s)
    var dirLight = new THREE.DirectionalLight(colWhite , 0.95);
    dirLight.position.set(-200, -1000, 1000);
    dirLight.position.normalize();
    scene.add(dirLight);

    var pointLight = new THREE.PointLight(colWhite , 5, 50);
    pointLight.position.set(10, 20, -10);
    scene.add(pointLight);

    //Make part objects (from shop.js)
    var baseObj = new shopSheet(basL,basW,basH);
    var sideBedObj = new shopSheet(sideBedL,sideBedW,sideBedH);
    var xRailAngObj = new shopAluAngle(xRAW,xRAH,xRAT,xRAL);
    var xRailObj = new shopSbrxx(xRL,xRD);
    var xLinBearObj = new shopSbrxxuu(xRD);
    var xBScrwObj = new shopRmxx05(xBSD, xBSL);
    var xBScrwFixSuppObj = new shopBkxx(xBSD);
    var xBScrwFltSuppObj = new shopBfxx(xBSD);
    var xBnutObj = new shopBallnut(xBSD);
    var xCarAngObj = new shopAluAngle(xCAW,xCAH,xCAT,xCAL);
    var yRailObj = new shopSbrxx(yRL,yRD);

    //make CSGs, and where applicable copies, to be merged into a single geometry
    var baseCsg = baseObj.makeCsg();
        baseCsg = baseCsg.center("y");
//     var sideBedCsg = sideBedObj.makeCsg();
//         sideBedCsg = sideBedCsg.union(sideBedCsg.translate([0,baseObj.width - sideBedObj.width + 2*sideBedO,0])).center("y");
//         sideBedCsg = sideBedCsg.union(sideBedCsg.translate([0,0,-baseObj.thickness - sideBedObj.thickness]));
    var xRailAngCsg = xRailAngObj.makeCsg();
        xRailAngCsg = xRailAngCsg.mirroredY().mirroredZ().translate([0,xRailAngObj.width,0]);
        xRailAngCsg = xRailAngCsg.union(xRailAngCsg.mirroredY().translate([0,baseObj.width,0])).center("y");
    var xRailCsg = xRailObj.makeCsg();
        xRailCsg = xRailCsg.rotateX(90).union(xRailCsg.rotateX(-90).translate([0,baseObj.width - 2*xRailAngObj.inWidth,0])).center("y"); //outside of linear bearings set equal to yRail length
    var xLinBearCsg = xLinBearObj.makeCsg();
        xLinBearCsg = xLinBearCsg.rotateX(90).union(xLinBearCsg.rotateX(90).translate([gSL - xLinBearObj.length,0,0]));
        xLinBearCsg = xLinBearCsg.union(xLinBearCsg.rotateX(180).translate([0,baseObj.width - 2*xRailAngObj.inWidth +2*(xRailObj.railZPos - xLinBearObj.railZPos),0])).center("y");
//     var xCarAngCsg = xCarAngObj.makeCsg();
//         xCarAngCsg = xCarAngCsg.union(xCarAngCsg.mirroredY().translate([0,baseObj.width + 2*xCAT,0])).center("y");
    var xBScrwFixSuppCsg = xBScrwFixSuppObj.makeCsg();
        xBScrwFixSuppCsg = xBScrwFixSuppCsg.union(xBScrwFixSuppCsg.translate([0,baseObj.width  - 2*xRailAngObj.width - xBScrwFixSuppObj.width,0])).center("y").mirroredZ().mirroredX();
    var xBScrwFltSuppCsg = xBScrwFltSuppObj.makeCsg();
        xBScrwFltSuppCsg = xBScrwFltSuppCsg.union(xBScrwFltSuppCsg.translate([0,baseObj.width  - 2*xRailAngObj.width - xBScrwFixSuppObj.width,0])).center("y").mirroredZ();
    var xBScrwCsg = xBScrwObj.makeCsg();
        xBScrwCsg = xBScrwCsg.union(xBScrwCsg.translate([0,baseObj.width  - 2*xRailAngObj.width - xBScrwFixSuppObj.width,0])).center("y").mirroredX();
    var xBnutCsg = xBnutObj.makeCsg();
        xBnutCsg = xBnutCsg.union(xBnutCsg.translate([0,baseObj.width  - 2*xRailAngObj.width - xBScrwFixSuppObj.width,0])).center("y");

    //make THREE meshes, assemble and position
    var geom3;
    //base
    geom3 = THREE.CSG.fromCSG(baseCsg);
    var base = new THREE.Mesh(geom3,matConcrete);
    scene.add(base);
    //side Bed
//     geom3 = THREE.CSG.fromCSG(sideBedCsg);
//     var sideBed = new THREE.Mesh(geom3,matMelamine);
//     base.add(sideBed);
//     sideBed.position.set(0,0,baseObj.thickness);
    //xRailAng
    geom3 = THREE.CSG.fromCSG(xRailAngCsg);
    var xRailAng = new THREE.Mesh(geom3,matAluminium);
    base.add(xRailAng);
    //xRailAng.position.set(0,0,baseObj.thickness);
    //xRails
    geom3 = THREE.CSG.fromCSG(xRailCsg);
    var xRails = new THREE.Mesh(geom3,matAluminium);
    xRailAng.add(xRails);
    xRails.position.set(0,0,xRailObj.width/2 - xRailAngObj.height);
    //xLinBears
    geom3 = THREE.CSG.fromCSG(xLinBearCsg);
    var xLinBears = new THREE.Mesh(geom3,matAluminium);
    xRails.add(xLinBears);
    xLinBears.position.set(gSX,0,0);
    //xCarAng
//     geom3 = THREE.CSG.fromCSG(xCarAngCsg);
//     var xCarAng = new THREE.Mesh(geom3,matAluminium);
//     xLinBears.add(xCarAng);
//     xCarAng.position.set(0,-xCAT,xLinBearObj.height);
    //x ballscrew fixed support
    geom3 = THREE.CSG.fromCSG(xBScrwFixSuppCsg);
    var xBScrwFixSupp = new THREE.Mesh(geom3,matAluminium);
    base.add(xBScrwFixSupp);
    xBScrwFixSupp.position.set(xBScrwFltSuppObj.thick + xBScrwFixSuppObj.thick + xBScrwObj.threadEnd - xBScrwObj.threadStart,0,0);
//     //x ballscrew floating support
    geom3 = THREE.CSG.fromCSG(xBScrwFltSuppCsg);
    var xBScrwFltSupp = new THREE.Mesh(geom3,matAluminium);
    base.add(xBScrwFltSupp);
    xBScrwFltSupp.position.set(0,0,0);
//     //x ballscrew
    geom3 = THREE.CSG.fromCSG(xBScrwCsg);
    var xBScrw = new THREE.Mesh(geom3,matAluminium);
    xBScrwFltSupp.add(xBScrw);
    xBScrw.position.set(xBScrwObj.length + xBScrwFltSuppObj.thick - xBScrwObj.threadFltNub,0,-xBScrwFixSuppObj.bscrewZPos);
    //x ballnut
    geom3 = THREE.CSG.fromCSG(xBnutCsg);
    var xBnut = new THREE.Mesh(geom3,matAluminium);
    xBScrw.add(xBnut);
    xBnut.position.set(gSX + gSL/2 + xBnutObj.length/2 - xBScrwObj.length,0,-xBScrwFixSuppObj.bscrewZPos);
}

//animation loop
function animate() {
    //var delta = clock.getDelta();
    requestAnimationFrame( animate );
    camera.up.set(0,0,1);
    controls.update();
    render();
}

//render function
function render() {
    renderer.render( scene, camera );
}
<commit_msg>positioning tweak<commit_after>//var clock = new THREE.Clock();

//var container, stats;

var camera, cameraTarget, scene, renderer, controls;

init();
animate();

function init() {
    //define a few colors
    var colWhite = new THREE.Color("rgb(100%, 100%, 100%)");
    var colMetal = new THREE.Color("rgb(70%, 70%, 70%)");
    var colConcrete = new THREE.Color("rgb(30%, 30%, 30%)");

    //make materials
    var matConcrete = new THREE.MeshPhongMaterial( { color: colConcrete , specular: 0x111111, shininess: 50 } );
    var matAluminium = new THREE.MeshPhongMaterial( { color: colMetal , specular: 0x111111, shininess: 200 } );
    var matMelamine = new THREE.MeshPhongMaterial( { color: colWhite , specular: 0x111111, shininess: 100 } );

    //dimensions
    //main base
    var basL = 1900;
    var basW = 1000;
    var basH = 18;

    //x carriage angle
    var xCAL = 300;
    var xCAW = 76.2;
    var xCAH = 101.6;
    var xCAT = 6.35;

    //side bed (which the xRails and x ballscrew are seated on
    var sideBedL = basL;
    var sideBedW = 75;
    var sideBedH = 15;
    var sideBedO = 0;(xCAW - xCAT); //amount the sideBed overhangs the sides of the base by. Assumes inset by inner width of xCarAngl - for easy measuring

    //x rail
    var xRL = 1900;
    var xRD = 20;

    //x rail angle
    var xRAL = xRL;
    var xRAW = 50.8;
    var xRAH = 63.5;
    var xRAT = 6.35;

    //x ballscrew
    var xBSD = 20;
    var xBSL = 1900;

    //Gantry side
    var gSL = 300; //gantry side length
    var gSX = 100; //x-location of the gantry

    //y rail
    var yRL = 1004;
    var yRD = 16;

    //y ballscrew
    var yBSD = 16;
    var yBSL = 1000;

    //html container div - to house the WebGL content
    //already made in index.html... an alternative would be to make on the fly here
    var container = document.getElementById("container");

    //renderer
    renderer = new THREE.WebGLRenderer( { antialias: true } );
    renderer.setSize(window.innerWidth, window.innerHeight);
    container.appendChild( renderer.domElement );

    //create scene (global scope)
    scene = new THREE.Scene();
    scene.background = colWhite ;//new THREE.Color( 0xffffff );
    scene.add(new THREE.AxisHelper(3000)); //axis helper

    //create camera (global scope)
    //and add to scene
    camera = new THREE.PerspectiveCamera( 45, container.offsetWidth / container.offsetHeight, 1, 10000 );
    camera.position.y = -1500;
    //camera.lookAt(new THREE.Vector3(0,0,0));
    //camera.position.z = 200;
    scene.add( camera );

    //add TrackBall controls to the camera
    controls = new THREE.TrackballControls( camera);
    controls.position0.set( -200, -1500, 400 ); // set a new desired position
    controls.target0.set(0,0,100);
    controls.up0.set( 0, 0, 1 ); // set a new up vector
    controls.reset();
    controls.rotateSpeed = 10.0;
    controls.zoomSpeed = 1.2;
    controls.panSpeed = 1;
    controls.noZoom = false;
    controls.noPan = false;
    controls.staticMoving = false;
    controls.dynamicDampingFactor = 0.3;
    controls.minDistance = 1.1;
    controls.maxDistance = 10000;
    controls.keys = [ 16, 17, 18 ]; // [ rotateKey, zoomKey, panKey ]

    //create light(s)
    var dirLight = new THREE.DirectionalLight(colWhite , 0.95);
    dirLight.position.set(-200, -1000, 1000);
    dirLight.position.normalize();
    scene.add(dirLight);

    var pointLight = new THREE.PointLight(colWhite , 5, 50);
    pointLight.position.set(10, 20, -10);
    scene.add(pointLight);

    //Make part objects (from shop.js)
    var baseObj = new shopSheet(basL,basW,basH);
    var sideBedObj = new shopSheet(sideBedL,sideBedW,sideBedH);
    var xRailAngObj = new shopAluAngle(xRAW,xRAH,xRAT,xRAL);
    var xRailObj = new shopSbrxx(xRL,xRD);
    var xLinBearObj = new shopSbrxxuu(xRD);
    var xBScrwObj = new shopRmxx05(xBSD, xBSL);
    var xBScrwFixSuppObj = new shopBkxx(xBSD);
    var xBScrwFltSuppObj = new shopBfxx(xBSD);
    var xBnutObj = new shopBallnut(xBSD);
    var xCarAngObj = new shopAluAngle(xCAW,xCAH,xCAT,xCAL);
    var yRailObj = new shopSbrxx(yRL,yRD);

    //make CSGs, and where applicable copies, to be merged into a single geometry
    var baseCsg = baseObj.makeCsg();
        baseCsg = baseCsg.center("y");
//     var sideBedCsg = sideBedObj.makeCsg();
//         sideBedCsg = sideBedCsg.union(sideBedCsg.translate([0,baseObj.width - sideBedObj.width + 2*sideBedO,0])).center("y");
//         sideBedCsg = sideBedCsg.union(sideBedCsg.translate([0,0,-baseObj.thickness - sideBedObj.thickness]));
    var xRailAngCsg = xRailAngObj.makeCsg();
        xRailAngCsg = xRailAngCsg.mirroredY().mirroredZ().translate([0,xRailAngObj.width,0]);
        xRailAngCsg = xRailAngCsg.union(xRailAngCsg.mirroredY().translate([0,baseObj.width,0])).center("y");
    var xRailCsg = xRailObj.makeCsg();
        xRailCsg = xRailCsg.rotateX(90).union(xRailCsg.rotateX(-90).translate([0,baseObj.width - 2*xRailAngObj.inWidth,0])).center("y"); //outside of linear bearings set equal to yRail length
    var xLinBearCsg = xLinBearObj.makeCsg();
        xLinBearCsg = xLinBearCsg.rotateX(90).union(xLinBearCsg.rotateX(90).translate([gSL - xLinBearObj.length,0,0]));
        xLinBearCsg = xLinBearCsg.union(xLinBearCsg.rotateX(180).translate([0,baseObj.width - 2*xRailAngObj.inWidth +2*(xRailObj.railZPos - xLinBearObj.railZPos),0])).center("y");
//     var xCarAngCsg = xCarAngObj.makeCsg();
//         xCarAngCsg = xCarAngCsg.union(xCarAngCsg.mirroredY().translate([0,baseObj.width + 2*xCAT,0])).center("y");
    var xBScrwFixSuppCsg = xBScrwFixSuppObj.makeCsg();
        xBScrwFixSuppCsg = xBScrwFixSuppCsg.union(xBScrwFixSuppCsg.translate([0,baseObj.width  - 2*xRailAngObj.width - xBScrwFixSuppObj.width,0])).center("y").mirroredZ().mirroredX();
    var xBScrwFltSuppCsg = xBScrwFltSuppObj.makeCsg();
        xBScrwFltSuppCsg = xBScrwFltSuppCsg.union(xBScrwFltSuppCsg.translate([0,baseObj.width  - 2*xRailAngObj.width - xBScrwFixSuppObj.width,0])).center("y").mirroredZ();
    var xBScrwCsg = xBScrwObj.makeCsg();
        xBScrwCsg = xBScrwCsg.union(xBScrwCsg.translate([0,baseObj.width  - 2*xRailAngObj.width - xBScrwFixSuppObj.width,0])).center("y").mirroredX();
    var xBnutCsg = xBnutObj.makeCsg();
        xBnutCsg = xBnutCsg.union(xBnutCsg.translate([0,baseObj.width  - 2*xRailAngObj.width - xBScrwFixSuppObj.width,0])).center("y");

    //make THREE meshes, assemble and position
    var geom3;
    //base
    geom3 = THREE.CSG.fromCSG(baseCsg);
    var base = new THREE.Mesh(geom3,matConcrete);
    scene.add(base);
    //side Bed
//     geom3 = THREE.CSG.fromCSG(sideBedCsg);
//     var sideBed = new THREE.Mesh(geom3,matMelamine);
//     base.add(sideBed);
//     sideBed.position.set(0,0,baseObj.thickness);
    //xRailAng
    geom3 = THREE.CSG.fromCSG(xRailAngCsg);
    var xRailAng = new THREE.Mesh(geom3,matAluminium);
    base.add(xRailAng);
    //xRailAng.position.set(0,0,baseObj.thickness);
    //xRails
    geom3 = THREE.CSG.fromCSG(xRailCsg);
    var xRails = new THREE.Mesh(geom3,matAluminium);
    xRailAng.add(xRails);
    xRails.position.set(0,0,xRailObj.width/2 - xRailAngObj.height);
    //xLinBears
    geom3 = THREE.CSG.fromCSG(xLinBearCsg);
    var xLinBears = new THREE.Mesh(geom3,matAluminium);
    xRails.add(xLinBears);
    xLinBears.position.set(gSX,0,0);
    //xCarAng
//     geom3 = THREE.CSG.fromCSG(xCarAngCsg);
//     var xCarAng = new THREE.Mesh(geom3,matAluminium);
//     xLinBears.add(xCarAng);
//     xCarAng.position.set(0,-xCAT,xLinBearObj.height);
    //x ballscrew fixed support
    geom3 = THREE.CSG.fromCSG(xBScrwFixSuppCsg);
    var xBScrwFixSupp = new THREE.Mesh(geom3,matAluminium);
    base.add(xBScrwFixSupp);
    xBScrwFixSupp.position.set(xBScrwFltSuppObj.thick + xBScrwFixSuppObj.thick + xBScrwObj.threadEnd - xBScrwObj.threadStart,0,0);
//     //x ballscrew floating support
    geom3 = THREE.CSG.fromCSG(xBScrwFltSuppCsg);
    var xBScrwFltSupp = new THREE.Mesh(geom3,matAluminium);
    base.add(xBScrwFltSupp);
    xBScrwFltSupp.position.set(0,0,0);
//     //x ballscrew
    geom3 = THREE.CSG.fromCSG(xBScrwCsg);
    var xBScrw = new THREE.Mesh(geom3,matAluminium);
    xBScrwFltSupp.add(xBScrw);
    xBScrw.position.set(xBScrwObj.length + xBScrwFltSuppObj.thick - xBScrwObj.threadFltNub,0,-xBScrwFixSuppObj.bscrewZPos);
    //x ballnut
    geom3 = THREE.CSG.fromCSG(xBnutCsg);
    var xBnut = new THREE.Mesh(geom3,matAluminium);
    xBScrw.add(xBnut);
    xBnut.position.set(gSX + gSL/2 - xBnutObj.length/2 - xBScrwObj.length,0,-xBScrwFixSuppObj.bscrewZPos);
}

//animation loop
function animate() {
    //var delta = clock.getDelta();
    requestAnimationFrame( animate );
    camera.up.set(0,0,1);
    controls.update();
    render();
}

//render function
function render() {
    renderer.render( scene, camera );
}
<|endoftext|>


<commit_before>

function isdigit(c)
{
	return c >= "0" && c <= "9";
}

function ishexdigit(c)
{
	return (c >= "A" && c <= "F") || (c >= "a" && c <= "f") || isdigit(c);
}

function isalpha(c)
{
	return (c >= "A" && c <= "Z") || (c >= "a" && c <= "z");
}

function isalnum(c)
{
	return isdigit(c) || isalpha(c);
}

// =====================================================================================================================
// Log/Warning/Error Reporter
// =====================================================================================================================

function dcpuReport()
{
	this.Content = [ ];

	this.Log = function(text, line)
	{
		this.Content.push([ text, line ]);
	}

	this.Error = function(text, line)
	{
		this.Log("ERROR -- " + text, line);
	}

	this.UnexpectedToken = function(token, line)
	{
		this.Error("Unexpected token '" + token + "'", line);
	}

	this.ExpectingToken = function(token, got, line)
	{
		this.Error("Expecting token '" + token + "' but got '" + got + "'", line);
	}
}

// =====================================================================================================================
// DCPU-16 Basics
// =====================================================================================================================

dcpuOpcodes = {

	// Basic opcodes
	NUL: 0x00,
	SET: 0x01,
	ADD: 0x02,
	SUB: 0x03,
	MUL: 0x04,
	DIV: 0x05,
	MOD: 0x06,
	SHL: 0x07,
	SHR: 0x08,
	AND: 0x09,
	BOR: 0x0A,
	XOR: 0x0B,
	IFE: 0x0C,
	IFN: 0x0D,
	IFG: 0x0E,
	IFB: 0x0F,

	// Non-basic opcodes
	JSR: 0x10000,

	// Not an opcode - purely here for the lexer
	DAT: 0xFFFFFFFF,
};

dcpuRegisters = {

	// Arithmetic registers
	A: 0x00,
	B: 0x01,
	C: 0x02,
	X: 0x03,
	Y: 0x04,
	Z: 0x05,
	I: 0x06,
	J: 0x07,

	// Control registers
	SP: 0x1B,
	PC: 0x1C,
	O:  0x1D,

	// Psuedo registers
	POP: 0x18,
	PEEK: 0x19,
	PUSH: 0x1A
};

// =====================================================================================================================
// Lexer for the DCPU Assembly Language
// =====================================================================================================================

var dcpuTokens = {

	INVALID:"INVALID",
	END:"END OF LINE",

	// Basic characters
	COLON:":",
	SEMICOLON:";",
	COMMA:",",
	LBRACKET:"[",
	RBRACKET:"]",
	PLUS:"+",

	// Keywords/text
	INSTRUCTION:"INSTRUCTION",
	REGISTER:"REGISTER",
	LABEL:"LABEL",

	// Values
	NUMBER:"NUMBER",
	STRING:"STRING"
};

function dcpuLexer(report)
{
	// Initialise defaults
	this.Report = report;
	this.Text = "";
	this.Length = 0;
	this.Pos = 0;
	this.Line = 0;

	this.SetText = function(text, line)
	{
		this.Text = text;
		this.Length = this.Text.length;
		this.Pos = 0;
		this.Line = line;
	}

	this.ParseNumber = function()
	{
		var number_text = "";

		// Skip the hex prefix
		var p = this.Pos;
		if (p + 2 <= this.Length)
		{
			if (this.Text[p] == "0" && this.Text[p + 1] == "x")
			{
				number_text = "0x";
				this.Pos += 2;
			}
		}

		// Pull together the text for the number
		while (this.Pos < this.Length)
		{
			var c = this.Text[this.Pos];
			if (!ishexdigit(c))
				break;
			number_text += c;
			this.Pos++;
		}

		// Check for parse errors before returning
		// NOTE: Not sure how to check for NaN - very dodgy code
		var num = parseInt(number_text);
		if (num.toString() == "NaN")
			return [ dcpuTokens.INVALID, null ];

		if (num > 0xFFFF)
		{
			this.Report.Error("Number '" + num + "' out of range", this.Line);
			return [ dcpuTokens.INVALID, null ];
		}

		return [ dcpuTokens.NUMBER, num ];
	}

	this.ParseString = function()
	{
		var text = "";

		// Skip entry
		this.Pos++;

		// Always increment parsing text to consume the closing quote
		var end = false;
		while (this.Pos < this.Length)
		{
			var c = this.Text[this.Pos++];
			if (c == '"')
			{
				end = true;
				break;
			}
			text += c;
		}

		if (end == false)
		{
			this.Report.Error("Unexpected end of file looking for string end", this.Line);
			return [ dcpuTokens.INVALID, null ];
		}

		return [ dcpuTokens.STRING, text ];
	}

	this.ParseText = function()
	{
		var text = this.Text[this.Pos++];

		// Parse the text, only incrementing on success
		while (this.Pos < this.Length)
		{
			var c = this.Text[this.Pos];
			if (!isalpha(c))
				break;
			text += c;
			this.Pos++;
		}

		// Promote all text to uppercase
		text = text.toUpperCase();

		// First check to see if the text is an instruction or register
		if (text in dcpuOpcodes)
			return [ dcpuTokens.INSTRUCTION, dcpuOpcodes[text] ];
		if (text in dcpuRegisters)
			return [ dcpuTokens.REGISTER, dcpuRegisters[text] ];

		return [ dcpuTokens.LABEL, text ];
	}

	this.NextToken = function()
	{
		while (this.Pos < this.Length)
		{
			var c = this.Text[this.Pos];
			switch (c)
			{
				// Basic character token values are the same as their characters
				case (":"):
				case (";"):
				case (","):
				case ("["):
				case ("]"):
				case ("+"):
					this.Pos++;
					return [ c, null ];

				case ('"'):
					return this.ParseString();

				default:

					// Skip whitespace
					if (c <= " ")
					{
						this.Pos++;
					}

					else if (isdigit(c))
					{
						return this.ParseNumber();
					}

					else if (isalpha(c))
					{
						return this.ParseText();
					}

					else
					{
						this.Report.Error("Invalid character '" + c + "'", this.Line);
						return [ dcpuTokens.INVALID, null ];
					}

			}
		}

		return [ dcpuTokens.END, null ];
	}

	this.ConsumeExpectToken = function(expected)
	{
		var token = this.NextToken();
		if (token[0] != expected)
		{
			this.Report.ExpectingToken(expected, token[0], this.Line);
			return false;
		}

		return true;
	}
}

// =====================================================================================================================
// DCPU-16 Assembly to Byte Code
// =====================================================================================================================

function dcpuAssembler(report)
{
	this.Report = report;
	this.Labels = { };
	this.LabelPatches = [ ];
	this.WordCode = [ ];
	this.Line = 0;

	this.AddLabelPatch = function(label, offset)
	{
		this.LabelPatches.push([ label, this.WordCode.length + offset, this.Line ]);
	}

	this.ParseLabel = function()
	{
		// Get the label name
		var token = this.Lexer.NextToken();
		if (token[0] != dcpuTokens.LABEL)
		{
			this.Report.ExpectingToken(dcpuTokens.LABEL, token[0], this.Line);
			return false;
		}

		this.Labels[token[1]] = this.WordCode.length;
	}

	this.ParseAddressArgument = function(extra_words)
	{
		//
		// Possibilities:
		//
		// Reg			-> 0x00-0x07 (and pseudo/ctrl)
		// Imm			-> 0x20-0x3f for 5-bit numbers or 0x1f + next word
		// Lbl			-> 0x1f + next word (5-bit numbers not allowed)
		// [Reg]		-> 0x08-0x0f (and pseudo/ctrl)
		// [Imm]		-> 0x1e + next word
		// [Lbl]		-> 0x1e + next word
		// [Imm+Reg]	-> 0x10-0x17 (pseudo/ctrl not allowed, value in next word)
		// [Lbl+Reg]	-> 0x10-0x17 (pseudo/ctrl not allowed, value in next word)
		//

		var token = this.Lexer.NextToken();
		var value = token[1];

		// Only arithmetic registers can be used as address operands
		if (token[0] == dcpuTokens.REGISTER)
		{
			if (value > 0x07)
			{
				this.Report.Error("Can't use register '" + value + "' as an address operand", this.Line);
				return [ false, 0 ];
			}

			// Also double-check that the closing token is the bracket
			return [ this.Lexer.ConsumeExpectToken(dcpuTokens.RBRACKET), 0x08 + value ];
		}

		// Either add an immediate or label patch
		if (token[0] == dcpuTokens.NUMBER)
		{
			extra_words.push(value);
		}
		else if (token[0] == dcpuTokens.LABEL)
		{
			this.AddLabelPatch(value, 1 + extra_words.length);
			extra_words.push(0);
		}
		else
		{
			this.Report.UnexpectedToken(token[0], this.Line);
			return [ false, 0 ];
		}

		// Leave if there's no offset
		token = this.Lexer.NextToken();
		if (token[0] == dcpuTokens.RBRACKET)
			return [ true, 0x1E ];

		// Parse the register offset
		if (token[0] == dcpuTokens.PLUS)
		{
			token = this.Lexer.NextToken();
			if (token[0] != dcpuTokens.REGISTER)
			{
				this.Report.ExpectingToken(dcpuTokens.REGISTER, token[0], this.Line);
				return [ false, 0 ];
			}

			// Only arithmetic registers can be used as address operands
			if (token[1] > 0x07)
			{
				this.Report.Error("Can't use register '" + token[1] + "' as an address operand", this.Line);
				return [ false, 0 ];
			}

			// Also double-check that the closing token is the bracket
			return [ this.Lexer.ConsumeExpectToken(dcpuTokens.RBRACKET), 0x10 + token[1] ];
		}

		this.Report.UnexpectedToken(token[0], this.Line);
		return [ false, 0 ];
	}

	this.ParseArgument = function(extra_words)
	{
		var token = this.Lexer.NextToken();
		var value = token[1];

		switch (token[0])
		{
			// Registers are simple!
			case (dcpuTokens.REGISTER):
				return [ true, value ];

			// 5-bit numbers can be compacted into the register details, otherwise they're in the next word
			case (dcpuTokens.NUMBER):
				// NOTE: Disabled for now as the emulator reads/writes with memory addresses
				//if (value <= 0x1F)
				//	return [ true, value + 0x20 ];
				extra_words.push(value);
				return [ true, 0x1F ];

			// Add a label patch note for the literal
			case (dcpuTokens.LABEL):
				this.AddLabelPatch(value, 1 + extra_words.length);
				extra_words.push(0);
				return [ true, 0x1F ];

			// This is quite complicated...
			case (dcpuTokens.LBRACKET):
				return this.ParseAddressArgument(extra_words);

			case (dcpuTokens.INVALID):
			case (dcpuTokens.END):
			default:
				this.Report.UnexpectedToken(token[0], this.Line);
				return [ false, 0 ];
		}

		return [ true, 0 ];
	}

	this.ParseInstruction = function(token)
	{
		// Start off with the opcode
		var word = token[1];
		var extra_words = [ ];

		// Inline data definition
		if (word == dcpuOpcodes.DAT)
		{
			while (true)
			{
				// Check for exit
				token = this.Lexer.NextToken();
				if (token[0] == dcpuTokens.END)
					break;
				if (token[0] == dcpuTokens.INVALID)
				{
					this.Report.UnexpectedToken(token[0], this.Line);
					break;
				}

				// Push directly into byte-code depending upon the token type
				var value = token[1];
				switch (token[0])
				{
					case (dcpuTokens.NUMBER):
						this.WordCode.push(value);
						break;

					case (dcpuTokens.STRING):
						for (var i in value)
							this.WordCode.push(value.charCodeAt(i));
						break;
				}
			}
		}

		else
		{
			// Is this a complex opcode?
			if ((word & 0xF) == 0)
			{
				// Parse the single argument
				var extra_words = [ ];
				var a = this.ParseArgument(extra_words);
				if (!a[0])
					return false;

				// Merge instruction details
				word |= a[1] << 10;
			}

			else
			{
				// Parse both arguments
				var a = this.ParseArgument(extra_words);
				if (!a[0])
					return false;
				var token = this.Lexer.NextToken();
				if (token[0] != dcpuTokens.COMMA)
				{
					this.Report.ExpectingToken(dcpuTokens.COMMA, token[0], this.Line);
					return false;
				}
				var b = this.ParseArgument(extra_words);
				if (!b[0])
					return false;

				// Merge instruction details
				word |= a[1] << 4;
				word |= b[1] << 10;
			}

			// Add to the generated code
			this.WordCode.push(word);
			for (var j in extra_words)
				this.WordCode.push(extra_words[j]);
		}
	}

	this.Assemble = function(asm)
	{
		this.Lexer = new dcpuLexer(this.Report);

		// Split into lines and run the lexer on them individually
		var lines = asm.split("\n");
		for (var i in lines)
		{
			this.Line = parseInt(i) + 1;
			this.Lexer.SetText(lines[i], this.Line);
			var token = this.Lexer.NextToken();

			switch (token[0])
			{
				// Skip comments and empty lines
				case (dcpuTokens.SEMICOLON):
				case (dcpuTokens.END):
					continue;

				// Only accept labels and instructions
				case (dcpuTokens.COLON):
					this.ParseLabel();
					continue;
				case (dcpuTokens.INSTRUCTION):
					this.ParseInstruction(token);
					break;

				default:
					this.Report.UnexpectedToken(token[0], this.Line);
					break;
			}

			// Catch any trailing characters
			token = this.Lexer.NextToken();
			if (token[0] != dcpuTokens.END && token[0] != dcpuTokens.SEMICOLON)
				this.Report.Error("End of line expected", this.Line);
		}

		// Patch up all label references
		for (var i in this.LabelPatches)
		{
			var patch = this.LabelPatches[i];

			// Ensure the labels exist first!
			var label_name = patch[0];
			if (!(label_name in this.Labels))
			{
				this.Report.Error("Unresolved reference to label '" + label_name + "'", patch[2]);
				continue;
			}

			// Set the offset in the byte code
			var label_offset = this.Labels[label_name];
			var reference_offset = patch[1];
			this.WordCode[reference_offset] = label_offset;
		}
	}
}

// =====================================================================================================================
// DCPU-16 Emulator
// =====================================================================================================================

function dcpuEmulator()
{
	this.Reset = function()
	{
		// Registers are mapped to >128k memory to make emulator code a little easier
		this.WordMem = new Array(0x10000 + 8 + 3);
		this.Registers = 0x10000;
		this.PC = this.Registers + 8 + 0;
		this.SP = this.Registers + 8 + 1;
		this.O  = this.Registers + 8 + 2;

		// Reset registers
		this.WordMem[this.PC] = 0;
		this.WordMem[this.SP] = 0xFFFF;
		this.WordMem[this.O] = 0;

		// I can't believe I'm doing this... is there a better way?
		for (var i = 0; i < this.WordMem.length; i++)
			this.WordMem[i] = 0;
		this.CodeLength = 0;
	}

	// Initial reset on create
	this.Reset();

	this.UploadCode = function(word_code)
	{
		this.Reset();

		// Copy each word manually
		this.CodeLength = word_code.length;
		for (var i = 0; i < this.CodeLength; i++)
		{
			var word = word_code[i];
			this.WordMem[i] = word;
		}
	}

	this.DecodeArgumentAddr = function(instr, shift)
	{
		// Get the correct argument
		var arg = (instr >> shift) & 0x3F;

		// Memory and registers are part of the same memory map, allowing this single function to return
		// the address of both source and destinaton operands.

		// Register values and immediate values in the code segment
		if (arg < 0x08)
			return this.Registers + arg;
		if (arg < 0x10)
			return this.WordMem[this.Registers + (arg - 0x08)];
		if (arg < 0x18)
			return this.WordMem[this.WordMem[this.PC]++] + this.WordMem[this.Registers + (arg - 0x10)];

		// Stack values that CAN NOT be used as address operands; this is implied by the instruction
		if (arg == dcpuRegisters.POP)
			return this.WordMem[this.SP]++;
		if (arg == dcpuRegisters.PEEK)
			return this.WordMem[this.SP];
		if (arg == dcpuRegisters.PUSH)
			return --this.WordMem[this.SP];

		// Raw control register values
		if (arg == dcpuRegisters.SP)
			return this.SP;
		if (arg == dcpuRegisters.PC)
			return this.PC;
		if (arg == dcpuRegisters.O)
			return this.O;

		// Using immediate values as address operands
		if (arg == 0x1E)
			return this.WordMem[this.WordMem[this.PC]++];

		// This is for immediate values. The spec mentions that writing to an immediate silently fails
		// whereas this code will effectively write to the code segment.
		if (arg == 0x1F)
			return this.WordMem[this.PC]++

		// TODO: 5-bit compact immediate values! (add another variable at the end of the mmap and use that)
	}

	this.SetO = function(o)
	{
		this.WordMem[this.O] = o & 0xFFFF;
	}

	// Simple instructions listed by index using their opcode - brittle but fast
	this.SimpleInstructions = [
		null,
		function(a, b) { return b; },
		function(a, b) { var r = a + b; this.SetO(r > 0xFFFF ? 1 : 0); return r; },
		function(a, b) { var r = a - b; this.SetO(r < 0 ? 0xFFFF : 0); return r < 0 ? r + 0xFFFF : r; },
		function(a, b) { var r = a * b; this.SetO(r >> 16); return r; },
		function(a, b) { if (b == 0) { this.SetO(0); return 0; } var r = a / b; this.SetO((a << 16) / b); return r; },
		function(a, b) { var r = b == 0 ? 0: a % b; return r; },
		function(a, b) { var r = a << b; this.SetO(r >> 16); return r; },
		function(a, b) { var r = a >> b; this.SetO((a << 16) >> b); return r; },
		function(a, b) { return a & b; },
		function(a, b) { return a | b; },
		function(a, b) { return a ^ b; },
		function(a, b) { if (a != b) this.SkipNextInstruction = true; },
		function(a, b) { if (a == b) this.SkipNextInstruction = true; },
		function(a, b) { if (a <= b) this.SkipNextInstruction = true; },
		function(a, b) { if ((a & b) == 0) this.SkipNextInstruction = true; }
	]

	this.SimpleOp = function(instr, op)
	{
		// Decode both arguments (forwards PC appropriately)
		var a = this.DecodeArgumentAddr(instr, 4);
		var b = this.DecodeArgumentAddr(instr, 10);

		if (this.SkipNextInstruction)
		{
			this.SkipNextInstruction = false;
		}

		else
		{
			// Run the instruction and commit any needed results to the first argument
			var r = op.apply(this, [ this.WordMem[a], this.WordMem[b] ]);
			if (r != null)
				this.WordMem[a] = r & 0xFFFF;
		}
	}

	this.JSR = function(instr)
	{
		// Decode the only argument
		var a = this.DecodeArgumentAddr(instr, 10);

		if (this.SkipNextInstruction)
		{
			this.SkipNextInstruction = false;
		}

		else
		{
			// Push address of next instruction
			var pc = this.WordMem[this.PC];
			this.WordMem[--this.WordMem[this.SP]] = pc;

			// Jump to subroutine
			this.WordMem[this.PC] = this.WordMem[a];
		}
	}

	this.DecodeInstruction = function()
	{
		// Don't execute into the ether!
		if (this.WordMem[this.PC] >= this.CodeLength)
			return;

		var instr = this.WordMem[this.WordMem[this.PC]++];

		// Decode and execute simple instructions
		var simple_op = instr & 0xF;
		if (this.SimpleInstructions[simple_op])
			this.SimpleOp(instr, this.SimpleInstructions[simple_op]);

		// Only one complex op for the moment but that will no doubt change at a later date - update then
		else if ((instr & 0xF0000) == dcpuOpcodes.JSR)
			this.JSR(instr);
	}

	this.UploadCharacterSet = function(image)
	{
		// Create a canvas and blit the image into that
		var buffer = document.createElement("canvas");
		buffer.width = image.width;
		buffer.height = image.height;
		var ctx = buffer.getContext("2d");
		ctx.drawImage(image, 0, 0);

		// Get access to the pixels
		var image_data = ctx.getImageData(0, 0, buffer.width, buffer.height);
		var data = image_data.data;

		// This one nasty big hack but I'm too tired now
		// Will clean it up later...
		for (var i = 0; i < buffer.width; i += 4)
		{
			var w = 0;
			for (var y = 0; y < 8; y++)
			{
				var p = data[y * buffer.width * 4 + i * 4 + 0 * 4];
				p = (p ? 0 : 1);
				w |= (1 << y) * p;
			}
			for (var y = 0; y < 8; y++)
			{
				var p = data[y * buffer.width * 4 + i * 4 + 1 * 4];
				p = (p ? 0 : 1);
				w |= (1 << (y+8)) * p;
			}

			this.WordMem[0x9000 + (32 + i / 4) * 2] = w;

			var w = 0;
			for (var y = 0; y < 8; y++)
			{
				var p = data[y * buffer.width * 4 + i * 4 + 2 * 4];
				p = (p ? 0 : 1);
				w |= (1 << y) * p;
			}
			for (var y = 0; y < 8; y++)
			{
				var p = data[y * buffer.width * 4 + i * 4 + 3 * 4];
				p = (p ? 0 : 1);
				w |= (1 << (y+8)) * p;
			}

			this.WordMem[0x9000 + (32 + i / 4) * 2 + 1] = w;
		}
	}

	function DrawColumn(data, po, line_width, c)
	{
		for (var i = 0; i < 8; i++)
		{
			if (c & 1)
			{
				data[po+0] = 0x33;
				data[po+1] = 0x66;
				data[po+2] = 0xFF;
			}
			po += line_width;
			c >>= 1;
		}
	}

	this.GenerateVideoBuffer = function()
	{
		// Create the video buffer canvas on demand
		if (!this.VideoBuffer)
		{
			this.VideoBuffer = document.createElement("canvas");
			this.VideoBuffer.width = 30 * 4;
			this.VideoBuffer.height = 10 * 8;
			this.VideoBuffer.Ctx = this.VideoBuffer.getContext("2d");
		}

		var w = this.VideoBuffer.width;
		var h = this.VideoBuffer.height;
		this.VideoBuffer.Ctx.fillStyle = "#000025";
		this.VideoBuffer.Ctx.fillRect(0, 0, w, h);

		var image_data = this.VideoBuffer.Ctx.getImageData(0, 0, w, h);
		var data = image_data.data;

		var line_width = w * 8 * 4;
		var char_width = 4 * 4;

		for (var y = 0, i = 0, po = 0; y < h; y += 8, po += line_width)
		{
			for (var x = 0; x < w; x += 4, i++, po += char_width)
			{
				var ccode = Emulator.WordMem[0x8000 + i] & 0x7F
				if (ccode)
				{
					// Locate the two words defining the character
					var coffs = 0x9000 + ccode * 2;
					var w0 = Emulator.WordMem[coffs + 0];
					var w1 = Emulator.WordMem[coffs + 1];

					// Split into the 4 columns and draw
					DrawColumn(data, po, w * 4, w0 & 0xFF);
					DrawColumn(data, po + 4, w * 4, w0 >> 8);
					DrawColumn(data, po + 8, w * 4, w1 & 0xFF);
					DrawColumn(data, po + 12, w * 4, w1 >> 8);
				}
			}
		}

		this.VideoBuffer.Ctx.putImageData(image_data, 0 , 0);
		return this.VideoBuffer;
	}
}<commit_msg>Shorter, more concise info box<commit_after><|endoftext|>


<commit_before>/**
 * @license RequireCSS 0.3.0 Copyright (c) 2011, VIISON All Rights Reserved.
 * Available via the MIT or new BSD license.
 * see: http://github.com/VIISON/RequireCSS for details
 */
(function () {
	"use strict";

	var head = document.head || document.getElementsByTagName('head')[0],
		// Eliminate browsers that admit to not support the link load event (e.g. Firefox)
		nativeLoad = document.createElement('link').onload === null ? undefined : false;

	function createLink(url) {
		var link = document.createElement('link');

		link.rel = "stylesheet";
		link.type = "text/css";
		link.href = url;

		return link;
	}

	function styleSheetLoaded(url) {
		// Get absolute url
		var a = document.createElement('a'),
			i;
		a.href = url;

		for (i in document.styleSheets) {
			if (document.styleSheets[i].href === a.href) {
				return true;
			}
		}

		return false;
	}

	define(function () {
		var css;

		css = {
			version: '0.3.0',

			testLoad: function (url, load) {
				// Test if the browser supports the link load event,
				// in case we don't know yet (mostly WebKit)
				if (nativeLoad === undefined) {
					// Create a link element with a data url,
					// it would fire a load event immediately
					var link = createLink('data:text/css,');

					link.onload = function () {
						// Native link load event works
						nativeLoad = true;
					};

					head.appendChild(link);

					// Schedule function in event loop, this will
					// execute after a potential execution of the link onload
					setTimeout(function () {
						head.removeChild(link);

						if (nativeLoad !== true) {
							// Native link load event is broken
							nativeLoad = false;
						}

						css.loadSwitch(url, load);
					}, 0);
				} else {
					css.loadSwitch(url, load);
				}
			},

			loadSwitch: function (url, load) {
				if (nativeLoad) {
					css.loadLink(url, load);
				} else {
					css.loadScript(url, load);
				}
			},

			/**
			 * Load using the browsers built-in load event on link tags
			 */
			loadLink: function (url, load) {
				var link = createLink(url);

				link.onload = function () {
					load();
				};

				head.appendChild(link);
			},

			/**
			 * Insert a script tag and use it's onload & onerror to know when
			 * the CSS is loaded, this will unfortunately also fire on other
			 * errors (file not found, network problems)
			 */
			loadScript: function (url, load) {
				var link = createLink(url),
					script = document.createElement('script');

				head.appendChild(link);

				script.onload = script.onerror = function () {
					head.removeChild(script);

					// In Safari the stylesheet might not yet be applied, when
					// the script is loaded so we poll document.styleSheets for it
					var checkLoaded = function () {
						if (styleSheetLoaded(url)) {
							load();

							return;
						}

						setTimeout(checkLoaded, 25);
					};
					checkLoaded();
				};
				script.src = url;

				head.appendChild(script);
			},

			load: function (name, req, load, config) {
				// Append default extension
				var url = name.search(/\.(css|less|scss)$/i) === -1 ? name + '.css' : name;

				css.testLoad(req.toUrl(url), load);
			}
		};

		return css;
	});
}());<commit_msg>Reuse anchor element for absolute url retrieval<commit_after>/**
 * @license RequireCSS 0.3.0 Copyright (c) 2011, VIISON All Rights Reserved.
 * Available via the MIT or new BSD license.
 * see: http://github.com/VIISON/RequireCSS for details
 */
(function () {
	"use strict";

	var head = document.head || document.getElementsByTagName('head')[0],
		// Eliminate browsers that admit to not support the link load event (e.g. Firefox)
		nativeLoad = document.createElement('link').onload === null ? undefined : false,
		a = document.createElement('a');

	function createLink(url) {
		var link = document.createElement('link');

		link.rel = "stylesheet";
		link.type = "text/css";
		link.href = url;

		return link;
	}

	function styleSheetLoaded(url) {
		var i;

		// Get absolute url by assigning to a link and reading it back below
		a.href = url;

		for (i in document.styleSheets) {
			if (document.styleSheets[i].href === a.href) {
				return true;
			}
		}

		return false;
	}

	define(function () {
		var css;

		css = {
			version: '0.3.0',

			testLoad: function (url, load) {
				// Test if the browser supports the link load event,
				// in case we don't know yet (mostly WebKit)
				if (nativeLoad === undefined) {
					// Create a link element with a data url,
					// it would fire a load event immediately
					var link = createLink('data:text/css,');

					link.onload = function () {
						// Native link load event works
						nativeLoad = true;
					};

					head.appendChild(link);

					// Schedule function in event loop, this will
					// execute after a potential execution of the link onload
					setTimeout(function () {
						head.removeChild(link);

						if (nativeLoad !== true) {
							// Native link load event is broken
							nativeLoad = false;
						}

						css.loadSwitch(url, load);
					}, 0);
				} else {
					css.loadSwitch(url, load);
				}
			},

			loadSwitch: function (url, load) {
				if (nativeLoad) {
					css.loadLink(url, load);
				} else {
					css.loadScript(url, load);
				}
			},

			/**
			 * Load using the browsers built-in load event on link tags
			 */
			loadLink: function (url, load) {
				var link = createLink(url);

				link.onload = function () {
					load();
				};

				head.appendChild(link);
			},

			/**
			 * Insert a script tag and use it's onload & onerror to know when
			 * the CSS is loaded, this will unfortunately also fire on other
			 * errors (file not found, network problems)
			 */
			loadScript: function (url, load) {
				var link = createLink(url),
					script = document.createElement('script');

				head.appendChild(link);

				script.onload = script.onerror = function () {
					head.removeChild(script);

					// In Safari the stylesheet might not yet be applied, when
					// the script is loaded so we poll document.styleSheets for it
					var checkLoaded = function () {
						if (styleSheetLoaded(url)) {
							load();

							return;
						}

						setTimeout(checkLoaded, 25);
					};
					checkLoaded();
				};
				script.src = url;

				head.appendChild(script);
			},

			load: function (name, req, load, config) {
				// Append default extension
				var url = name.search(/\.(css|less|scss)$/i) === -1 ? name + '.css' : name;

				css.testLoad(req.toUrl(url), load);
			}
		};

		return css;
	});
}());<|endoftext|>


<commit_before>/*jslint browser: true, indent: 2, nomen: true, plusplus: true */
/*global _: true */
/*global $: true */
/*global jQuery: true */
/*global console: true */

(function () {
  "use strict";

  var script;

  function camel2dashed(str) {
    return str.replace(/([A-Z])/g, function (c) {return "-" + c.toLowerCase(); });
  }

  function computedCssNode(elt) {
    var style = window.getComputedStyle ? window.getComputedStyle(elt, null) : elt.currentStyle,
      styleValue;
    return _.reduce(_.keys(style),
      function (memo, prop) {
        styleValue = style.getPropertyValue(prop);
        if (styleValue) {
          memo[prop] = styleValue;
        }
        return memo;
      }, {});
  }

  function computedCssTree(elt) {
    if (!elt) {
      return [];
    }
    return {
      tag: elt[0].tagName,
      klass: elt.attr('class'),
      id: elt.attr('id'),
      css: computedCssNode(elt[0]),
      children: _.map(elt.children(), function (c) { return computedCssTree($(c)); })
    };
  }

  function filterKeys(obj, valid_keys) {
    return _.intersection(_.keys(obj), valid_keys).reduce(function (result, key) {
      result[key] = obj[key];
      return result;
    }, {});
  }

  function objectIntersection(array) {
    function simpleIntersection(a, b) {
      return filterKeys(a, _.intersection(_.keys(a), _.keys(b)).filter(function (key) {
        return _.isEqual(a[key], b[key]);
      }));
    }
    function repeatedly(f) {
      return function (args) {
        if (args.length === 0) { return {}; }
        var seed = args.pop();
        return _.reduce(args, function (memo, obj) { return f(memo, obj); }, seed);
      };
    }

    return repeatedly(simpleIntersection)(array);
  }

  function objectDifference(a, b) {
    return filterKeys(a, _.difference(_.keys(a), _.keys(b)));
  }

  function liftHeritable(node) {
    var i, heritable = [
      'cursor', 'font-family', 'font-weight', 'font-stretch', 'font-style',
      'font-size', 'font-size-adjust', 'font', 'font-synthesis', 'font-kerning',
      'font-variant-ligatures', 'font-variant-position', 'font-variant-caps',
      'font-variant-numeric', 'font-variant-alternatives', 'font-variant-east-asian',
      'font-variant', 'font-feature-settings', 'font-language-override', 'text-transform',
      'white-space', 'tab-size', 'line-break', 'word-break', 'hyphens', 'word-wrap',
      'overflow-wrap', 'text-align', 'text-align-last', 'text-justify', 'word-spacing',
      'letter-spacing', 'text-indent', 'hanging-punctuation', 'text-decoration-skip',
      'text-underline-skip', 'text-emphasis-style', 'text-emphasis-color', 'text-emphasis',
      'text-emphasis-position', 'text-shadow', 'color', 'border-collapse', 'border-spacing',
      'caption-side', 'direction', 'elevation', 'empty-cells', 'line-height', 'list-style-image',
      'list-style-position', 'list-style-type', 'list-style', 'orphans', 'pitch-range',
      'pitch', 'quotes', 'richness', 'speak-header', 'speak-numeral', 'speak-punctuation',
      'speak', 'speech-rate', 'stress', 'visibility', 'voice-family', 'volume', 'widows'],
      disinherited_kids = _.map(node.children, liftHeritable),
      common = filterKeys(
        objectIntersection(_.map(disinherited_kids, function (k) { return k.css; })),
        heritable
      );

    for (i = 0; i < disinherited_kids.length; i++) {
      disinherited_kids[i].css = objectDifference(disinherited_kids[i].css, common);
    }
    $.extend(node.css, common);
    return {
      tag: node.tag,
      klass: node.klass,
      id: node.id,
      css: node.css,
      children: disinherited_kids
    };
  }

  function defaultDisplayForTag(tag) {
    return {
      A: 'inline', ABBR: 'inline', ADDRESS: 'block', AREA: 'none',
      ARTICLE: 'block', ASIDE: 'block', AUDIO: 'inline', B: 'inline',
      BASE: 'inline', BB: 'inline', BDI: 'inline', BDO: 'inline', BLOCKQUOTE:
      'block', BODY: 'block', BR: 'inline', BUTTON: 'inline-block', CANVAS:
      'inline', CAPTION: 'table-caption', CITE: 'inline', CODE: 'inline',
      COMMAND: 'inline', DATA: 'inline', DATAGRID: 'inline', DATALIST:
      'none', DD: 'block', DEL: 'inline', DETAILS: 'block', DFN: 'inline',
      DIV: 'block', DL: 'block', DT: 'block', EM: 'inline', EMBED: 'inline',
      EVENTSOURCE: 'inline', FIELDSET: 'block', FIGCAPTION: 'block',
      FIGURE: 'block', FOOTER: 'block', FORM: 'block', H1: 'block', H2:
      'block', H3: 'block', H4: 'block', H5: 'block', H6: 'block', HEADER:
      'block', HGROUP: 'block', HR: 'block', I: 'inline', IFRAME: 'inline',
      IMG: 'inline-block', INPUT: 'inline-block', INS: 'inline', KBD:
      'inline', KEYGEN: 'inline-block', LABEL: 'inline', LEGEND: 'block',
      LI: 'list-item', LINK: 'none', MAP: 'inline', MARK: 'inline', MENU:
      'block', META: 'none', METER: 'inline-block', NAV: 'block', NOSCRIPT:
      'inline', OBJECT: 'inline', OL: 'block', OPTGROUP: 'inline', OPTION:
      'inline', OUTPUT: 'inline', P: 'block', PARAM: 'none', PRE: 'block',
      PROGRESS: 'inline-block', Q: 'inline', RP: 'inline', RT: 'inline',
      RUBY: 'inline', S: 'inline', SAMP: 'inline', SCRIPT: 'none', SECTION:
      'block', SELECT: 'inline-block', SMALL: 'inline', SOURCE: 'inline',
      SPAN: 'inline', STRONG: 'inline', STYLE: 'none', SUB: 'inline',
      SUMMARY: 'block', SUP: 'inline', TABLE: 'table', TBODY: 'table-row-group',
      TD: 'table-cell', TEXTAREA: 'inline-block', TFOOT: 'table-footer-group',
      TH: 'table-cell', THEAD: 'table-header-group', TIME: 'inline', TR:
      'table-row', TRACK: 'inline', U: 'inline', UL: 'block', VAR: 'inline',
      VIDEO: 'inline'}[tag];
  }

  function stripDefaultStyles(node) {
    var defaults = { background: 'rgba(0, 0, 0, 0) none repeat scroll 0% 0% / auto padding-box border-box',
      border: 'none', bottom: 'auto', clear: 'none', clip: 'auto', cursor: 'auto',
      direction: 'ltr', fill: '#000000', filter: 'none', float: 'none', kerning: '0', left: 'auto',
      mask: 'none', opacity: "1", outline: 'none', overflow: 'visible', position: 'static',
      resize: 'none', right: 'auto', stroke: 'none', top: 'auto', zoom: '1', height: 'auto', width: 'auto'};

    if (defaultDisplayForTag(node.tag) === node.css['display']) {
      delete node.css['display'];
    }

    _.each(_.keys(defaults), function (def) {
      var prop = node.css[def];
      if (prop && prop.indexOf(defaults[def]) > -1) {
        delete node.css[def];
      }
    });
    _.each(node.children, function (k) {
      stripDefaultStyles(k);
    });
  }

  function selectorsUsed(node) {
    function tagDict(node) {
      var dict = {};
      dict[node.tag] = true;
      if (node.klass) {
        _.each(node.klass.split(/\s+/), function (klass) {
          dict['.' + klass] = true;
        });
      }
      _.each(node.children, function (k) { $.extend(dict, tagDict(k)); });
      return dict;
    }
    return _.keys(tagDict(node));
  }

  function select(root, condition) {
    var collection = [];
    if (condition(root)) {
      collection.push(root);
    }
    _.each(root.children, function (k) { collection = collection.concat(select(k, condition)); });
    return collection;
  }

  function apply(condition, transformation) {
    function applyToNode(node) {
      var ret = condition(node) ? transformation(node) : node;
      ret.children = _.map(ret.children, function (k) {
        return applyToNode(k, condition, transformation);
      });
      return ret;
    }
    return applyToNode;
  }

  function checkMatch(selector) {
    return function (node) {
      var classRegexp;
      if (!node) {
        return false;
      }
      if (selector[0] === '.' && node.klass) {
        classRegexp = new RegExp('\\b' + selector.substring(1) + '\\b');
        return node.klass.match(classRegexp);
      }
      return node.tag === selector;
    };
  }

  function styleConsolidations(node) {
    return _.reduce(selectorsUsed(node),
      function (memo, selector) {
        var instances = select(node, checkMatch(selector));
        memo[selector] = {
          css: objectIntersection(_.map(instances, function (i) { return i.css; })),
          count: instances.length
        };
        return memo;
      }, {});
  }

  function renderStyle(selector, properties) {
    if (!_.isEmpty(properties.css)) {
      console.log(selector + ' {');
      _.each(properties.css, function (val, key) {
        console.log("\t" + key + ': ' + val + ';');
      });
      console.log('}');
    }
  }

  function selectorPropertyVolume(consolidation) {
    return _.map(consolidation, function (properties, tag) {
      var ret = {};
      ret[tag] = _.keys(properties.css).length * properties.count;
      return ret;
    });
  }

  function removeStyleFromSelected(node, selector, style) {
    return apply(checkMatch(selector), function (node) {
      var ret = node;
      ret.css = objectDifference(node.css, style);
      return ret;
    })(node);
  }

  function consolidateSelectors(cssTree) {
    var consolidated, i, n = selectorsUsed(cssTree).length, primeSelector;
    for (i = 0; i < n; i++) {
      consolidated = styleConsolidations(cssTree);
      primeSelector = _.keys(_.sortBy(selectorPropertyVolume(consolidated), function (choice) {
        return -(_.values(choice)[0]);
      })[0])[0];
      renderStyle(primeSelector, consolidated[primeSelector]);
      cssTree = removeStyleFromSelected(cssTree, primeSelector, consolidated[primeSelector].css);
    }
    return cssTree;
  }

  function onScriptsLoaded() {
    console.log("Lifting heritable styles...");
    var lifted = liftHeritable(computedCssTree($('body')));
    console.log("Stripping default styles...");
    stripDefaultStyles(lifted);
    console.log("Consolidating styles...");
    consolidateSelectors(lifted);
  }

  ////////////////////////////////////////////////////////////////////////////////////////
  // Load jQuery and underscore then begin the fun.
  console.log("Loading required external scripts...");
  script        = document.createElement("script");
  script.src    = "https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js";
  script.onload = function () {
    jQuery.getScript(
      'https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min.js',
      onScriptsLoaded
    );
  };
  document.getElementsByTagName("head")[0].appendChild(script);
}());
<commit_msg>Use jquery to associate data with dom elements<commit_after>/*jslint browser: true, indent: 2, nomen: true, plusplus: true */
/*global _: true */
/*global $: true */
/*global jQuery: true */
/*global console: true */

(function () {
  "use strict";

  var script;

  function computedCssProperties(elt, pseudoclass) {
    var style = window.getComputedStyle ? window.getComputedStyle(elt, pseudoclass || null) : elt.currentStyle;
    return _.reduce(_.keys(style),
      function (memo, prop) {
        var styleValue = style.getPropertyValue(prop);
        if (styleValue) {
          memo[prop] = styleValue;
        }
        return memo;
      }, {}) || {};
  }

  function filterKeys(obj, valid_keys) {
    return _.intersection(_.keys(obj), valid_keys).reduce(function (result, key) {
      result[key] = obj[key];
      return result;
    }, {});
  }

  function objectIntersection(array) {
    function simpleIntersection(a, b) {
      if (typeof a !== 'object' || typeof b !== 'object') {
        return {};
      }
      return filterKeys(a, _.intersection(_.keys(a), _.keys(b)).filter(function (key) {
        return _.isEqual(a[key], b[key]);
      }));
    }
    function repeatedly(f) {
      return function (args) {
        if (args.length === 0) { return {}; }
        var seed = args.pop();
        return _.reduce(args, function (memo, obj) { return f(memo, obj); }, seed);
      };
    }

    return repeatedly(simpleIntersection)(array);
  }

  function objectDifference(a, b) {
    if (typeof a !== 'object' || typeof b !== 'object') {
      return a;
    }
    return filterKeys(a, _.difference(_.keys(a), _.keys(b)));
  }

  function commonStyle(nodes) {
    return objectIntersection(_.map(nodes, function (k) { return $(k).data('style') || {}; }));
  }

  function liftHeritable(node) {
    node.children().each(function () { liftHeritable($(this)); });

    var heritable = [
      'cursor', 'font-family', 'font-weight', 'font-stretch', 'font-style',
      'font-size', 'font-size-adjust', 'font', 'font-synthesis', 'font-kerning',
      'font-variant-ligatures', 'font-variant-position', 'font-variant-caps',
      'font-variant-numeric', 'font-variant-alternatives', 'font-variant-east-asian',
      'font-variant', 'font-feature-settings', 'font-language-override', 'text-transform',
      'white-space', 'tab-size', 'line-break', 'word-break', 'hyphens', 'word-wrap',
      'overflow-wrap', 'text-align', 'text-align-last', 'text-justify', 'word-spacing',
      'letter-spacing', 'text-indent', 'hanging-punctuation', 'text-decoration-skip',
      'text-underline-skip', 'text-emphasis-style', 'text-emphasis-color', 'text-emphasis',
      'text-emphasis-position', 'text-shadow', 'color', 'border-collapse', 'border-spacing',
      'caption-side', 'direction', 'elevation', 'empty-cells', 'line-height', 'list-style-image',
      'list-style-position', 'list-style-type', 'list-style', 'orphans', 'pitch-range',
      'pitch', 'quotes', 'richness', 'speak-header', 'speak-numeral', 'speak-punctuation',
      'speak', 'speech-rate', 'stress', 'visibility', 'voice-family', 'volume', 'widows'],
      common = filterKeys(commonStyle(node.children()), heritable);

    node.children().each(function () {
      $(this).data('style', objectDifference($(this).data('style'), common));
    });
    node.data('style', $.extend(node.data('style'), common));
  }

  function defaultDisplayForTag(tag) {
    return {
      A: 'inline', ABBR: 'inline', ADDRESS: 'block', AREA: 'none',
      ARTICLE: 'block', ASIDE: 'block', AUDIO: 'inline', B: 'inline',
      BASE: 'inline', BB: 'inline', BDI: 'inline', BDO: 'inline', BLOCKQUOTE:
      'block', BODY: 'block', BR: 'inline', BUTTON: 'inline-block', CANVAS:
      'inline', CAPTION: 'table-caption', CITE: 'inline', CODE: 'inline',
      COMMAND: 'inline', DATA: 'inline', DATAGRID: 'inline', DATALIST:
      'none', DD: 'block', DEL: 'inline', DETAILS: 'block', DFN: 'inline',
      DIV: 'block', DL: 'block', DT: 'block', EM: 'inline', EMBED: 'inline',
      EVENTSOURCE: 'inline', FIELDSET: 'block', FIGCAPTION: 'block',
      FIGURE: 'block', FOOTER: 'block', FORM: 'block', H1: 'block', H2:
      'block', H3: 'block', H4: 'block', H5: 'block', H6: 'block', HEADER:
      'block', HGROUP: 'block', HR: 'block', I: 'inline', IFRAME: 'inline',
      IMG: 'inline-block', INPUT: 'inline-block', INS: 'inline', KBD:
      'inline', KEYGEN: 'inline-block', LABEL: 'inline', LEGEND: 'block',
      LI: 'list-item', LINK: 'none', MAP: 'inline', MARK: 'inline', MENU:
      'block', META: 'none', METER: 'inline-block', NAV: 'block', NOSCRIPT:
      'inline', OBJECT: 'inline', OL: 'block', OPTGROUP: 'inline', OPTION:
      'inline', OUTPUT: 'inline', P: 'block', PARAM: 'none', PRE: 'block',
      PROGRESS: 'inline-block', Q: 'inline', RP: 'inline', RT: 'inline',
      RUBY: 'inline', S: 'inline', SAMP: 'inline', SCRIPT: 'none', SECTION:
      'block', SELECT: 'inline-block', SMALL: 'inline', SOURCE: 'inline',
      SPAN: 'inline', STRONG: 'inline', STYLE: 'none', SUB: 'inline',
      SUMMARY: 'block', SUP: 'inline', TABLE: 'table', TBODY: 'table-row-group',
      TD: 'table-cell', TEXTAREA: 'inline-block', TFOOT: 'table-footer-group',
      TH: 'table-cell', THEAD: 'table-header-group', TIME: 'inline', TR:
      'table-row', TRACK: 'inline', U: 'inline', UL: 'block', VAR: 'inline',
      VIDEO: 'inline'}[tag];
  }

  function stripDefaultStyles(node) {
    var defaults = { background: 'rgba(0, 0, 0, 0) none repeat scroll 0% 0% / auto padding-box border-box',
      border: 'none', bottom: 'auto', clear: 'none', clip: 'auto', cursor: 'auto',
      direction: 'ltr', fill: '#000000', filter: 'none', float: 'none', kerning: '0', left: 'auto',
      mask: 'none', opacity: "1", outline: 'none', overflow: 'visible', position: 'static',
      resize: 'none', right: 'auto', stroke: 'none', top: 'auto', zoom: '1', height: 'auto', width: 'auto'};

    if (node.data('style')) {
      if (defaultDisplayForTag(node.prop("tagName")) === node.data('style')['display']) {
        delete node.data('style')['display'];
      }
      _.each(_.keys(defaults), function (def) {
        var prop = node.data('style')[def];
        if (prop && prop.indexOf(defaults[def]) > -1) {
          delete node.data('style')[def];
        }
      });
    }
    node.children().each(function () {
      stripDefaultStyles($(this));
    });
  }

  function selectorsUsed(node) {
    function tagDict(node) {
      var dict = {};
      dict[node.prop("tagName")] = true;
      if (node.attr('class')) {
        _.each(node.attr('class').split(/\s+/), function (klass) {
          if (klass) {
            dict['.' + klass] = true;
          }
        });
      }
      node.children().each(function () { $.extend(dict, tagDict($(this))); });
      return dict;
    }
    return _.keys(tagDict(node));
  }

  function renderStyle(selector, properties) {
    if (!_.isEmpty(properties)) {
      console.log(selector + ' {');
      _.each(properties, function (val, key) {
        console.log("\t" + key + ': ' + val + ';');
      });
      console.log('}');
    }
  }

  function onScriptsLoaded() {
    var root = $('body'), selectors, common, best;

    console.log("Computing styles...");
    $('*').each(function () {
      $(this).data('style', computedCssProperties(this));
    });

    console.log("Lifting heritable styles...");
    liftHeritable(root);

    console.log("Stripping default styles...");
    stripDefaultStyles(root);

    console.log("Consolidating styles...");
    selectors = selectorsUsed(root);
    while(selectors.length > 0) {
      common = _.map(selectors, function (sel) {
        return { selector: sel, style: commonStyle(root.find(sel)) };
      });
      best   = _.sortBy(common, function (choice) {
        return -(_.keys(choice.style).length * root.find(choice.selector).length);
      })[0];
      renderStyle(best.selector, best.style);
      $(best.selector).each(function () {
        $(this).data('style', objectDifference($(this).data('style'), best.style));
      });
      selectors = _.without(selectors, best.selector);
    }
  }

  ////////////////////////////////////////////////////////////////////////////////////////
  // Load jQuery and underscore then begin the fun.
  console.log("Loading required external scripts...");
  script        = document.createElement("script");
  script.src    = "https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js";
  script.onload = function () {
    jQuery.getScript(
      'https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min.js',
      onScriptsLoaded
    );
  };
  document.getElementsByTagName("head")[0].appendChild(script);
}());
<|endoftext|>


<commit_before>var dms_check = /(\d+\.?\d*)\D+(\d+\.?\d*)\D+(\d+\.?\d*)/,
	dm_check = /(\d+\.?\d*)\D+(\d+\.?\d*)/,
	d_check = /(\d+\.?\d*)/,
	float_check = /(\d+)(\.\d+)/;

module.exports = function deg (input) {
	var dec = 0.0, d = 0.0, m = 0.0, s = 0.0;

	if (isNaN(input)) {
		// Attempt to find 3 numbers.
		var match = dms_check.exec(input);

		// Found 3 numbers.
		if (match) {
			// Get the seconds.
			s = parseFloat(match[3]);

		} else {
			// Attempt to find 2 numbers.
			match = dm_check.exec(input);
		}

		// At least 2 numbers were found.
		if (match) {
			// Check if minutes have a fraction.
			float_match = float_check.exec(match[2]);

			if (float_match) {
				// Get the integer part of the minutes.
				m = parseInt(float_match[1]);

				// Add the fraction part to the seconds.
				s += parseFloat(float_match[2]) * 60;

			} else {
				// Get the minutes.
				m = parseInt(float_match[2]);
			}

		} else {
			// Attempt to find 1 number.
			match = d_check.exec(input);
		}

		// At least 1 number was found.
		if (match) {
			// Check if degrees have a fraction.
			float_match = float_check.exec(match[1]);

			if (float_match) {
				// Get the integer part of the degrees.
				d = parseInt(float_match[1]);

				// Add the fraction part to the minutes.
				m += parseFloat(float_match[2]) * 60;

			} else {
				// Get the degrees.
				m = parseInt(match[2]);
			}
		}

		// Calculate the decimal degrees from what was found.
		dec = d + (m / 60.0) + (s / 60.0);

	} else {
		dec = input;
		d = 0;
		m = 0;
		s = 0;
	}

	return {
		decimal: dec,
		degrees: d,
		minutes: m,
		seconds: s,
	};
};
<commit_msg>Add decimal degrees conversion<commit_after>var dms_check = /(\d+\.?\d*)\D+(\d+\.?\d*)\D+(\d+\.?\d*)/,
	dm_check = /(\d+\.?\d*)\D+(\d+\.?\d*)/,
	d_check = /(\d+\.?\d*)/,
	float_check = /(\d+)(\.\d+)/;

module.exports = function deg (input) {
	var dec = 0.0, d = 0.0, m = 0.0, s = 0.0;

	if (isNaN(input)) {
		// Attempt to find 3 numbers.
		var match = dms_check.exec(input);

		// Found 3 numbers.
		if (match) {
			// Get the seconds.
			s = parseFloat(match[3]);

		} else {
			// Attempt to find 2 numbers.
			match = dm_check.exec(input);
		}

		// At least 2 numbers were found.
		if (match) {
			// Check if minutes have a fraction.
			float_match = float_check.exec(match[2]);

			if (float_match) {
				// Get the integer part of the minutes.
				m = parseInt(float_match[1]);

				// Add the fraction part to the seconds.
				s += parseFloat(float_match[2]) * 60;

			} else {
				// Get the minutes.
				m = parseInt(float_match[2]);
			}

		} else {
			// Attempt to find 1 number.
			match = d_check.exec(input);
		}

		// At least 1 number was found.
		if (match) {
			// Check if degrees have a fraction.
			float_match = float_check.exec(match[1]);

			if (float_match) {
				// Get the integer part of the degrees.
				d = parseInt(float_match[1]);

				// Add the fraction part to the minutes.
				m += parseFloat(float_match[2]) * 60;

			} else {
				// Get the degrees.
				m = parseInt(match[2]);
			}
		}

		// Calculate the decimal degrees from what was found.
		dec = d + (m / 60.0) + (s / 60.0);

	// Input is a number, so it is treated as a decimal degrees float.
	} else {
		dec = input;

		d = Math.floor(input);

		m_float = (input - d) * 60.0;
		m = Math.floor(m_float);

		s = (m_float - m) * 60.0;
	}

	return {
		decimal: dec,
		degrees: d,
		minutes: m,
		seconds: s,
	};
};
<|endoftext|>


<commit_before>// doT.js
// 2011, Laura Doktorova, https://github.com/olado/doT
//
// doT.js is an open source component of http://bebedo.com
// Licensed under the MIT license.
//
(function() {
	"use strict";

	var doT = {
		version: '0.2.0',
		templateSettings: {
			evaluate:    /\{\{([\s\S]+?)\}\}/g,
			interpolate: /\{\{=([\s\S]+?)\}\}/g,
			encode:      /\{\{!([\s\S]+?)\}\}/g,
			use:         /\{\{#([\s\S]+?)\}\}/g,
			define:      /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,
			conditional: /\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,
			iterate:     /\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,
			varname: 'it',
			strip: true,
			append: true,
			selfcontained: false
		},
		template: undefined, //fn, compile template
		compile:  undefined  //fn, for express
	};

	var global = (function(){ return this || (0||eval)('this'); }());

	if (typeof module !== 'undefined' && module.exports) {
		module.exports = doT;
	} else if (typeof define === 'function' && define.amd) {
		define(function(){return doT;});
	} else {
		global.doT = doT;
	}

	function encodeHTMLSource() {
		var encodeHTMLRules = { "&": "&", "<": "<", ">": ">", '"': '"', "'": ''', "/": '/' },
			matchHTML = /&(?!\\w+;)|<|>|"|'|\//g;
		return function(code) {
			return code ? code.toString().replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : code;
		};
	}
	global.encodeHTML = encodeHTMLSource();

	var startend = {
		append: { start: "'+(",      end: ")+'",      startencode: "'+encodeHTML(" },
		split:  { start: "';out+=(", end: ");out+='", startencode: "';out+=encodeHTML("}
	}, skip = /$^/;

	function resolveDefs(c, block, def) {
		return ((typeof block === 'string') ? block : block.toString())
		.replace(c.define || skip, function(m, code, assign, value) {
			if (code.indexOf('def.') === 0) {
				code = code.substring(4);
			}
			if (!(code in def)) {
				if (assign === ':') {
					def[code]= value;
				} else {
					eval("def['"+code+"']=" + value);
				}
			}
			return '';
		})
		.replace(c.use || skip, function(m, code) {
			var v = eval(code);
			return v ? resolveDefs(c, v, def) : v;
		});
	}

	function unescape(code) {
		return code.replace(/\\('|\\)/g, "$1").replace(/[\r\t\n]/g, ' ');
	}

	doT.template = function(tmpl, c, def) {
		c = c || doT.templateSettings;
		var cse = c.append ? startend.append : startend.split, str, needhtmlencode, sid=0, indv;

		if (c.use || c.define) {
			var olddef = global.def; global.def = def || {}; // workaround minifiers
			str = resolveDefs(c, tmpl, global.def);
			global.def = olddef;
		} else str = tmpl;

		str = ("var out='" + (c.strip ? str.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g,' ')
					.replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,''): str)
			.replace(/'|\\/g, '\\$&')
			.replace(c.interpolate || skip, function(m, code) {
				return cse.start + unescape(code) + cse.end;
			})
			.replace(c.encode || skip, function(m, code) {
				needhtmlencode = true;
				return cse.startencode + unescape(code) + cse.end;
			})
			.replace(c.conditional || skip, function(m, elsecase, code) {
				return elsecase ?
					(code ? "';}else if(" + unescape(code) + "){out+='" : "';}else{out+='") :
					(code ? "';if(" + unescape(code) + "){out+='" : "';}out+='");
			})
			.replace(c.iterate || skip, function(m, iterate, vname, iname) {
				if (!iterate) return "';} } out+='";
				sid+=1; indv=iname || "i"+sid; iterate=unescape(iterate);
				return "';var arr"+sid+"="+iterate+";if(arr"+sid+"){var "+indv+"=-1,l"+sid+"=arr"+sid+".length-1;while("+indv+"<l"+sid+"){"
					+vname+"=arr"+sid+"["+indv+"+=1];out+='";
			})
			.replace(c.evaluate || skip, function(m, code) {
				return "';" + unescape(code) + "out+='";
			})
			+ "';return out;")
			.replace(/\n/g, '\\n').replace(/\t/g, '\\t').replace(/\r/g, '\\r')
			.replace(/(\s|;|}|^|{)out\+='';/g, '$1').replace(/\+''/g, '')
			.replace(/(\s|;|}|^|{)out\+=''\+/g,'$1out+=');

		if (needhtmlencode && c.selfcontained) {
			str = "var encodeHTML=(" + encodeHTMLSource.toString() + "());" + str;
		}
		try {
			return new Function(c.varname, str);
		} catch (e) {
			if (typeof console !== 'undefined') console.log("Could not create a template function: " + str);
			throw e;
		}
	};

	doT.compile = function(tmpl, def) {
		return doT.template(tmpl, null, def);
	};
}());
<commit_msg>Opera 11.6 compatibility. Closes #26.<commit_after>// doT.js
// 2011, Laura Doktorova, https://github.com/olado/doT
//
// doT.js is an open source component of http://bebedo.com
// Licensed under the MIT license.
//
(function() {
	"use strict";

	var doT = {
		version: '0.2.0',
		templateSettings: {
			evaluate:    /\{\{([\s\S]+?)\}\}/g,
			interpolate: /\{\{=([\s\S]+?)\}\}/g,
			encode:      /\{\{!([\s\S]+?)\}\}/g,
			use:         /\{\{#([\s\S]+?)\}\}/g,
			define:      /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,
			conditional: /\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,
			iterate:     /\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,
			varname: 'it',
			strip: true,
			append: true,
			selfcontained: false
		},
		template: undefined, //fn, compile template
		compile:  undefined  //fn, for express
	};

	var global = (function(){ return this || (0,eval)('this'); }());

	if (typeof module !== 'undefined' && module.exports) {
		module.exports = doT;
	} else if (typeof define === 'function' && define.amd) {
		define(function(){return doT;});
	} else {
		global.doT = doT;
	}

	function encodeHTMLSource() {
		var encodeHTMLRules = { "&": "&", "<": "<", ">": ">", '"': '"', "'": ''', "/": '/' },
			matchHTML = /&(?!\\w+;)|<|>|"|'|\//g;
		return function(code) {
			return code ? code.toString().replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : code;
		};
	}
	global.encodeHTML = encodeHTMLSource();

	var startend = {
		append: { start: "'+(",      end: ")+'",      startencode: "'+encodeHTML(" },
		split:  { start: "';out+=(", end: ");out+='", startencode: "';out+=encodeHTML("}
	}, skip = /$^/;

	function resolveDefs(c, block, def) {
		return ((typeof block === 'string') ? block : block.toString())
		.replace(c.define || skip, function(m, code, assign, value) {
			if (code.indexOf('def.') === 0) {
				code = code.substring(4);
			}
			if (!(code in def)) {
				if (assign === ':') {
					def[code]= value;
				} else {
					eval("def['"+code+"']=" + value);
				}
			}
			return '';
		})
		.replace(c.use || skip, function(m, code) {
			var v = eval(code);
			return v ? resolveDefs(c, v, def) : v;
		});
	}

	function unescape(code) {
		return code.replace(/\\('|\\)/g, "$1").replace(/[\r\t\n]/g, ' ');
	}

	doT.template = function(tmpl, c, def) {
		c = c || doT.templateSettings;
		var cse = c.append ? startend.append : startend.split, str, needhtmlencode, sid=0, indv;

		if (c.use || c.define) {
			var olddef = global.def; global.def = def || {}; // workaround minifiers
			str = resolveDefs(c, tmpl, global.def);
			global.def = olddef;
		} else str = tmpl;

		str = ("var out='" + (c.strip ? str.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g,' ')
					.replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,''): str)
			.replace(/'|\\/g, '\\$&')
			.replace(c.interpolate || skip, function(m, code) {
				return cse.start + unescape(code) + cse.end;
			})
			.replace(c.encode || skip, function(m, code) {
				needhtmlencode = true;
				return cse.startencode + unescape(code) + cse.end;
			})
			.replace(c.conditional || skip, function(m, elsecase, code) {
				return elsecase ?
					(code ? "';}else if(" + unescape(code) + "){out+='" : "';}else{out+='") :
					(code ? "';if(" + unescape(code) + "){out+='" : "';}out+='");
			})
			.replace(c.iterate || skip, function(m, iterate, vname, iname) {
				if (!iterate) return "';} } out+='";
				sid+=1; indv=iname || "i"+sid; iterate=unescape(iterate);
				return "';var arr"+sid+"="+iterate+";if(arr"+sid+"){var "+indv+"=-1,l"+sid+"=arr"+sid+".length-1;while("+indv+"<l"+sid+"){"
					+vname+"=arr"+sid+"["+indv+"+=1];out+='";
			})
			.replace(c.evaluate || skip, function(m, code) {
				return "';" + unescape(code) + "out+='";
			})
			+ "';return out;")
			.replace(/\n/g, '\\n').replace(/\t/g, '\\t').replace(/\r/g, '\\r')
			.replace(/(\s|;|}|^|{)out\+='';/g, '$1').replace(/\+''/g, '')
			.replace(/(\s|;|}|^|{)out\+=''\+/g,'$1out+=');

		if (needhtmlencode && c.selfcontained) {
			str = "var encodeHTML=(" + encodeHTMLSource.toString() + "());" + str;
		}
		try {
			return new Function(c.varname, str);
		} catch (e) {
			if (typeof console !== 'undefined') console.log("Could not create a template function: " + str);
			throw e;
		}
	};

	doT.compile = function(tmpl, def) {
		return doT.template(tmpl, null, def);
	};
}());
<|endoftext|>