<commit_before>var autoscroll = false;

function resourceInfo(name, type) {
  var group = ".build-"+type+"s"

  var resource = $(group).find(".build-source[data-resource='"+name+"']");
  if(resource.length === 0) {
    resource = $("#resource-template .build-source").clone(true).appendTo(group);
    resource.attr("data-resource", name);
    resource.find("h3").text(name);
  }

  return resource;
}

var v1Handlers = {
  "log": function(msg) {
    processLogs(JSON.parse(msg.data));
  },

  "error": function(msg) {
    if (msg.data === undefined) {
      // 'error' event may also be native browser error, unfortunately
      return
    }

    processError(JSON.parse(msg.data));
  },

  "status": function(msg) {
    var event = JSON.parse(msg.data);

    var currentStatus = $("#page-header").attr("class");

    var buildTimes = $(".build-times");

    var status = event.status;
    var m = moment.unix(event.time);

    var time = $("<time>");
    time.text(m.fromNow());
    time.attr("datetime", m.format());
    time.attr("title", m.format("lll Z"));
    time.addClass(status);

    if(status == "started") {
      $("<dt/>").text(status).appendTo(buildTimes);
      $("<dd/>").append(time).appendTo(buildTimes);
    } else {
      $("<dt/>").text(status).appendTo(buildTimes);
      $("<dd/>").append(time).appendTo(buildTimes);

      var startTime = $(".build-times time.started").attr("datetime");

      // Some events cause the build to never start (e.g. input errors).
      var didStart = !!startTime

      if(didStart) {
        var duration = moment.duration(m.diff(moment(startTime)));

        var durationEle = $("<span>");
        durationEle.addClass("duration");
        durationEle.text(duration.format("h[h]m[m]s[s]"));

        $("<dt/>").text("duration").appendTo(buildTimes);
        $("<dd/>").append(durationEle).appendTo(buildTimes);
      }
    }

    // only transition from transient states; state may already be set
    // if the page loaded after build was done
    if(currentStatus != "pending" && currentStatus != "started") {
      return;
    }

    $("#page-header").attr("class", status);
    $("#builds .current").attr("class", status + " current");

    if(status != "started") {
      $(".abort-build").remove();
    }
  },

  "input": function(msg) {
    renderResource(JSON.parse(msg.data), msg.type);
  },

  "output": function(msg) {
    renderResource(JSON.parse(msg.data), msg.type);
  }
}

var eventHandlers = {
  "0.0": {
    "log": function(msg) {
      writeLogs(msg.data, $("#build-log"));
    },
  },

  "1.0": v1Handlers,

  "1.1": v1Handlers,
}

function renderResource(event, type) {
  var resource = event[type];
  var info = resourceInfo(resource.resource, type);

  info.removeClass("running");

  var version = info.find(".version");
  if(version.children().length === 0) {
    for(var key in resource.version) {
      $("<dt/>").text(key).appendTo(version);
      $("<dd/>").text(resource.version[key]).appendTo(version);
    }
  }

  var metadata = info.find(".build-metadata");
  if(metadata.children().length === 0) {
    for(var i in resource.metadata) {
      var field = resource.metadata[i];
      $("<dt/>").text(field.name).appendTo(metadata);
      $("<dd/>").text(field.value).appendTo(metadata);
    }
  }
}

function processLogs(event) {
  var log;

  switch(event.origin.type) {
  case "run":
    log = $("#build-log");
    break;
  case "input":
  case "output":
    var resource = resourceInfo(event.origin.name, event.origin.type);
    if(!resource.hasClass("running"))
      resource.addClass("running");

    log = resource.find(".log")
  }

  if(!log) {
    return;
  }

  writeLogs(event.payload, log);
}

function processError(event) {
  var log;

  var errorSpan = $("<span/>");
  errorSpan.addClass("error");
  errorSpan.text(event.message);

  if(event.origin) {
    switch(event.origin.type) {
    case "input":
    case "output":
      var resource = resourceInfo(event.origin.name, event.origin.type);
      resource.removeClass("running");
      resource.addClass("errored");

      log = resource.find(".log");
    }
  } else {
    log = $("#build-log");
  }

  if(!log) {
    return;
  }

  log.append(errorSpan);
}

var currentLine;
var lineCursor;
var lineToOverwrite;

function overwriteLine(segment) {
  lineCursor.after(segment);

  lineCursor = $(segment);

  var textLen = segment.text().length;
  lineToOverwrite.each(function() {
    var text = $(this).text();

    if(text.length >= textLen) {
      $(this).text(text.substr(textLen));
      return false;
    } else {
      $(this).remove();
      textLen -= text.length;
    }
  });
}

function writeLogs(payload, destination) {
  var sequence = ansiparse(payload);

  var ele;
  for(var i = 0; i < sequence.length; i++) {
    ele = $("<span>");
    ele.text(sequence[i].text);

    if(sequence[i].linebreak) {
      ele.addClass("linebreak");
    }

    if(sequence[i].foreground) {
      ele.addClass("ansi-"+sequence[i].foreground+"-fg");
    }

    if(sequence[i].background) {
      ele.addClass("ansi-"+sequence[i].background+"-bg");
    }

    if(sequence[i].bold) {
      ele.addClass("ansi-bold");
    }

    if(sequence[i].cr && currentLine) {
      lineCursor = currentLine;
      lineToOverwrite = currentLine.nextAll();
    } else if(sequence[i].linebreak) {
      currentLine = ele;
      lineToOverwrite = null;
    }

    if(lineToOverwrite) {
      overwriteLine(ele);
    } else {
      destination.append(ele);
    }
  }

  if (autoscroll) {
    $(document).scrollTop($(document).height());
  }
}

function streamLog(uri) {
  var es = new EventSource(uri);

  var successfullyConnected = false;
  var eventHandler;
  var currentVersion;

  es.addEventListener("version", function(event) {
    successfullyConnected = true;

    if (eventHandler) {
      for (var key in eventHandler) {
        es.removeEventListener(key, eventHandler[key]);
      }
    }

    currentVersion = JSON.parse(event.data);
    eventHandler = eventHandlers[currentVersion];

    for (var key in eventHandler) {
      es.addEventListener(key, eventHandler[key], false);
    }
  });

  es.addEventListener("end", function(event) {
    es.close();
  });

  es.onerror = function(event) {
    if(currentVersion != "1.1") {
      // versions < 1.1 cannot distinguish between end of stream and an
      // interrupted connection
      es.close();
    }

    if(!successfullyConnected) {
      // assume rejected because of auth
      $("#build-requires-auth").show();
    }
  };
}

function scrollToCurrentBuild() {
  var currentBuild = $("#builds .current");
  var buildWidth = currentBuild.width();
  var left = currentBuild.offset().left;

  if((left + buildWidth) > window.innerWidth) {
    $("#builds").scrollLeft(left - buildWidth);
  }
}

$(document).ready(function() {
  var title = $("#page-header");

  if (title.hasClass("pending") || title.hasClass("started")) {
    autoscroll = true;
  }

  $(window).scroll(function() {
    var scrollEnd = $(window).scrollTop() + $(window).height();

    if (scrollEnd >= ($(document).height() - 16)) {
      autoscroll = true;
    } else {
      autoscroll = false;
    }
  });

  $("#builds").bind('mousewheel', function(e){
    if (e.originalEvent.deltaX != 0) {
      $(this).scrollLeft($(this).scrollLeft() + e.originalEvent.deltaX);
    } else {
      $(this).scrollLeft($(this).scrollLeft() - e.originalEvent.deltaY);
    }

    return false;
  });

  $(".build-source .header").click(function() {
    $(this).parent().find(".resource-body").toggle();
  });

  scrollToCurrentBuild();
});
<commit_msg>render errors with no origin in build log<commit_after>var autoscroll = false;

function resourceInfo(name, type) {
  var group = ".build-"+type+"s"

  var resource = $(group).find(".build-source[data-resource='"+name+"']");
  if(resource.length === 0) {
    resource = $("#resource-template .build-source").clone(true).appendTo(group);
    resource.attr("data-resource", name);
    resource.find("h3").text(name);
  }

  return resource;
}

var v1Handlers = {
  "log": function(msg) {
    processLogs(JSON.parse(msg.data));
  },

  "error": function(msg) {
    if (msg.data === undefined) {
      // 'error' event may also be native browser error, unfortunately
      return
    }

    processError(JSON.parse(msg.data));
  },

  "status": function(msg) {
    var event = JSON.parse(msg.data);

    var currentStatus = $("#page-header").attr("class");

    var buildTimes = $(".build-times");

    var status = event.status;
    var m = moment.unix(event.time);

    var time = $("<time>");
    time.text(m.fromNow());
    time.attr("datetime", m.format());
    time.attr("title", m.format("lll Z"));
    time.addClass(status);

    if(status == "started") {
      $("<dt/>").text(status).appendTo(buildTimes);
      $("<dd/>").append(time).appendTo(buildTimes);
    } else {
      $("<dt/>").text(status).appendTo(buildTimes);
      $("<dd/>").append(time).appendTo(buildTimes);

      var startTime = $(".build-times time.started").attr("datetime");

      // Some events cause the build to never start (e.g. input errors).
      var didStart = !!startTime

      if(didStart) {
        var duration = moment.duration(m.diff(moment(startTime)));

        var durationEle = $("<span>");
        durationEle.addClass("duration");
        durationEle.text(duration.format("h[h]m[m]s[s]"));

        $("<dt/>").text("duration").appendTo(buildTimes);
        $("<dd/>").append(durationEle).appendTo(buildTimes);
      }
    }

    // only transition from transient states; state may already be set
    // if the page loaded after build was done
    if(currentStatus != "pending" && currentStatus != "started") {
      return;
    }

    $("#page-header").attr("class", status);
    $("#builds .current").attr("class", status + " current");

    if(status != "started") {
      $(".abort-build").remove();
    }
  },

  "input": function(msg) {
    renderResource(JSON.parse(msg.data), msg.type);
  },

  "output": function(msg) {
    renderResource(JSON.parse(msg.data), msg.type);
  }
}

var eventHandlers = {
  "0.0": {
    "log": function(msg) {
      writeLogs(msg.data, $("#build-log"));
    },
  },

  "1.0": v1Handlers,

  "1.1": v1Handlers,
}

function renderResource(event, type) {
  var resource = event[type];
  var info = resourceInfo(resource.resource, type);

  info.removeClass("running");

  var version = info.find(".version");
  if(version.children().length === 0) {
    for(var key in resource.version) {
      $("<dt/>").text(key).appendTo(version);
      $("<dd/>").text(resource.version[key]).appendTo(version);
    }
  }

  var metadata = info.find(".build-metadata");
  if(metadata.children().length === 0) {
    for(var i in resource.metadata) {
      var field = resource.metadata[i];
      $("<dt/>").text(field.name).appendTo(metadata);
      $("<dd/>").text(field.value).appendTo(metadata);
    }
  }
}

function processLogs(event) {
  var log;

  switch(event.origin.type) {
  case "run":
    log = $("#build-log");
    break;
  case "input":
  case "output":
    var resource = resourceInfo(event.origin.name, event.origin.type);
    if(!resource.hasClass("running"))
      resource.addClass("running");

    log = resource.find(".log")
  }

  if(!log) {
    return;
  }

  writeLogs(event.payload, log);
}

function processError(event) {
  var log;

  var errorSpan = $("<span/>");
  errorSpan.addClass("error");
  errorSpan.text(event.message);

  switch(event.origin.type) {
  case "input":
  case "output":
    var resource = resourceInfo(event.origin.name, event.origin.type);
    resource.removeClass("running");
    resource.addClass("errored");

    log = resource.find(".log");
    break;
  default:
    log = $("#build-log");
    break;
  }

  if(!log) {
    return;
  }

  log.append(errorSpan);
}

var currentLine;
var lineCursor;
var lineToOverwrite;

function overwriteLine(segment) {
  lineCursor.after(segment);

  lineCursor = $(segment);

  var textLen = segment.text().length;
  lineToOverwrite.each(function() {
    var text = $(this).text();

    if(text.length >= textLen) {
      $(this).text(text.substr(textLen));
      return false;
    } else {
      $(this).remove();
      textLen -= text.length;
    }
  });
}

function writeLogs(payload, destination) {
  var sequence = ansiparse(payload);

  var ele;
  for(var i = 0; i < sequence.length; i++) {
    ele = $("<span>");
    ele.text(sequence[i].text);

    if(sequence[i].linebreak) {
      ele.addClass("linebreak");
    }

    if(sequence[i].foreground) {
      ele.addClass("ansi-"+sequence[i].foreground+"-fg");
    }

    if(sequence[i].background) {
      ele.addClass("ansi-"+sequence[i].background+"-bg");
    }

    if(sequence[i].bold) {
      ele.addClass("ansi-bold");
    }

    if(sequence[i].cr && currentLine) {
      lineCursor = currentLine;
      lineToOverwrite = currentLine.nextAll();
    } else if(sequence[i].linebreak) {
      currentLine = ele;
      lineToOverwrite = null;
    }

    if(lineToOverwrite) {
      overwriteLine(ele);
    } else {
      destination.append(ele);
    }
  }

  if (autoscroll) {
    $(document).scrollTop($(document).height());
  }
}

function streamLog(uri) {
  var es = new EventSource(uri);

  var successfullyConnected = false;
  var eventHandler;
  var currentVersion;

  es.addEventListener("version", function(event) {
    successfullyConnected = true;

    if (eventHandler) {
      for (var key in eventHandler) {
        es.removeEventListener(key, eventHandler[key]);
      }
    }

    currentVersion = JSON.parse(event.data);
    eventHandler = eventHandlers[currentVersion];

    for (var key in eventHandler) {
      es.addEventListener(key, eventHandler[key], false);
    }
  });

  es.addEventListener("end", function(event) {
    es.close();
  });

  es.onerror = function(event) {
    if(currentVersion != "1.1") {
      // versions < 1.1 cannot distinguish between end of stream and an
      // interrupted connection
      es.close();
    }

    if(!successfullyConnected) {
      // assume rejected because of auth
      $("#build-requires-auth").show();
    }
  };
}

function scrollToCurrentBuild() {
  var currentBuild = $("#builds .current");
  var buildWidth = currentBuild.width();
  var left = currentBuild.offset().left;

  if((left + buildWidth) > window.innerWidth) {
    $("#builds").scrollLeft(left - buildWidth);
  }
}

$(document).ready(function() {
  var title = $("#page-header");

  if (title.hasClass("pending") || title.hasClass("started")) {
    autoscroll = true;
  }

  $(window).scroll(function() {
    var scrollEnd = $(window).scrollTop() + $(window).height();

    if (scrollEnd >= ($(document).height() - 16)) {
      autoscroll = true;
    } else {
      autoscroll = false;
    }
  });

  $("#builds").bind('mousewheel', function(e){
    if (e.originalEvent.deltaX != 0) {
      $(this).scrollLeft($(this).scrollLeft() + e.originalEvent.deltaX);
    } else {
      $(this).scrollLeft($(this).scrollLeft() - e.originalEvent.deltaY);
    }

    return false;
  });

  $(".build-source .header").click(function() {
    $(this).parent().find(".resource-body").toggle();
  });

  scrollToCurrentBuild();
});
<|endoftext|>


<commit_before>'use strict'

let io = null
let connectionInfo
let pingInfo
let states = []

function setPingInfo(ping) {
    pingInfo.text = 'Ping: ' + ping
    let fill
    if (ping < 100)
        fill = 0x57fc20
    else if (ping < 200)
        fill = 0xfc9520
    else
        fill = 0xef1c2a
    pingInfo.style.fill = fill
}

let ownId
function connect(address) {
    io = new WebSocket(address)
    io.onopen = () => {
        resetWait()
        connectionInfo.visible = false
    };

    io.onmessage = (serializedMsg) => {
        const msg = JSON.parse(serializedMsg.data, (key, value) => value === "" ? 0 : value)

        switch (msg.opcode) {
            case 'Greeting':
                ownId = msg.payload[0]
                const actors = msg.payload[1]

                for (let actor of actors) {
                    spawnActor(actor)
                }
                break;
            case 'Connect':
                const player = {id: msg.payload.id, kind: "Player"}
                spawnActor(player)
                break;
            case 'Disconnect':
                removeActor(msg.payload)
                break;
            case 'WorldUpdate':
                const state = {}
                state.actors = msg.payload
                state.timestamp = Date.now()
                states.push(state)
                // Todo: Exchange for real queue library
                setTimeout(states.shift, 100)
                break;
            default:
                throw 'Received invalid opcode: ' + msg.opcode
        }
    }

    io.onclose = () => {
        connectionInfo.text = 'Attempting to reconnect'
        connectionInfo.visible = true
        io = null
        setTimeout(() => {
            incrementWait()
            connect(address);
        }, wait)
    };

    io.onerror = () => {
        connectionInfo.text = 'Lost connection to server'
        connectionInfo.visible = true
        for (let id of Object.keys(actors))
            removeActor(id)
        io.close()
        io = null
    };
}

const MIN_WAIT = 100
let wait = MIN_WAIT

function resetWait() {
    wait = MIN_WAIT
}

function incrementWait() {
    const MAX_WAIT = 2000
    if (wait < MAX_WAIT)
        wait *= 1.25
    else
        wait = MAX_WAIT
}

function send(data) {
    if (io && io.readyState === 1) {
        console.log('sending data: ', data)
        io.send(JSON.stringify(data))
    }
}

const Application = PIXI.Application,
    loader = PIXI.loader,
    resources = PIXI.loader.resources,
    Sprite = PIXI.Sprite

const GAME_WIDTH = 1000
const GAME_HEIGHT = 1000
const app = new Application(
    screen.availWidth, screen.availHeight, {
        backgroundColor: 0xFFFFFF,
        antialias: true,
    },
)

document.body.appendChild(app.view)

loader
    .add([{
        name: 'pong',
        url: 'assets/pong.json'
    }, ])
    .on('progress', loadProgressHandler)
    .load(setup)

let validKeys = ["ArrowUp", "ArrowDown"]
let keyPressed = {
    ArrowLeft: false,
    ArrowRight: false
}
document.addEventListener("keydown", (event) => {
    sendKeyWithVal(event.key, true)
})
document.addEventListener("keyup", (event) => {
    sendKeyWithVal(event.key, false)
})

function sendKeyWithVal(key, val) {
    if (validKeys.indexOf(key) > -1) {
        sendIfNew(key, val)
    }
}

let msgId = 0

function sendIfNew(key, val) {
    if (keyPressed[key] !== val) {
        keyPressed[key] = val
        let msg = {
            id: msgId,
            key: key,
            pressed: val
        }
        msgId++
        send(msg)
    }
}

function loadProgressHandler(loader, resource) {
    console.log('loading: ' + resource.name + ' (' + resource.url + ')')
    console.log('progress: ' + loader.progress + '%')
    if (resource.error)
        console.error(resource.error)
}

function setup() {
    const background = new Sprite(resources.pong.textures['fancy-court.png'])
    background.width = GAME_WIDTH
    background.height = GAME_HEIGHT
    app.stage.addChild(background)

    connectionInfo = new PIXI.Text('')
    connectionInfo.style.fill = 0xe3e3ed
    connectionInfo.style.dropShadow = true
    connectionInfo.style.dropShadowAlpha = 0.7
    connectionInfo.y = 30
    connectionInfo.x = GAME_WIDTH - 300
    app.stage.addChild(connectionInfo)

    pingInfo = new PIXI.Text('Ping: Calculating...')
    pingInfo.style.fill = 0xe3e3ed
    pingInfo.style.dropShadow = true
    pingInfo.style.dropShadowAlpha = 0.7
    pingInfo.y = 30
    pingInfo.x = 40
    app.stage.addChild(pingInfo)

    resize()
    window.addEventListener('resize', resize);

    setInterval(() => setPingInfo(getOwnPing()), 1000)
    const addr = window.location.hostname === 'localhost' ? 'ws://localhost:8081' : 'wss://beta.jnferner.com/socket'
    connect(addr)
    app.ticker.add(gameLoop)
}

function getOwnPing() {
    if (states.len === 0 || !ownId)
        return 0
    const players = states[states.length - 1].actors
    return players[ownId].delay
}

function resize() {
    let ratio = window.innerWidth / GAME_WIDTH
    if (GAME_HEIGHT * ratio > window.innerHeight)
        ratio = window.innerHeight / GAME_HEIGHT
    app.width = app.stage.width = GAME_WIDTH * ratio
    app.height = app.stage.height = GAME_HEIGHT * ratio
}

let state = connecting

function gameLoop(delta) {
    state()
}

function connecting() {
    const txt = 'Connecting...'
    if (connectionInfo.text != txt) {
        connectionInfo.text = txt
        connectionInfo.visible = true
    }

    const renderTime = getRenderTime(getOwnPing())
    const index = getIndexOfRenderState(states, renderTime)
    if (index >= 0) {
        connectionInfo.visible = false
        state = play
    }
}

function play() {
    render(states)
}

function render(states) {
    const renderTime = getRenderTime(getOwnPing())
    const index = getIndexOfRenderState(states, renderTime)
    if (index < 0)
        return
    let interpolatedState = getInterpolatedState(states[index], states[index + 1], renderTime)
    setWorld(interpolatedState)
}

function getRenderTime(ping) {
    const now = new Date().getTime()
    const minDelay = 100
    const maxDelay = 300
    const delay = Math.max(minDelay, Math.min(maxDelay, ping))
    return now - delay
}

function getIndexOfRenderState(states, renderTime) {
    const found = states.findIndex((state) => state.timestamp >= renderTime)
    return found - 1
}

function getInterpolatedState(from, to, renderTime) {
    const total = to.timestamp - from.timestamp
    const progress = renderTime - from.timestamp
    if (total === 0 || progress === 0)
        return from
    const fraction = progress / total
    let state = JSON.parse(JSON.stringify(from)).actors
    for (let id of Object.keys(state)) {
        const actor = state[id]
        const toActor = to[id]
        if (!toActor)
            continue
        const fromActor = from[id]

        actor.pos.x += (toActor.pos.x - fromActor.pos.x) * fraction
        actor.pos.y += (toActor.pos.y - fromActor.pos.y) * fraction
        actor.vel.x += (toActor.vel.x - fromActor.vel.x) * fraction
        actor.vel.y += (toActor.vel.y - fromActor.vel.y) * fraction
    }
    state.timestamp = renderTime
    return state
}

let actors = {}
function setWorld(state) {
    for (let id of Object.keys(state)) {
        const liveActor = actors[id]
        const stateActor = state[id]
        if (!liveActor || !stateActor)
            continue
        liveActor.x = stateActor.pos.x
        liveActor.y = stateActor.pos.y
        if (stateActor.vel)
            addBlur(liveActor, stateActor.vel)
    }
}

function addBlur(obj, vel) {
    const maxVel = Math.max(vel.x, vel.y)
    const strength = Math.pow(Math.atan(Math.pow((maxVel / 10), 1.5)), 2) - 0.2
    if (strength > 0.5) {
        const blurFilter = new PIXI.filters.BlurFilter(strength, 1, 1)
        obj.filters = [blurFilter]
    }
}

function spawnActor(actor) {
    let texture
    switch (actor.kind) {
        case "Player":
            texture = 'fancy-paddle-green.png'
            break;
        case "Ball":
            texture = 'fancy-ball.png'
            break;
        default:
            throw 'Tried to spawn invalid kind of actor: ' + actor.kind
    }
    const sprite = new Sprite(resources.pong.textures[texture])
    sprite.anchor.set(0.5)
    app.stage.addChild(sprite)
    actors[actor.id] = sprite
}

function removeActor(id) {
    const actor = actors[id]
    app.stage.removeChild(actor)
    delete actors[id]
}<commit_msg>Client: Fix nullcheck<commit_after>'use strict'

let io = null
let connectionInfo
let pingInfo
let states = []

function setPingInfo(ping) {
    pingInfo.text = 'Ping: ' + ping
    let fill
    if (ping < 100)
        fill = 0x57fc20
    else if (ping < 200)
        fill = 0xfc9520
    else
        fill = 0xef1c2a
    pingInfo.style.fill = fill
}

let ownId
function connect(address) {
    io = new WebSocket(address)
    io.onopen = () => {
        resetWait()
        connectionInfo.visible = false
    };

    io.onmessage = (serializedMsg) => {
        const msg = JSON.parse(serializedMsg.data, (key, value) => value === "" ? 0 : value)

        switch (msg.opcode) {
            case 'Greeting':
                ownId = msg.payload[0]
                const actors = msg.payload[1]

                for (let actor of actors) {
                    spawnActor(actor)
                }
                break;
            case 'Connect':
                const player = {id: msg.payload.id, kind: "Player"}
                spawnActor(player)
                break;
            case 'Disconnect':
                removeActor(msg.payload)
                break;
            case 'WorldUpdate':
                const state = {}
                state.actors = msg.payload
                state.timestamp = Date.now()
                states.push(state)
                // Todo: Exchange for real queue library
                setTimeout(states.shift, 100)
                break;
            default:
                throw 'Received invalid opcode: ' + msg.opcode
        }
    }

    io.onclose = () => {
        connectionInfo.text = 'Attempting to reconnect'
        connectionInfo.visible = true
        io = null
        setTimeout(() => {
            incrementWait()
            connect(address);
        }, wait)
    };

    io.onerror = () => {
        connectionInfo.text = 'Lost connection to server'
        connectionInfo.visible = true
        for (let id of Object.keys(actors))
            removeActor(id)
        io.close()
        io = null
    };
}

const MIN_WAIT = 100
let wait = MIN_WAIT

function resetWait() {
    wait = MIN_WAIT
}

function incrementWait() {
    const MAX_WAIT = 2000
    if (wait < MAX_WAIT)
        wait *= 1.25
    else
        wait = MAX_WAIT
}

function send(data) {
    if (io && io.readyState === 1) {
        console.log('sending data: ', data)
        io.send(JSON.stringify(data))
    }
}

const Application = PIXI.Application,
    loader = PIXI.loader,
    resources = PIXI.loader.resources,
    Sprite = PIXI.Sprite

const GAME_WIDTH = 1000
const GAME_HEIGHT = 1000
const app = new Application(
    screen.availWidth, screen.availHeight, {
        backgroundColor: 0xFFFFFF,
        antialias: true,
    },
)

document.body.appendChild(app.view)

loader
    .add([{
        name: 'pong',
        url: 'assets/pong.json'
    }, ])
    .on('progress', loadProgressHandler)
    .load(setup)

let validKeys = ["ArrowUp", "ArrowDown"]
let keyPressed = {
    ArrowLeft: false,
    ArrowRight: false
}
document.addEventListener("keydown", (event) => {
    sendKeyWithVal(event.key, true)
})
document.addEventListener("keyup", (event) => {
    sendKeyWithVal(event.key, false)
})

function sendKeyWithVal(key, val) {
    if (validKeys.indexOf(key) > -1) {
        sendIfNew(key, val)
    }
}

let msgId = 0

function sendIfNew(key, val) {
    if (keyPressed[key] !== val) {
        keyPressed[key] = val
        let msg = {
            id: msgId,
            key: key,
            pressed: val
        }
        msgId++
        send(msg)
    }
}

function loadProgressHandler(loader, resource) {
    console.log('loading: ' + resource.name + ' (' + resource.url + ')')
    console.log('progress: ' + loader.progress + '%')
    if (resource.error)
        console.error(resource.error)
}

function setup() {
    const background = new Sprite(resources.pong.textures['fancy-court.png'])
    background.width = GAME_WIDTH
    background.height = GAME_HEIGHT
    app.stage.addChild(background)

    connectionInfo = new PIXI.Text('')
    connectionInfo.style.fill = 0xe3e3ed
    connectionInfo.style.dropShadow = true
    connectionInfo.style.dropShadowAlpha = 0.7
    connectionInfo.y = 30
    connectionInfo.x = GAME_WIDTH - 300
    app.stage.addChild(connectionInfo)

    pingInfo = new PIXI.Text('Ping: Calculating...')
    pingInfo.style.fill = 0xe3e3ed
    pingInfo.style.dropShadow = true
    pingInfo.style.dropShadowAlpha = 0.7
    pingInfo.y = 30
    pingInfo.x = 40
    app.stage.addChild(pingInfo)

    resize()
    window.addEventListener('resize', resize);

    setInterval(() => setPingInfo(getOwnPing()), 1000)
    const addr = window.location.hostname === 'localhost' ? 'ws://localhost:8081' : 'wss://beta.jnferner.com/socket'
    connect(addr)
    app.ticker.add(gameLoop)
}

function getOwnPing() {
    if (states.length === 0 || !ownId)
        return 0
    const players = states[states.length - 1].actors
    return players[ownId].delay
}

function resize() {
    let ratio = window.innerWidth / GAME_WIDTH
    if (GAME_HEIGHT * ratio > window.innerHeight)
        ratio = window.innerHeight / GAME_HEIGHT
    app.width = app.stage.width = GAME_WIDTH * ratio
    app.height = app.stage.height = GAME_HEIGHT * ratio
}

let state = connecting

function gameLoop(delta) {
    state()
}

function connecting() {
    const txt = 'Connecting...'
    if (connectionInfo.text != txt) {
        connectionInfo.text = txt
        connectionInfo.visible = true
    }

    const renderTime = getRenderTime(getOwnPing())
    const index = getIndexOfRenderState(states, renderTime)
    if (index >= 0) {
        connectionInfo.visible = false
        state = play
    }
}

function play() {
    render(states)
}

function render(states) {
    const renderTime = getRenderTime(getOwnPing())
    const index = getIndexOfRenderState(states, renderTime)
    if (index < 0)
        return
    let interpolatedState = getInterpolatedState(states[index], states[index + 1], renderTime)
    setWorld(interpolatedState)
}

function getRenderTime(ping) {
    const now = new Date().getTime()
    const minDelay = 100
    const maxDelay = 300
    const delay = Math.max(minDelay, Math.min(maxDelay, ping))
    return now - delay
}

function getIndexOfRenderState(states, renderTime) {
    const found = states.findIndex((state) => state.timestamp >= renderTime)
    return found - 1
}

function getInterpolatedState(from, to, renderTime) {
    const total = to.timestamp - from.timestamp
    const progress = renderTime - from.timestamp
    if (total === 0 || progress === 0)
        return from
    const fraction = progress / total
    let state = JSON.parse(JSON.stringify(from)).actors
    for (let id of Object.keys(state)) {
        const actor = state[id]
        const toActor = to[id]
        if (!toActor)
            continue
        const fromActor = from[id]

        actor.pos.x += (toActor.pos.x - fromActor.pos.x) * fraction
        actor.pos.y += (toActor.pos.y - fromActor.pos.y) * fraction
        actor.vel.x += (toActor.vel.x - fromActor.vel.x) * fraction
        actor.vel.y += (toActor.vel.y - fromActor.vel.y) * fraction
    }
    state.timestamp = renderTime
    return state
}

let actors = {}
function setWorld(state) {
    for (let id of Object.keys(state)) {
        const liveActor = actors[id]
        const stateActor = state[id]
        if (!liveActor || !stateActor)
            continue
        liveActor.x = stateActor.pos.x
        liveActor.y = stateActor.pos.y
        if (stateActor.vel)
            addBlur(liveActor, stateActor.vel)
    }
}

function addBlur(obj, vel) {
    const maxVel = Math.max(vel.x, vel.y)
    const strength = Math.pow(Math.atan(Math.pow((maxVel / 10), 1.5)), 2) - 0.2
    if (strength > 0.5) {
        const blurFilter = new PIXI.filters.BlurFilter(strength, 1, 1)
        obj.filters = [blurFilter]
    }
}

function spawnActor(actor) {
    let texture
    switch (actor.kind) {
        case "Player":
            texture = 'fancy-paddle-green.png'
            break;
        case "Ball":
            texture = 'fancy-ball.png'
            break;
        default:
            throw 'Tried to spawn invalid kind of actor: ' + actor.kind
    }
    const sprite = new Sprite(resources.pong.textures[texture])
    sprite.anchor.set(0.5)
    app.stage.addChild(sprite)
    actors[actor.id] = sprite
}

function removeActor(id) {
    const actor = actors[id]
    app.stage.removeChild(actor)
    delete actors[id]
}<|endoftext|>


<commit_before>
function init() {
  var prop;
  for (prop in window) {
    if (prop.match(/test/) && typeof window[prop] == "function" && prop != "testEquals") {
      dwr.util.addOptions("buttons", [ prop ], function(data) {
        return "<button onclick='dwr.util.setValue(\"output\", \"\"); " + prop + "()'>" + prop.substring(4) + "</button>";
        // return "<input name='submit' type='image' src='imagebutton.png' onclick='dwr.util.setValue(\"output\", \"\"); " + prop + "()' />";
      });
    }
  }
}

function success(message) {
  var output = $('output').innerHTML + "
\n" + message;
  dwr.util.setValue('output', output);
}

function failure(message) {
  alert(message);
}

function testError1() {
  var counter = 0;
  var exceptionHandler = function(message, ex) {
    if (message == null) failure("message is null");
    else if (ex == null) failure("ex is null");
    else if (ex.message == null) failure("ex.message is null");
    else if (ex.message != message) failure("ex.message [" + ex.message + "] != message [" + message + "]");
    else if (ex.name != "java.lang.NullPointerException") failure("ex.name is not NPE [" + ex.name + "]");
    else counter++;
  };
  var warningHandler = function(data) {
    failure("Wrong call of warningHandler with data: " + data);
  };
  var callback = function(data) {
    failure("Wrong call of callback with data: " + data);
  };
  var errorHandler = function(data) {
    failure("Wrong call of errorHandler with data: " + data);
  };
  var callData = {
    callback:callback,
    errorHandler:errorHandler,
    warningHandler:warningHandler,
    exceptionHandler:exceptionHandler
  };

  callData.httpMethod = "POST";
  callData.rpcType = dwr.engine.XMLHttpRequest;
  Test.throwNPE(callData);

  callData.rpcType = dwr.engine.IFrame;
  Test.throwNPE(callData);

  callData.rpcType = dwr.engine.ScriptTag;
  Test.throwNPE(callData);

  callData.httpMethod = "GET";
  callData.rpcType = dwr.engine.XMLHttpRequest;
  Test.throwNPE(callData);

  callData.rpcType = dwr.engine.IFrame;
  Test.throwNPE(callData);

  callData.rpcType = dwr.engine.ScriptTag;
  callData.exceptionHandler = function(message, ex) {
    exceptionHandler(message, ex);
    if (counter != 5) failure("Some errors did not complete (Sync issue?) counter = " + counter);
    else success("Error test passed");
  };
  Test.throwNPE(callData);
}

function testAsyncNesting() {
  Test.slowStringParam("AsyncNesting-2", 100, function(data1) {
    success(data1);
    Test.slowStringParam("AsyncNesting-End", 200, function(data2) {
      success(data2);
    });
    success("AsyncNesting-3");
  });
  success("AsyncNesting-1");
}

function testSyncNesting() {
  dwr.engine.setAsync(false);
  Test.slowStringParam("SyncNesting-1", 100, function(data1) {
    success(data1);
    Test.slowStringParam("SyncNesting-2", 100, function(data2) {
      success(data2);
    });
    success("SyncNesting-3");
  });
  success("SyncNesting-End");
  dwr.engine.setAsync(true);
}

function testSyncInCallMetaData() {
  Test.slowStringParam("SyncInCallMetaData-1", 100, {
    async:false,
    callback:function(data) {
      success(data);
    }
  });
  success("SyncInCallMetaData-End");
}

function testAsyncInCallMetaData() {
  Test.slowStringParam("AsyncInCallMetaData-End", 100, {
    async:true,
    callback:function(data) {
      success(data);
    }
  });
  success("AsyncInCallMetaData-1");
}

function testDefaultAsyncInCallMetaData() {
  Test.slowStringParam("DefaultAsyncInCallMetaData-End", 100, {
    callback:function(data) {
      success(data);
    }
  });
  success("DefaultAsyncInCallMetaData-1");
}
<commit_msg>better error handling tests<commit_after>
function init() {
  var prop;
  for (prop in window) {
    if (prop.match(/test/) && typeof window[prop] == "function" && prop != "testEquals") {
      dwr.util.addOptions("buttons", [ prop ], function(data) {
        return "<button onclick='dwr.util.setValue(\"output\", \"\"); " + prop + "()'>" + prop.substring(4) + "</button>";
        // return "<input name='submit' type='image' src='imagebutton.png' onclick='dwr.util.setValue(\"output\", \"\"); " + prop + "()' />";
      });
    }
  }
}

function success(message) {
  var output = $('output').innerHTML + "
\n" + message;
  dwr.util.setValue('output', output);
}

function failure(message) {
  alert(message);
}

function testError1() {
  var counter = 0;
  var exceptionHandler = function(message, ex) {
    if (message == null) failure("message is null");
    else if (ex == null) failure("ex is null");
    else if (ex.message == null) failure("ex.message is null");
    else if (ex.message != message) failure("ex.message [" + ex.message + "] != message [" + message + "]");
    else if (ex.javaClassName != "java.lang.NullPointerException") failure("ex.name is not NPE [" + ex.name + "]");
    else counter++;
  };
  var warningHandler = function(data) {
    failure("Wrong call of warningHandler with data: " + data);
  };
  var callback = function(data) {
    failure("Wrong call of callback with data: " + data);
  };
  var errorHandler = function(data) {
    failure("Wrong call of errorHandler with data: " + data);
  };
  var callData = {
    callback:callback,
    errorHandler:errorHandler,
    warningHandler:warningHandler,
    exceptionHandler:exceptionHandler
  };

  callData.httpMethod = "POST";
  callData.rpcType = dwr.engine.XMLHttpRequest;
  Test.throwNPE(callData);

  callData.rpcType = dwr.engine.IFrame;
  Test.throwNPE(callData);

  callData.rpcType = dwr.engine.ScriptTag;
  Test.throwNPE(callData);

  callData.httpMethod = "GET";
  callData.rpcType = dwr.engine.XMLHttpRequest;
  Test.throwNPE(callData);

  callData.rpcType = dwr.engine.IFrame;
  Test.throwNPE(callData);

  callData.rpcType = dwr.engine.ScriptTag;
  callData.exceptionHandler = function(message, ex) {
    exceptionHandler(message, ex);
    if (counter != 5) failure("Some errors did not complete (Sync issue?) counter = " + counter);
    else success("Error test passed");
  };
  Test.throwNPE(callData);
}

function testError2() {
  var incorrectHandler = function(data) {
    failure("Wrong call of warningHandler with data: " + data + ". See console for more");
    dwr.engine._debug("Wrong call of warningHandler with data: " + data, true);
  }
  dwr.engine.setWarningHandler(incorrectHandler);
  var counter = 0;
  var correctHandler = function(data) {
    counter++;
  };
  var temp = dwr.engine._errorHandler;

  // Test exceptions bouncing to global errors
  dwr.engine.setErrorHandler(correctHandler);
  Test.throwNPE();

  // Test exceptions bouncing to batch errors
  dwr.engine.setErrorHandler(incorrectHandler);
  dwr.engine.beginBatch();
  Test.throwNPE();
  dwr.engine.endBatch({
    errorHandler:correctHandler,
    warningHandler:incorrectHandler
  });

  // Test exceptions bouncing to call errors
  Test.throwNPE({
    errorHandler:function(data) {
      correctHandler(data);
      if (counter != 3) failure("Some errors did not complete (Sync issue?) counter = " + counter);
      else success("Error test passed");
    },
    warningHandler:incorrectHandler
  });

  dwr.engine.setErrorHandler(temp);
}

function testAsyncNesting() {
  Test.slowStringParam("AsyncNesting-2", 100, function(data1) {
    success(data1);
    Test.slowStringParam("AsyncNesting-End", 200, function(data2) {
      success(data2);
    });
    success("AsyncNesting-3");
  });
  success("AsyncNesting-1");
}

function testSyncNesting() {
  dwr.engine.setAsync(false);
  Test.slowStringParam("SyncNesting-1", 100, function(data1) {
    success(data1);
    Test.slowStringParam("SyncNesting-2", 100, function(data2) {
      success(data2);
    });
    success("SyncNesting-3");
  });
  success("SyncNesting-End");
  dwr.engine.setAsync(true);
}

function testSyncInCallMetaData() {
  Test.slowStringParam("SyncInCallMetaData-1", 100, {
    async:false,
    callback:function(data) {
      success(data);
    }
  });
  success("SyncInCallMetaData-End");
}

function testAsyncInCallMetaData() {
  Test.slowStringParam("AsyncInCallMetaData-End", 100, {
    async:true,
    callback:function(data) {
      success(data);
    }
  });
  success("AsyncInCallMetaData-1");
}

function testDefaultAsyncInCallMetaData() {
  Test.slowStringParam("DefaultAsyncInCallMetaData-End", 100, {
    callback:function(data) {
      success(data);
    }
  });
  success("DefaultAsyncInCallMetaData-1");
}
<|endoftext|>


<commit_before>/* Copyright 2012 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const DEFAULT_VIEW_HISTORY_CACHE_SIZE = 20;

/**
 * View History - This is a utility for saving various view parameters for
 *                recently opened files.
 *
 * The way that the view parameters are stored depends on how PDF.js is built,
 * for 'gulp <flag>' the following cases exist:
 *  - FIREFOX or MOZCENTRAL - uses sessionStorage.
 *  - GENERIC or CHROME     - uses localStorage, if it is available.
 */
class ViewHistory {
  constructor(fingerprint, cacheSize = DEFAULT_VIEW_HISTORY_CACHE_SIZE) {
    this.fingerprint = fingerprint;
    this.cacheSize = cacheSize;

    this._initializedPromise = this._readFromStorage().then((databaseStr) => {
      let database = JSON.parse(databaseStr || '{}');
      if (!('files' in database)) {
        database.files = [];
      }
      if (database.files.length >= this.cacheSize) {
        database.files.shift();
      }
      let index;
      for (let i = 0, length = database.files.length; i < length; i++) {
        let branch = database.files[i];
        if (branch.fingerprint === this.fingerprint) {
          index = i;
          break;
        }
      }
      if (typeof index !== 'number') {
        index = database.files.push({ fingerprint: this.fingerprint, }) - 1;
      }
      this.file = database.files[index];
      this.database = database;
    });
  }

  _writeToStorage() {
    return new Promise((resolve) => {
      let databaseStr = JSON.stringify(this.database);

      if (typeof PDFJSDev !== 'undefined' &&
          PDFJSDev.test('FIREFOX || MOZCENTRAL')) {
        sessionStorage.setItem('pdfjs.history', databaseStr);
      } else {
        localStorage.setItem('pdfjs.history', databaseStr);
      }
      resolve();
    });
  }

  _readFromStorage() {
    return new Promise(function(resolve) {
      if (typeof PDFJSDev !== 'undefined' &&
          PDFJSDev.test('FIREFOX || MOZCENTRAL')) {
        resolve(sessionStorage.getItem('pdfjs.history'));
      } else {
        let value = localStorage.getItem('pdfjs.history');

        // TODO: Remove this key-name conversion after a suitable time-frame.
        // Note that we only remove the old 'database' entry if it looks like
        // it was created by PDF.js, to avoid removing someone else's data.
        if (!value) {
          let databaseStr = localStorage.getItem('database');
          if (databaseStr) {
            try {
              let database = JSON.parse(databaseStr);
              if (typeof database.files[0].fingerprint === 'string') {
                localStorage.setItem('pdfjs.history', databaseStr);
                localStorage.removeItem('database');
                value = databaseStr;
              }
            } catch (ex) { }
          }
        }
        resolve(value);
      }
    });
  }

  set(name, val) {
    return this._initializedPromise.then(() => {
      this.file[name] = val;
      return this._writeToStorage();
    });
  }

  setMultiple(properties) {
    return this._initializedPromise.then(() => {
      for (let name in properties) {
        this.file[name] = properties[name];
      }
      return this._writeToStorage();
    });
  }

  get(name, defaultValue) {
    return this._initializedPromise.then(() => {
      let val = this.file[name];
      return val !== undefined ? val : defaultValue;
    });
  }

  getMultiple(properties) {
    return this._initializedPromise.then(() => {
      let values = Object.create(null);

      for (let name in properties) {
        let val = this.file[name];
        values[name] = val !== undefined ? val : properties[name];
      }
      return values;
    });
  }
}

export {
  ViewHistory,
};
<commit_msg>Remove the migration code for old localStorage data in `ViewHistory`<commit_after>/* Copyright 2012 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const DEFAULT_VIEW_HISTORY_CACHE_SIZE = 20;

/**
 * View History - This is a utility for saving various view parameters for
 *                recently opened files.
 *
 * The way that the view parameters are stored depends on how PDF.js is built,
 * for 'gulp <flag>' the following cases exist:
 *  - FIREFOX or MOZCENTRAL - uses sessionStorage.
 *  - GENERIC or CHROME     - uses localStorage, if it is available.
 */
class ViewHistory {
  constructor(fingerprint, cacheSize = DEFAULT_VIEW_HISTORY_CACHE_SIZE) {
    this.fingerprint = fingerprint;
    this.cacheSize = cacheSize;

    this._initializedPromise = this._readFromStorage().then((databaseStr) => {
      let database = JSON.parse(databaseStr || '{}');
      if (!('files' in database)) {
        database.files = [];
      }
      if (database.files.length >= this.cacheSize) {
        database.files.shift();
      }
      let index;
      for (let i = 0, length = database.files.length; i < length; i++) {
        let branch = database.files[i];
        if (branch.fingerprint === this.fingerprint) {
          index = i;
          break;
        }
      }
      if (typeof index !== 'number') {
        index = database.files.push({ fingerprint: this.fingerprint, }) - 1;
      }
      this.file = database.files[index];
      this.database = database;
    });
  }

  _writeToStorage() {
    return new Promise((resolve) => {
      let databaseStr = JSON.stringify(this.database);

      if (typeof PDFJSDev !== 'undefined' &&
          PDFJSDev.test('FIREFOX || MOZCENTRAL')) {
        sessionStorage.setItem('pdfjs.history', databaseStr);
      } else {
        localStorage.setItem('pdfjs.history', databaseStr);
      }
      resolve();
    });
  }

  _readFromStorage() {
    return new Promise(function(resolve) {
      if (typeof PDFJSDev !== 'undefined' &&
          PDFJSDev.test('FIREFOX || MOZCENTRAL')) {
        resolve(sessionStorage.getItem('pdfjs.history'));
      } else {
        resolve(localStorage.getItem('pdfjs.history'));
      }
    });
  }

  set(name, val) {
    return this._initializedPromise.then(() => {
      this.file[name] = val;
      return this._writeToStorage();
    });
  }

  setMultiple(properties) {
    return this._initializedPromise.then(() => {
      for (let name in properties) {
        this.file[name] = properties[name];
      }
      return this._writeToStorage();
    });
  }

  get(name, defaultValue) {
    return this._initializedPromise.then(() => {
      let val = this.file[name];
      return val !== undefined ? val : defaultValue;
    });
  }

  getMultiple(properties) {
    return this._initializedPromise.then(() => {
      let values = Object.create(null);

      for (let name in properties) {
        let val = this.file[name];
        values[name] = val !== undefined ? val : properties[name];
      }
      return values;
    });
  }
}

export {
  ViewHistory,
};
<|endoftext|>


<commit_before>var $ = require('jquery');

(function() {
   var filterSymbol = function(value) {
      return value.replace(/[^\d.]/g, '');
   };

   $(document).on('focus', '.jsCurrency', function() {
      var elem = $(this),
          val = filterSymbol(elem.val());

      // If zero value, clear input for user
      if (parseFloat(val) === 0) {
         val = '';
      }

      elem.val(val);
   });

   $(document).on('blur', '.jsCurrency', function() {
      var elem = $(this),
          val = elem.val();

      // Trim to float, e.g. 2112.123, then format to
      // 2 decimal places, e.g. 212.12, rounding as needed.
      val = parseFloat(val).toFixed(2);

      elem.val('$' + val);
   });
})();
<commit_msg>Force to zero if parsed value is NaN<commit_after>var $ = require('jquery');

(function() {
   var filterSymbol = function(value) {
      return value.replace(/[^\d.]/g, '');
   };

   $(document).on('focus', '.jsCurrency', function() {
      var elem = $(this),
          val = filterSymbol(elem.val());

      // If zero value, clear input for user
      if (parseFloat(val) === 0) {
         val = '';
      }

      elem.val(val);
   });

   $(document).on('blur', '.jsCurrency', function() {
      var elem = $(this),
          val = elem.val();

      // Trim to float, e.g. 2112.123, then format to
      // 2 decimal places, e.g. 212.12, rounding as needed.
      val = parseFloat(val) || 0;
      val = val.toFixed(2);

      elem.val('$' + val);
   });
})();
<|endoftext|>


<commit_before>/* Copyright (c) 2016 Jason Ish
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

class EveBoxApi {

    constructor($window) {
        this.$window = $window;
    }

    downloadPcap(what, event) {
        let url = "/eve2pcap?what=" + what + "&event=" +
            encodeURIComponent(JSON.stringify(event));
        this.$window.location = url;
    }

}

EveBoxApi.$inject = ["$window"];

angular.module("app").service("EveBoxApi", EveBoxApi);
<commit_msg>fix pcap downloads when evebox is behind reverse proxy<commit_after>/* Copyright (c) 2016 Jason Ish
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

class EveBoxApi {

    constructor($window) {
        this.$window = $window;
    }

    downloadPcap(what, event) {
        let url = this.$window.location.pathname
            + "eve2pcap?what="
            + what
            + "&event="
            + encodeURIComponent(JSON.stringify(event));
        this.$window.location = url;
    }

}

EveBoxApi.$inject = ["$window"];

angular.module("app").service("EveBoxApi", EveBoxApi);
<|endoftext|>


<commit_before>

function Login_Page_Loaded(){

}

function Login_Return(){
    if (xmlhttp.readyState==4){
	Login_Form.style.display = "none";
	if(xmlhttp.status==200){
	    stuff.innerHTML("Welcome "+uname);
	}
	if(xmlhttp.status==500||xmlhttp.status==400){
	    stuff.innerHTML = stuff.innerHTML+xmlhttp.responseText;
	}
	else{
	    stuff.innerHTML="Faute d'erreur! Grave! Grave!!";
	}
    }
}

function Login(){
    Login_Form = window.document.getElementById("LoginForm");
    stuff = window.document.getElementById("stuff");
    uname = window.document.getElementById("uname").value;
    pass = window.document.getElementById("pass").value;
    var url = "/api/login/?user="+uname+"&pass="+pass;
    stuff.innerHTML = url;
    xmlhttp=new XMLHttpRequest();
    xmlhttp.onreadystatechange=Login_Return;
    xmlhttp.open("GET",url,true);
    xmlhttp.send();

}

<commit_msg>HTTPrequest 5<commit_after>

function Login_Page_Loaded(){

}

function Login_Return(){
    if (xmlhttp.readyState==4){
	Login_Form.style.display = "none";
	if(xmlhttp.status==200){
	    stuff.innerHTML = "Welcome "+uname;
	}
	if(xmlhttp.status==500||xmlhttp.status==400){
	    stuff.innerHTML = stuff.innerHTML+" : "+xmlhttp.responseText;
	}
	else{
	    stuff.innerHTML="Faute d'erreur! Grave! Grave!!";
	}
    }
}

function Login(){
    Login_Form = window.document.getElementById("LoginForm");
    stuff = window.document.getElementById("stuff");
    uname = window.document.getElementById("uname").value;
    pass = window.document.getElementById("pass").value;
    var url = "/api/login/?user="+uname+"&pass="+pass;
    stuff.innerHTML = url;
    xmlhttp=new XMLHttpRequest();
    xmlhttp.onreadystatechange=Login_Return;
    xmlhttp.open("GET",url,true);
    xmlhttp.send();

}

<|endoftext|>


<commit_before>import React from 'react';
import {connect} from 'react-redux';
import * as utils from '../../lib/utils';
import AuthForm from '../auth-form';
import {userFetchRequest, userCreateRequest, userUpdateRequest} from '../../action/auth-actions';
import {postFetchAllRequest} from '../../action/post-actions';
import PostItem from '../post-item';

class SettingsContainer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      editUser: false,
      username: '',
      bio: '',
    };
    this.handleToggle = this.handleToggle.bind(this);
  }

  // componentWillMount() {
  //   if(!this.props.user) this.props.userFetch();
  // }

  handleToggle() {
    this.setState({editUser: !this.state.editUser});
  }

  render() {
    let filtered = this.props.post.filter(post => post.ownerId === this.props.user._id);
    return (

        {utils.renderIf(!this.props.user.avatar,

I see this is your first time logging in

Feel free to upload an avatar and edit your profile

            <AuthForm
              buttonText="Update"
              onComplete={this.props.userUpdate}
              user={this.props.user}/>

        )}

 About me

Username: {this.props.user.username}

Email: {this.props.user.email}

My Biography:
 {this.props.user.bio}

My Avatar

Here are all your posts

          {utils.renderIf(this.props.post,

            filtered.map(post =>

{
                <PostItem key={post._id} post={post}
                />
              }

            ))}

    );
  }
}
// state.filter(item => item._id !== payload._id)
let mapStateToProps = state => ({
  user: state.user,
  auth: state.auth,
  post: state.post,
});

let mapDispatchToProps = dispatch => ({
  userCreate: user => dispatch(userCreateRequest(user)),
  userFetch: () => dispatch(userFetchRequest()),
  userUpdate: user => dispatch(userUpdateRequest(user)),
  postFetchAll: () => dispatch(postFetchAllRequest()),
});

export default connect(mapStateToProps, mapDispatchToProps)(SettingsContainer);
<commit_msg>added some more edit to settings<commit_after>import React from 'react';
import {connect} from 'react-redux';
import * as utils from '../../lib/utils';
import AuthForm from '../auth-form';
import {userFetchRequest, userCreateRequest, userUpdateRequest} from '../../action/auth-actions';
import {postFetchAllRequest} from '../../action/post-actions';
import PostItem from '../post-item';

class SettingsContainer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      editUser: false,
      username: '',
      bio: '',
    };
    this.handleEdit = this.handleEdit.bind(this);
  }

  handleEdit() {
    this.setState({editUser: !this.state.editUser});
  }

  render() {
    let filtered = this.props.post.filter(post => post.ownerId === this.props.user._id);
    return (

        {utils.renderIf(!this.props.user.avatar,

I see this is your first time logging in

Feel free to upload an avatar and edit your profile

            <AuthForm
              buttonText="Update"
              onComplete={this.props.userUpdate}
              user={this.props.user}/>

        )}

        {utils.renderIf(this.state.editUser,

 Edit your profile

            <AuthForm
              buttonText="Update"
              onComplete={this.props.userUpdate}
              user={this.props.user}/>

        )}

 About me

Username: {this.props.user.username}

Email: {this.props.user.email}

My Biography:
 {this.props.user.bio}

My Avatar

          <button onClick={this.handleEdit}>Edit Profile</button>

Here are all your posts

          {utils.renderIf(this.props.post,

            filtered.map(post =>

{
                <PostItem key={post._id} post={post}
                />
              }

            ))}

    );
  }
}
// state.filter(item => item._id !== payload._id)
let mapStateToProps = state => ({
  user: state.user,
  auth: state.auth,
  post: state.post,
});

let mapDispatchToProps = dispatch => ({
  userCreate: user => dispatch(userCreateRequest(user)),
  userFetch: () => dispatch(userFetchRequest()),
  userUpdate: user => dispatch(userUpdateRequest(user)),
  postFetchAll: () => dispatch(postFetchAllRequest()),
});

export default connect(mapStateToProps, mapDispatchToProps)(SettingsContainer);
<|endoftext|>


<commit_before> function main() {
         var map = new L.Map('map', {
             zoomControl: false,
             center: [44.908, -75.83],
             zoom: 15
         });
         L.tileLayer(
             'http://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}', {
                 attribution: 'Tiles © Esri — Esri, DeLorme, NAVTEQ',
                 maxZoom: 16
             }).addTo(map);
         // load 10k course route
         $.getJSON("10k.geojson", function(data) {
             // add GeoJSON layer to the map once the file is loaded
             L.geoJson(data).addTo(map);
         });
         // Define markers
         var startIcon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: 'flag-checkered',
             iconColor: 'white',
             markerColor: 'cadetblue'
         });
         var km1Icon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: '',
             iconColor: 'white',
             markerColor: 'cadetblue',
			 html: "1"
         });
		 var km2Icon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: '',
             iconColor: 'white',
             markerColor: 'cadetblue',
			 html: "2"
         });
		 var km3Icon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: '',
             iconColor: 'white',
             markerColor: 'cadetblue',
			 html: "3"
         });
		 var km4Icon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: '',
             iconColor: 'white',
             markerColor: 'cadetblue',
			 html: "4"
         });
		 var km5Icon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: '',
             iconColor: 'white',
             markerColor: 'cadetblue',
			 html: "5"
         });
		 var km6Icon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: '',
             iconColor: 'white',
             markerColor: 'cadetblue',
			 html: "6"
         });
		 var km7Icon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: '',
             iconColor: 'white',
             markerColor: 'cadetblue',
			 html: "7"
         });
		 var km8Icon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: '',
             iconColor: 'white',
             markerColor: 'cadetblue',
			 html: "8"
         });
		 var km9Icon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: '',
             iconColor: 'white',
             markerColor: 'cadetblue',
			 html: "9"
         });
		 var defaultIcon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: '',
             iconColor: 'white',
             markerColor: 'cadetblue',
			 html: ""
		});
         // load 10k course route features
         $.getJSON("features.geojson", function(data) {
             //add GeoJSON layer to the map once the file is loaded
             L.geoJson(data, {
                 pointToLayer: function(feature, latlng) {
                     if (feature.properties.cng_Meters ==
                         "0.0") {
                         var marker = L.marker(latlng, {
                             icon: startIcon
                         });
					} else if (feature.properties.cng_Meters ==
                         "1000.0") {
                         var marker = L.marker(latlng, {
                             icon: km1Icon
                         });
					} else if (feature.properties.cng_Meters ==
                         "2000.0") {
                         var marker = L.marker(latlng, {
                             icon: km2Icon
                         });
					} else if (feature.properties.cng_Meters ==
                         "3000.0") {
                         var marker = L.marker(latlng, {
                             icon: km3Icon
                         });
					} else if (feature.properties.cng_Meters ==
                         "4000.0") {
                         var marker = L.marker(latlng, {
                             icon: km4Icon
                         });
					} else if (feature.properties.cng_Meters ==
                         "5000.0") {
                         var marker = L.marker(latlng, {
                             icon: km5Icon
                         });
					} else if (feature.properties.cng_Meters ==
                         "6000.0") {
                         var marker = L.marker(latlng, {
                             icon: km6Icon
                         });
					} else if (feature.properties.cng_Meters ==
                         "7000.0") {
                         var marker = L.marker(latlng, {
                             icon: km7Icon
                         });
					} else if (feature.properties.cng_Meters ==
                         "8000.0") {
                         var marker = L.marker(latlng, {
                             icon: km8Icon
                         });
					} else if (feature.properties.cng_Meters ==
                         "9000.0") {
                         var marker = L.marker(latlng, {
                             icon: km9Icon
                         });
                     } else {
                         var marker = L.marker(latlng, {
                             icon: defaultIcon
                         });
                     };
                     return marker;
                     //return new L.marker(latlng, {
                     //icon: startIcon
                     //});
                 },
                 //onEachFeature: function(feature, layer) {
                 //layer.bindPopup(feature.properties.cng_Meters);
                 //}
             }).addTo(map);
         });

// we will be appending the SVG to the Leaflet map pane
    // g (group) element will be inside the svg and it
    svg = d3.select(map.getPanes().overlayPane).append("svg"),

    // if you don't include the leaflet-zoom-hide when a
    // user zooms in or out you will still see the phantom
    // original SVG
    g = svg.append("g").attr("class", "leaflet-zoom-hide");

    //read in the GeoJSON. This function is asynchronous so
    // anything that needs the json file should be within
    d3.json("10k.geojson", function(collection) {

        //stream transform. transforms geometry before passing it to
        // listener. Can be used in conjunction with d3.geo.path
        // to implement the transform. In this case the transform

        var transform = d3.geo.transform({
            point: projectPoint
        });

        //d3.geo.path translates GeoJSON to SVG path codes.
        //essentially a path generator. In this case it's
        // a path generator referencing our custom "projection"
        // which is the Leaflet method latLngToLayerPoint inside
        // our function called projectPoint
        var d3path = d3.geo.path().projection(transform);

        //essentially we're appending our features to the
        // group element. We're adding a class with the line name
        // and we're making them invisible
        var lineFeatures = g.selectAll("path")
            .data(collection.features)
            .enter()
            .append("path")
            .attr("class", function(d) {
                return d.properties.name

            })
            .attr("style", "opacity:0.5");

        // this is going to be the circle that tracks the
        // route, we're appending it to the g element
        var marker = g.append("circle");
        marker.attr("r", 10)
            .attr("id", "marker");

        // for now we're selecting just one of the lines. And
        // on this one line we're invoking (with the selection.call)
        // our transition function. Using callis the same as invoking
        // the function by hand but makes it easier to use method
        // chaining.
        var path = svg.select("path.line0")
            .attr("style", "opacity:1")
            .call(transition);

        // when the user zooms in or out you need to reset
        // the view
        map.on("viewreset", reset);

        // this puts stuff on the map! Without this "path"
        // only exists in theory
        reset();

             var startPoint = pathStartPoint(path);
         marker.attr("transform", "translate(" + startPoint[0] + "," + startPoint[1] + ")");

     // Reposition the SVG to cover the features.
        function reset() {
            var bounds = d3path.bounds(collection),
                topLeft = bounds[0],
                bottomRight = bounds[1];

            // here you're setting some styles, width, heigh etc
            // to the SVG. Note that we're adding a little height and
            // width because otherwise the bounding box would perfectly
            // cover our features BUT... since you might be using a big
            // circle to represent a 1 dimensional point, the circle
            // might get cut off.

        svg.attr("width", bottomRight[0] - topLeft[0] + 100)
            .attr("height", bottomRight[1] - topLeft[1] + 100)
            .style("left", topLeft[0] - 50 + "px")
            .style("top", topLeft[1] - 50 + "px");

        lineFeatures.attr("d", d3path);
        g.attr("transform", "translate(" + (-topLeft[0] + 50) + "," + (-topLeft[1] + 50) + ")"    );

        }// end reset

        function pathStartPoint(path) {

            var d = path.attr('d');
            console.log(d)

            dsplitted = d.split("L")[0].slice(1).split(",");
            var point = []
            point[0] = parseInt(dsplitted[0]);
            point[1] = parseInt(dsplitted[1]);

            return point;
        }//end pathStartPoint

        function transition(path) {
            path.transition()
                .duration(9500)
                .attrTween("stroke-dasharray", tweenDash)
                //if you want to have it repeat the sequence
                 //then uncomment this piece
                .each("end", function() {
                    d3.select(this).call(transition);
                }); // infinite loop
        } //end transition

        function tweenDash() {
            var l = path.node().getTotalLength(); //total length of path
            var i = d3.interpolateString("0," + l, l + "," + l); // interpolation of stroke-dasharray style attr
            console.log(l)
            return function(t) {
                //t is fraction of time 0-1 since transition began
                var marker = d3.select("#marker");
                console.log(t)
                // p is the point on the line (coordinates) at a given length
                // along the line. In this case if l=50 and we're midway through
                // the time then this would 25.
                var p = path.node().getPointAtLength(t * l);

                //Move the marker to that point
                marker.attr("transform", "translate(" + p.x + "," + p.y + ")"); //move marker
                return i(t);
            }
        } //end tweenDash

        // Use Leaflet to implement a D3 geometric transformation.
        // the latLngToLayerPoint is a Leaflet conversion method:
        //Returns the map layer point that corresponds to the given geographical
        // coordinates (useful for placing overlays on the map).
        function projectPoint(x, y) {
            var point = map.latLngToLayerPoint(new L.LatLng(y, x));
            this.stream.point(point.x, point.y);
        }//end projectPoint
    });

     }
     // you could use $(window).load(main);
 window.onload = main;<commit_msg>change routepath duration<commit_after> function main() {
         var map = new L.Map('map', {
             zoomControl: false,
             center: [44.908, -75.83],
             zoom: 15
         });
         L.tileLayer(
             'http://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}', {
                 attribution: 'Tiles © Esri — Esri, DeLorme, NAVTEQ',
                 maxZoom: 16
             }).addTo(map);
         // load 10k course route
         $.getJSON("10k.geojson", function(data) {
             // add GeoJSON layer to the map once the file is loaded
             L.geoJson(data).addTo(map);
         });
         // Define markers
         var startIcon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: 'flag-checkered',
             iconColor: 'white',
             markerColor: 'cadetblue'
         });
         var km1Icon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: '',
             iconColor: 'white',
             markerColor: 'cadetblue',
			 html: "1"
         });
		 var km2Icon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: '',
             iconColor: 'white',
             markerColor: 'cadetblue',
			 html: "2"
         });
		 var km3Icon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: '',
             iconColor: 'white',
             markerColor: 'cadetblue',
			 html: "3"
         });
		 var km4Icon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: '',
             iconColor: 'white',
             markerColor: 'cadetblue',
			 html: "4"
         });
		 var km5Icon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: '',
             iconColor: 'white',
             markerColor: 'cadetblue',
			 html: "5"
         });
		 var km6Icon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: '',
             iconColor: 'white',
             markerColor: 'cadetblue',
			 html: "6"
         });
		 var km7Icon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: '',
             iconColor: 'white',
             markerColor: 'cadetblue',
			 html: "7"
         });
		 var km8Icon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: '',
             iconColor: 'white',
             markerColor: 'cadetblue',
			 html: "8"
         });
		 var km9Icon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: '',
             iconColor: 'white',
             markerColor: 'cadetblue',
			 html: "9"
         });
		 var defaultIcon = L.AwesomeMarkers.icon({
             prefix: 'fa',
             icon: '',
             iconColor: 'white',
             markerColor: 'cadetblue',
			 html: ""
		});
         // load 10k course route features
         $.getJSON("features.geojson", function(data) {
             //add GeoJSON layer to the map once the file is loaded
             L.geoJson(data, {
                 pointToLayer: function(feature, latlng) {
                     if (feature.properties.cng_Meters ==
                         "0.0") {
                         var marker = L.marker(latlng, {
                             icon: startIcon
                         });
					} else if (feature.properties.cng_Meters ==
                         "1000.0") {
                         var marker = L.marker(latlng, {
                             icon: km1Icon
                         });
					} else if (feature.properties.cng_Meters ==
                         "2000.0") {
                         var marker = L.marker(latlng, {
                             icon: km2Icon
                         });
					} else if (feature.properties.cng_Meters ==
                         "3000.0") {
                         var marker = L.marker(latlng, {
                             icon: km3Icon
                         });
					} else if (feature.properties.cng_Meters ==
                         "4000.0") {
                         var marker = L.marker(latlng, {
                             icon: km4Icon
                         });
					} else if (feature.properties.cng_Meters ==
                         "5000.0") {
                         var marker = L.marker(latlng, {
                             icon: km5Icon
                         });
					} else if (feature.properties.cng_Meters ==
                         "6000.0") {
                         var marker = L.marker(latlng, {
                             icon: km6Icon
                         });
					} else if (feature.properties.cng_Meters ==
                         "7000.0") {
                         var marker = L.marker(latlng, {
                             icon: km7Icon
                         });
					} else if (feature.properties.cng_Meters ==
                         "8000.0") {
                         var marker = L.marker(latlng, {
                             icon: km8Icon
                         });
					} else if (feature.properties.cng_Meters ==
                         "9000.0") {
                         var marker = L.marker(latlng, {
                             icon: km9Icon
                         });
                     } else {
                         var marker = L.marker(latlng, {
                             icon: defaultIcon
                         });
                     };
                     return marker;
                     //return new L.marker(latlng, {
                     //icon: startIcon
                     //});
                 },
                 //onEachFeature: function(feature, layer) {
                 //layer.bindPopup(feature.properties.cng_Meters);
                 //}
             }).addTo(map);
         });

// we will be appending the SVG to the Leaflet map pane
    // g (group) element will be inside the svg and it
    svg = d3.select(map.getPanes().overlayPane).append("svg"),

    // if you don't include the leaflet-zoom-hide when a
    // user zooms in or out you will still see the phantom
    // original SVG
    g = svg.append("g").attr("class", "leaflet-zoom-hide");

    //read in the GeoJSON. This function is asynchronous so
    // anything that needs the json file should be within
    d3.json("10k.geojson", function(collection) {

        //stream transform. transforms geometry before passing it to
        // listener. Can be used in conjunction with d3.geo.path
        // to implement the transform. In this case the transform

        var transform = d3.geo.transform({
            point: projectPoint
        });

        //d3.geo.path translates GeoJSON to SVG path codes.
        //essentially a path generator. In this case it's
        // a path generator referencing our custom "projection"
        // which is the Leaflet method latLngToLayerPoint inside
        // our function called projectPoint
        var d3path = d3.geo.path().projection(transform);

        //essentially we're appending our features to the
        // group element. We're adding a class with the line name
        // and we're making them invisible
        var lineFeatures = g.selectAll("path")
            .data(collection.features)
            .enter()
            .append("path")
            .attr("class", function(d) {
                return d.properties.name

            })
            .attr("style", "opacity:0.5");

        // this is going to be the circle that tracks the
        // route, we're appending it to the g element
        var marker = g.append("circle");
        marker.attr("r", 10)
            .attr("id", "marker");

        // for now we're selecting just one of the lines. And
        // on this one line we're invoking (with the selection.call)
        // our transition function. Using callis the same as invoking
        // the function by hand but makes it easier to use method
        // chaining.
        var path = svg.select("path.line0")
            .attr("style", "opacity:1")
            .call(transition);

        // when the user zooms in or out you need to reset
        // the view
        map.on("viewreset", reset);

        // this puts stuff on the map! Without this "path"
        // only exists in theory
        reset();

             var startPoint = pathStartPoint(path);
         marker.attr("transform", "translate(" + startPoint[0] + "," + startPoint[1] + ")");

     // Reposition the SVG to cover the features.
        function reset() {
            var bounds = d3path.bounds(collection),
                topLeft = bounds[0],
                bottomRight = bounds[1];

            // here you're setting some styles, width, heigh etc
            // to the SVG. Note that we're adding a little height and
            // width because otherwise the bounding box would perfectly
            // cover our features BUT... since you might be using a big
            // circle to represent a 1 dimensional point, the circle
            // might get cut off.

        svg.attr("width", bottomRight[0] - topLeft[0] + 100)
            .attr("height", bottomRight[1] - topLeft[1] + 100)
            .style("left", topLeft[0] - 50 + "px")
            .style("top", topLeft[1] - 50 + "px");

        lineFeatures.attr("d", d3path);
        g.attr("transform", "translate(" + (-topLeft[0] + 50) + "," + (-topLeft[1] + 50) + ")"    );

        }// end reset

        function pathStartPoint(path) {

            var d = path.attr('d');
            console.log(d)

            dsplitted = d.split("L")[0].slice(1).split(",");
            var point = []
            point[0] = parseInt(dsplitted[0]);
            point[1] = parseInt(dsplitted[1]);

            return point;
        }//end pathStartPoint

        function transition(path) {
            path.transition()
                .duration(1200)
                .attrTween("stroke-dasharray", tweenDash)
                //if you want to have it repeat the sequence
                 //then uncomment this piece
                .each("end", function() {
                    d3.select(this).call(transition);
                }); // infinite loop
        } //end transition

        function tweenDash() {
            var l = path.node().getTotalLength(); //total length of path
            var i = d3.interpolateString("0," + l, l + "," + l); // interpolation of stroke-dasharray style attr
            console.log(l)
            return function(t) {
                //t is fraction of time 0-1 since transition began
                var marker = d3.select("#marker");
                console.log(t)
                // p is the point on the line (coordinates) at a given length
                // along the line. In this case if l=50 and we're midway through
                // the time then this would 25.
                var p = path.node().getPointAtLength(t * l);

                //Move the marker to that point
                marker.attr("transform", "translate(" + p.x + "," + p.y + ")"); //move marker
                return i(t);
            }
        } //end tweenDash

        // Use Leaflet to implement a D3 geometric transformation.
        // the latLngToLayerPoint is a Leaflet conversion method:
        //Returns the map layer point that corresponds to the given geographical
        // coordinates (useful for placing overlays on the map).
        function projectPoint(x, y) {
            var point = map.latLngToLayerPoint(new L.LatLng(y, x));
            this.stream.point(point.x, point.y);
        }//end projectPoint
    });

     }
     // you could use $(window).load(main);
 window.onload = main;<|endoftext|>


<commit_before>// Utilities
//
'use strict';

function _class(obj) { return Object.prototype.toString.call(obj); }

function isString(obj) { return _class(obj) === '[object String]'; }

var _hasOwnProperty = Object.prototype.hasOwnProperty;

function has(object, key) {
  return _hasOwnProperty.call(object, key);
}

// Merge objects
//
function assign(obj /*from1, from2, from3, ...*/) {
  var sources = Array.prototype.slice.call(arguments, 1);

  sources.forEach(function (source) {
    if (!source) { return; }

    if (typeof source !== 'object') {
      throw new TypeError(source + 'must be object');
    }

    Object.keys(source).forEach(function (key) {
      obj[key] = source[key];
    });
  });

  return obj;
}

// Remove element from array and put another array at those position.
// Useful for some operations with tokens
function arrayReplaceAt(src, pos, newElements) {
  return [].concat(src.slice(0, pos), newElements, src.slice(pos + 1));
}

////////////////////////////////////////////////////////////////////////////////

var UNESCAPE_MD_RE = /\\([\\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g;

function unescapeMd(str) {
  if (str.indexOf('\\') < 0) { return str; }
  return str.replace(UNESCAPE_MD_RE, '$1');
}

////////////////////////////////////////////////////////////////////////////////

function isValidEntityCode(c) {
  /*eslint no-bitwise:0*/
  // broken sequence
  if (c >= 0xD800 && c <= 0xDFFF) { return false; }
  // never used
  if (c >= 0xFDD0 && c <= 0xFDEF) { return false; }
  if ((c & 0xFFFF) === 0xFFFF || (c & 0xFFFF) === 0xFFFE) { return false; }
  // control codes
  if (c >= 0x00 && c <= 0x08) { return false; }
  if (c === 0x0B) { return false; }
  if (c >= 0x0E && c <= 0x1F) { return false; }
  if (c >= 0x7F && c <= 0x9F) { return false; }
  // out of range
  if (c > 0x10FFFF) { return false; }
  return true;
}

function fromCodePoint(c) {
  /*eslint no-bitwise:0*/
  if (c > 0xffff) {
    c -= 0x10000;
    var surrogate1 = 0xd800 + (c >> 10),
        surrogate2 = 0xdc00 + (c & 0x3ff);

    return String.fromCharCode(surrogate1, surrogate2);
  }
  return String.fromCharCode(c);
}

var NAMED_ENTITY_RE   = /&([a-z#][a-z0-9]{1,31});/gi;
var DIGITAL_ENTITY_TEST_RE = /^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i;
var entities = require('./entities');

function replaceEntityPattern(match, name) {
  var code = 0;

  if (has(entities, name)) {
    return entities[name];
  } else if (name.charCodeAt(0) === 0x23/* # */ && DIGITAL_ENTITY_TEST_RE.test(name)) {
    code = name[1].toLowerCase() === 'x' ?
      parseInt(name.slice(2), 16)
    :
      parseInt(name.slice(1), 10);
    if (isValidEntityCode(code)) {
      return fromCodePoint(code);
    }
  }
  return match;
}

function replaceEntities(str) {
  if (str.indexOf('&') < 0) { return str; }

  return str.replace(NAMED_ENTITY_RE, replaceEntityPattern);
}

////////////////////////////////////////////////////////////////////////////////

var HTML_ESCAPE_TEST_RE = /[&<>"]/;
var HTML_ESCAPE_REPLACE_RE = /[&<>"]/g;
var HTML_REPLACEMENTS = {
  '&': '&',
  '<': '<',
  '>': '>',
  '"': '"'
};

function replaceUnsafeChar(ch) {
  return HTML_REPLACEMENTS[ch];
}

function escapeHtml(str) {
  if (HTML_ESCAPE_TEST_RE.test(str)) {
    return str.replace(HTML_ESCAPE_REPLACE_RE, replaceUnsafeChar);
  }
  return str;
}

////////////////////////////////////////////////////////////////////////////////

// Incoming link can be partially encoded. Convert possible combinations to
// unified form.
function normalizeLink(url) {
  var normalized = replaceEntities(url);

  // We don't care much about result of mailformed URIs,
  // but shoud not throw exception.
  try {
    normalized = decodeURI(normalized);
  } catch (__) {}

  return encodeURI(normalized);
}

////////////////////////////////////////////////////////////////////////////////

var REGEXP_ESCAPE_RE = /[.?*+^$[\]\\(){}|-]/g;

function escapeRE (str) {
  return str.replace(REGEXP_ESCAPE_RE, '\\$&');
}

////////////////////////////////////////////////////////////////////////////////

// Zs (unicode class) || 09, 0A, 0D, 0C
function isWhiteSpace(code) {
  if (code >= 0x2000 && code <= 0x200A) { return true; }
  switch (code) {
    case 0x09:
    case 0x0A:
    case 0x0D:
    case 0x0C:
    case 0x20:
    case 0xA0:
    case 0x1680:
    case 0x202F:
    case 0x205F:
    case 0x3000:
      return true;
  }
  return false;
}

////////////////////////////////////////////////////////////////////////////////

/*eslint-disable max-len*/
var BMP_PUNCT_RE = /[\x21-\x23\x25-\x2A\x2C-\x2F\x3A\x3B\x3F\x40\x5B-\x5D\x5F\x7B\x7D\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E42\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]/;

// Currently without astral characters support.
function isPunctChar(char) {
  return BMP_PUNCT_RE.test(char);
}

////////////////////////////////////////////////////////////////////////////////

exports.assign            = assign;
exports.isString          = isString;
exports.has               = has;
exports.unescapeMd        = unescapeMd;
exports.isValidEntityCode = isValidEntityCode;
exports.fromCodePoint     = fromCodePoint;
exports.replaceEntities   = replaceEntities;
exports.escapeHtml        = escapeHtml;
exports.arrayReplaceAt    = arrayReplaceAt;
exports.normalizeLink     = normalizeLink;
exports.isWhiteSpace      = isWhiteSpace;
exports.isPunctChar       = isPunctChar;
exports.escapeRE          = escapeRE;
<commit_msg>Catch exception in link normalizer on broken unicode sequence<commit_after>// Utilities
//
'use strict';

function _class(obj) { return Object.prototype.toString.call(obj); }

function isString(obj) { return _class(obj) === '[object String]'; }

var _hasOwnProperty = Object.prototype.hasOwnProperty;

function has(object, key) {
  return _hasOwnProperty.call(object, key);
}

// Merge objects
//
function assign(obj /*from1, from2, from3, ...*/) {
  var sources = Array.prototype.slice.call(arguments, 1);

  sources.forEach(function (source) {
    if (!source) { return; }

    if (typeof source !== 'object') {
      throw new TypeError(source + 'must be object');
    }

    Object.keys(source).forEach(function (key) {
      obj[key] = source[key];
    });
  });

  return obj;
}

// Remove element from array and put another array at those position.
// Useful for some operations with tokens
function arrayReplaceAt(src, pos, newElements) {
  return [].concat(src.slice(0, pos), newElements, src.slice(pos + 1));
}

////////////////////////////////////////////////////////////////////////////////

var UNESCAPE_MD_RE = /\\([\\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g;

function unescapeMd(str) {
  if (str.indexOf('\\') < 0) { return str; }
  return str.replace(UNESCAPE_MD_RE, '$1');
}

////////////////////////////////////////////////////////////////////////////////

function isValidEntityCode(c) {
  /*eslint no-bitwise:0*/
  // broken sequence
  if (c >= 0xD800 && c <= 0xDFFF) { return false; }
  // never used
  if (c >= 0xFDD0 && c <= 0xFDEF) { return false; }
  if ((c & 0xFFFF) === 0xFFFF || (c & 0xFFFF) === 0xFFFE) { return false; }
  // control codes
  if (c >= 0x00 && c <= 0x08) { return false; }
  if (c === 0x0B) { return false; }
  if (c >= 0x0E && c <= 0x1F) { return false; }
  if (c >= 0x7F && c <= 0x9F) { return false; }
  // out of range
  if (c > 0x10FFFF) { return false; }
  return true;
}

function fromCodePoint(c) {
  /*eslint no-bitwise:0*/
  if (c > 0xffff) {
    c -= 0x10000;
    var surrogate1 = 0xd800 + (c >> 10),
        surrogate2 = 0xdc00 + (c & 0x3ff);

    return String.fromCharCode(surrogate1, surrogate2);
  }
  return String.fromCharCode(c);
}

var NAMED_ENTITY_RE   = /&([a-z#][a-z0-9]{1,31});/gi;
var DIGITAL_ENTITY_TEST_RE = /^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i;
var entities = require('./entities');

function replaceEntityPattern(match, name) {
  var code = 0;

  if (has(entities, name)) {
    return entities[name];
  } else if (name.charCodeAt(0) === 0x23/* # */ && DIGITAL_ENTITY_TEST_RE.test(name)) {
    code = name[1].toLowerCase() === 'x' ?
      parseInt(name.slice(2), 16)
    :
      parseInt(name.slice(1), 10);
    if (isValidEntityCode(code)) {
      return fromCodePoint(code);
    }
  }
  return match;
}

function replaceEntities(str) {
  if (str.indexOf('&') < 0) { return str; }

  return str.replace(NAMED_ENTITY_RE, replaceEntityPattern);
}

////////////////////////////////////////////////////////////////////////////////

var HTML_ESCAPE_TEST_RE = /[&<>"]/;
var HTML_ESCAPE_REPLACE_RE = /[&<>"]/g;
var HTML_REPLACEMENTS = {
  '&': '&',
  '<': '<',
  '>': '>',
  '"': '"'
};

function replaceUnsafeChar(ch) {
  return HTML_REPLACEMENTS[ch];
}

function escapeHtml(str) {
  if (HTML_ESCAPE_TEST_RE.test(str)) {
    return str.replace(HTML_ESCAPE_REPLACE_RE, replaceUnsafeChar);
  }
  return str;
}

////////////////////////////////////////////////////////////////////////////////

// Incoming link can be partially encoded. Convert possible combinations to
// unified form.
//
// TODO: Rewrite it. Should use:
//
// - encodeURIComponent for query
// - encodeURI for path
// - (?) punicode for domain mame (but encodeURI seems to work in real world)
//
function normalizeLink(url) {
  var normalized = replaceEntities(url);

  // We don't care much about result of mailformed URIs,
  // but shoud not throw exception.
  try {
    normalized = decodeURI(normalized);
  } catch (__) {}

  // Encoder throws exception on broken unicode sequence.
  // Kill suspicious data for the safety.
  //
  try {
    return encodeURI(normalized);
  } catch (__) {
    return '';
  }
}

////////////////////////////////////////////////////////////////////////////////

var REGEXP_ESCAPE_RE = /[.?*+^$[\]\\(){}|-]/g;

function escapeRE (str) {
  return str.replace(REGEXP_ESCAPE_RE, '\\$&');
}

////////////////////////////////////////////////////////////////////////////////

// Zs (unicode class) || 09, 0A, 0D, 0C
function isWhiteSpace(code) {
  if (code >= 0x2000 && code <= 0x200A) { return true; }
  switch (code) {
    case 0x09:
    case 0x0A:
    case 0x0D:
    case 0x0C:
    case 0x20:
    case 0xA0:
    case 0x1680:
    case 0x202F:
    case 0x205F:
    case 0x3000:
      return true;
  }
  return false;
}

////////////////////////////////////////////////////////////////////////////////

/*eslint-disable max-len*/
var BMP_PUNCT_RE = /[\x21-\x23\x25-\x2A\x2C-\x2F\x3A\x3B\x3F\x40\x5B-\x5D\x5F\x7B\x7D\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E42\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]/;

// Currently without astral characters support.
function isPunctChar(char) {
  return BMP_PUNCT_RE.test(char);
}

////////////////////////////////////////////////////////////////////////////////

exports.assign            = assign;
exports.isString          = isString;
exports.has               = has;
exports.unescapeMd        = unescapeMd;
exports.isValidEntityCode = isValidEntityCode;
exports.fromCodePoint     = fromCodePoint;
exports.replaceEntities   = replaceEntities;
exports.escapeHtml        = escapeHtml;
exports.arrayReplaceAt    = arrayReplaceAt;
exports.normalizeLink     = normalizeLink;
exports.isWhiteSpace      = isWhiteSpace;
exports.isPunctChar       = isPunctChar;
exports.escapeRE          = escapeRE;
<|endoftext|>