<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 = () => {
        onnectionInfo.text = 'Reconnecting...'connectionInfo.text = 'Reconnecting...'
        connectionInfo.visible = true
        io = null
        setTimeout(() => {
            incrementWait()
            connect(address);
        }, wait)
    };

    io.onerror = (err) => {
        console.error('Socket encountered error: ', err.message, 'Closing socket')
        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 - 200
    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: Improve socket error feedback<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.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]
}<|endoftext|>


<commit_before>'use strict';
import { assert } from 'chai';
import path from 'path';

import db from '../app/db';
import { setupStructure as setupDdStructure } from '../app/db/structure';
import { bucket } from '../app/s3/';
import { setupStructure as setupStorageStructure, putObjectFromFile } from '../app/s3/structure';
import { projectPendingWithAllFiles } from './utils/data';
import Operation from '../app/utils/operation';
import { concludeProjectSetup } from '../app/services/project-setup/project-setup';

const FILE_ROAD_NETWORK = path.join(__dirname, 'utils/road-network-small.osm');
const INVALID_FILE_JSON = path.join(__dirname, 'utils/test-file.json');
const INVALID_FILE = path.join(__dirname, 'utils/test-file');

describe('Finish Project Setup', function () {
  before(function () {
    this.timeout(5000);
    return setupDdStructure()
      .then(() => setupStorageStructure())

      // Small valid road-network file.
      .then(() => projectPendingWithAllFiles(3000))
      .then(() => putObjectFromFile(bucket, `scenario-3000/road-network_000000`, FILE_ROAD_NETWORK))

      // Invalid admin bounds file. Still JSON though.
      .then(() => projectPendingWithAllFiles(3010))
      .then(() => putObjectFromFile(bucket, `project-3010/admin-bounds_000000`, INVALID_FILE_JSON))

      // Invalid road-network file. (not xml, just text)
      .then(() => projectPendingWithAllFiles(3020))
      .then(() => putObjectFromFile(bucket, `scenario-3020/road-network_000000`, INVALID_FILE));
  });

  it('should process the project files to finish the setup', function (done) {
    this.slow(250);
    // There needs to be an ongoing operation to start the script.
    // Operation is fully tested on another file so it's safe to use.
    let op = new Operation(db);
    op.start('project-setup-finish', 3000, 3000)
      .then(() => op.log('start', {message: 'Operation started'}))
      .then(() => {
        const validate = () => {
          // Project should be active.
          // Project should have a bbox
          // Scenario should be active.
          // Scenario should have admin areas.
          // Operation should be complete.
          // There should be 5 operation logs.
          Promise.all([
            db('projects')
              .where('id', 3000)
              .first()
              .then(proj => {
                assert.equal(proj.status, 'active');
                assert.deepEqual(proj.bbox, [ -38.313, -11.89, -37.1525399, -10.5333431 ]);
              }),
            db('scenarios')
              .where('id', 3000)
              .first()
              .then(scenario => {
                assert.equal(scenario.status, 'active');
              }),
            db('scenarios_settings')
              .where('scenario_id', 3000)
              .where('key', 'admin_areas')
              .first()
              .then(setting => {
                assert.equal(setting.value, '[]');
              }),
            db('projects_aa')
              .select('name', 'project_id', 'type')
              .where('project_id', 3000)
              .then(aa => {
                let adminAreas = [
                  {'name': 'Arauá', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Boquim', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Campo do Brito', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Cristinápolis', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Distrito de Abadia', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Distrito de Buril', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Distrito de Conceição de Campinas', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Distrito de Itamira', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Distrito de Itanhi', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Distrito de Sambaíba', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Estância', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Indiaroba', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Itabaiana', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Itabaianinha', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Itaporanga d\'Ajuda', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Lagarto', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Macambira', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Palmares', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Pedra Mole', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Pedrinhas', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Poço Verde', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Riachão do Dantas', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Salgado', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Samambaia', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Santa Luzia do Itanhy', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'São Domingos', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Simão Dias', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Tobias Barreto', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Tomar do Geru', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Umbaúba', 'type': 'boundary', 'project_id': 3000}
                ];
                assert.deepEqual(aa, adminAreas);
              }),
            db('operations')
              .where('id', op.getId())
              .first()
              .then(operation => {
                assert.equal(operation.status, 'complete');
              }),
            db('operations_logs')
              .where('operation_id', op.getId())
              .then(logs => {
                // assert.lengthOf(logs, 5);
                assert.lengthOf(logs, 3);
                assert.equal(logs[0].code, 'start');
                assert.equal(logs[0].data.message, 'Operation started');
                assert.equal(logs[1].code, 'process:admin-bounds');
                assert.equal(logs[1].data.message, 'Processing admin areas');
                // assert.equal(logs[2].code, 'process:road-network');
                // assert.equal(logs[2].data.message, 'Road network processing started');
                // assert.equal(logs[3].code, 'process:road-network');
                // assert.equal(logs[3].data.message, 'Road network processing finished');
                // assert.equal(logs[4].code, 'success');
                // assert.equal(logs[4].data.message, 'Operation complete');
                assert.equal(logs[2].code, 'success');
                assert.equal(logs[2].data.message, 'Operation complete');
              })
          ])
          .then(() => done())
          .catch(err => done(err));
        };

        // Start.
        let data = {
          opId: op.getId(),
          projId: 3000,
          scId: 3000,
          callback: (err) => {
            if (err) {
              done(new Error('The script ended in error' + err));
            } else {
              validate();
            }
          }
        };
        concludeProjectSetup(data);
      });
  });

  it('should error with invalid admin bounds file', function (done) {
    this.slow(250);
    // There needs to be an ongoing operation to start the script.
    // Operation is fully tested on another file so it's safe to use.
    let op = new Operation(db);
    op.start('project-setup-finish', 3010, 3010)
      .then(() => op.log('start', {message: 'Operation started'}))
      .then(() => {
        // Start.
        let data = {
          opId: op.getId(),
          projId: 3010,
          scId: 3010,
          callback: (err) => {
            if (err) {
              db('operations_logs')
                .where('operation_id', op.getId())
                .orderBy('id', 'desc')
                .then(logs => {
                  assert.equal(err, 'Invalid administrative boundaries file');
                  assert.lengthOf(logs, 3);
                  assert.equal(logs[0].code, 'error');
                  assert.equal(logs[0].data.error, 'Invalid administrative boundaries file');
                })
                .then(() => done())
                .catch(err => done(err));
            } else {
              done(new Error('The test should have failed but succeeded'));
            }
          }
        };

        concludeProjectSetup(data);
      });
  });

  // Without the import into osm-p2p-db the file is just uploaded
  // to the storage. No error will happen. Skipping for now.
  it.skip('should error with invalid road network file', function (done) {
    this.slow(250);
    this.timeout(5000);
    // There needs to be an ongoing operation to start the script.
    // Operation is fully tested on another file so it's safe to use.
    let op = new Operation(db);
    op.start('project-setup-finish', 3020, 3020)
      .then(() => op.log('start', {message: 'Operation started'}))
      .then(() => {
        // Start.
        let data = {
          opId: op.getId(),
          projId: 3020,
          scId: 3020,
          callback: (err) => {
            if (err) {
              db('operations_logs')
                .where('operation_id', op.getId())
                .orderBy('id', 'desc')
                .then(logs => {
                  assert.match(err, /OGR failed to open (.+)\/road-networkP3020S3020.osm, format may be unsupported/);
                  assert.lengthOf(logs, 4);
                  assert.equal(logs[0].code, 'error');
                  assert.match(logs[0].data.error, /OGR failed to open (.+)\/road-networkP3020S3020.osm, format may be unsupported/);
                })
                .then(() => done())
                .catch(err => done(err));
            } else {
              done(new Error('The test should have failed but succeeded'));
            }
          }
        };

        concludeProjectSetup(data);
      });
  });
});
<commit_msg>Fix tests<commit_after>'use strict';
import { assert } from 'chai';
import path from 'path';

import db from '../app/db';
import { setupStructure as setupDdStructure } from '../app/db/structure';
import { bucket } from '../app/s3/';
import { setupStructure as setupStorageStructure, putObjectFromFile } from '../app/s3/structure';
import { projectPendingWithAllFiles } from './utils/data';
import Operation from '../app/utils/operation';
import { concludeProjectSetup } from '../app/services/project-setup/project-setup';

const FILE_ROAD_NETWORK = path.join(__dirname, 'utils/road-network-small.osm');
const INVALID_FILE_JSON = path.join(__dirname, 'utils/test-file.json');
const INVALID_FILE = path.join(__dirname, 'utils/test-file');

describe('Finish Project Setup', function () {
  before(function () {
    this.timeout(5000);
    return setupDdStructure()
      .then(() => setupStorageStructure())

      // Small valid road-network file.
      .then(() => projectPendingWithAllFiles(3000))
      .then(() => putObjectFromFile(bucket, `scenario-3000/road-network_000000`, FILE_ROAD_NETWORK))

      // Invalid admin bounds file. Still JSON though.
      .then(() => projectPendingWithAllFiles(3010))
      .then(() => putObjectFromFile(bucket, `project-3010/admin-bounds_000000`, INVALID_FILE_JSON))

      // Invalid road-network file. (not xml, just text)
      .then(() => projectPendingWithAllFiles(3020))
      .then(() => putObjectFromFile(bucket, `scenario-3020/road-network_000000`, INVALID_FILE));
  });

  it('should process the project files to finish the setup', function (done) {
    this.slow(250);
    // There needs to be an ongoing operation to start the script.
    // Operation is fully tested on another file so it's safe to use.
    let op = new Operation(db);
    op.start('project-setup-finish', 3000, 3000)
      .then(() => op.log('start', {message: 'Operation started'}))
      .then(() => {
        const validate = () => {
          // Project should be active.
          // Project should have a bbox
          // Scenario should be active.
          // Scenario should have admin areas.
          // Operation should be complete.
          // There should be 5 operation logs.
          Promise.all([
            db('projects')
              .where('id', 3000)
              .first()
              .then(proj => {
                assert.equal(proj.status, 'active');
                assert.deepEqual(proj.bbox, [ -38.313, -11.89, -37.1525399, -10.5333431 ]);
              }),
            db('scenarios')
              .where('id', 3000)
              .first()
              .then(scenario => {
                assert.equal(scenario.status, 'active');
              }),
            db('scenarios_settings')
              .where('scenario_id', 3000)
              .where('key', 'admin_areas')
              .first()
              .then(setting => {
                assert.equal(setting.value, '[]');
              }),
            db('projects_aa')
              .select('name', 'project_id', 'type')
              .where('project_id', 3000)
              .then(aa => {
                let adminAreas = [
                  {'name': 'Arauá', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Boquim', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Campo do Brito', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Cristinápolis', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Distrito de Abadia', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Distrito de Buril', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Distrito de Conceição de Campinas', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Distrito de Itamira', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Distrito de Itanhi', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Distrito de Sambaíba', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Estância', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Indiaroba', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Itabaiana', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Itabaianinha', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Itaporanga d\'Ajuda', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Lagarto', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Macambira', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Palmares', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Pedra Mole', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Pedrinhas', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Poço Verde', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Riachão do Dantas', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Salgado', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Samambaia', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Santa Luzia do Itanhy', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'São Domingos', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Simão Dias', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Tobias Barreto', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Tomar do Geru', 'type': 'boundary', 'project_id': 3000},
                  {'name': 'Umbaúba', 'type': 'boundary', 'project_id': 3000}
                ];
                assert.deepEqual(aa, adminAreas);
              }),
            db('operations')
              .where('id', op.getId())
              .first()
              .then(operation => {
                assert.equal(operation.status, 'complete');
              }),
            db('operations_logs')
              .where('operation_id', op.getId())
              .then(logs => {
                // assert.lengthOf(logs, 5);
                assert.lengthOf(logs, 4);
                assert.equal(logs[0].code, 'start');
                assert.equal(logs[0].data.message, 'Operation started');
                assert.equal(logs[1].code, 'process:admin-bounds');
                assert.equal(logs[1].data.message, 'Processing admin areas');
                assert.equal(logs[2].code, 'process:origins');
                assert.equal(logs[2].data.message, 'Processing origins');
                // assert.equal(logs[2].code, 'process:road-network');
                // assert.equal(logs[2].data.message, 'Road network processing started');
                // assert.equal(logs[3].code, 'process:road-network');
                // assert.equal(logs[3].data.message, 'Road network processing finished');
                // assert.equal(logs[4].code, 'success');
                // assert.equal(logs[4].data.message, 'Operation complete');
                assert.equal(logs[3].code, 'success');
                assert.equal(logs[3].data.message, 'Operation complete');
              })
          ])
          .then(() => done())
          .catch(err => done(err));
        };

        // Start.
        let data = {
          opId: op.getId(),
          projId: 3000,
          scId: 3000,
          callback: (err) => {
            if (err) {
              done(new Error('The script ended in error' + err));
            } else {
              validate();
            }
          }
        };
        concludeProjectSetup(data);
      });
  });

  it('should error with invalid admin bounds file', function (done) {
    this.slow(250);
    // There needs to be an ongoing operation to start the script.
    // Operation is fully tested on another file so it's safe to use.
    let op = new Operation(db);
    op.start('project-setup-finish', 3010, 3010)
      .then(() => op.log('start', {message: 'Operation started'}))
      .then(() => {
        // Start.
        let data = {
          opId: op.getId(),
          projId: 3010,
          scId: 3010,
          callback: (err) => {
            if (err) {
              db('operations_logs')
                .where('operation_id', op.getId())
                .orderBy('id', 'desc')
                .then(logs => {
                  assert.equal(err, 'Invalid administrative boundaries file');
                  assert.lengthOf(logs, 4);
                  assert.equal(logs[0].code, 'error');
                  assert.equal(logs[0].data.error, 'Invalid administrative boundaries file');
                })
                .then(() => done())
                .catch(err => done(err));
            } else {
              done(new Error('The test should have failed but succeeded'));
            }
          }
        };

        concludeProjectSetup(data);
      });
  });

  // Without the import into osm-p2p-db the file is just uploaded
  // to the storage. No error will happen. Skipping for now.
  it.skip('should error with invalid road network file', function (done) {
    this.slow(250);
    this.timeout(5000);
    // There needs to be an ongoing operation to start the script.
    // Operation is fully tested on another file so it's safe to use.
    let op = new Operation(db);
    op.start('project-setup-finish', 3020, 3020)
      .then(() => op.log('start', {message: 'Operation started'}))
      .then(() => {
        // Start.
        let data = {
          opId: op.getId(),
          projId: 3020,
          scId: 3020,
          callback: (err) => {
            if (err) {
              db('operations_logs')
                .where('operation_id', op.getId())
                .orderBy('id', 'desc')
                .then(logs => {
                  assert.match(err, /OGR failed to open (.+)\/road-networkP3020S3020.osm, format may be unsupported/);
                  assert.lengthOf(logs, 4);
                  assert.equal(logs[0].code, 'error');
                  assert.match(logs[0].data.error, /OGR failed to open (.+)\/road-networkP3020S3020.osm, format may be unsupported/);
                })
                .then(() => done())
                .catch(err => done(err));
            } else {
              done(new Error('The test should have failed but succeeded'));
            }
          }
        };

        concludeProjectSetup(data);
      });
  });
});
<|endoftext|>


<commit_before>
/**
 * allowed_terms is a white list of Canvas enrollment_term_ids where shopping is allowed
 * for a specific school
 * NOTE - the term ids in allowed_terms must be strings, not ints
 * @type {string[]}
 */
var allowed_terms = ['3', '4', '179', '595', '596', '603', '487', '569', '1','8','447','591','597', '342'];

/**
 * check to see if the '#unauthorized_message' is being rendered  and only proceed
 * with additional checks to show shopping messages if authorized
 * @type {boolean}
 */
var authorized = $('#unauthorized_message').length > 0 ? false : true;
if (authorized){
  var un = $('ul#identity > li.user_name > a').text();
  if ( !un ) {
    $.getJSON(course_url, function( data ) {
      /*
       Check to see the course is in the 'available' (Published) state before showing
       the shopping button.
       */

      if(is_course_available(data['workflow_state']) && !on_special_page) {
        /*
         TLT-668 - only allow shopping for terms that are in the whitelist.
         */
        if (term_allowed(data['enrollment_term_id'])) {
          shopping_banner.append(no_user_canvas_login);
          $('#breadcrumbs').after(shopping_banner);
        }
      }
    });
  }
  else {
    var sis_user_id = '';
    $.getJSON(user_url, function( data ) {
      sis_user_id = get_sis_user_id(data);
      if (course_id > 0) {
        $.getJSON(course_url, function( data ) {
          /*
           Check to see the course is in the 'available' (Published) state before showing
           the shopping button.
           */
          if(is_course_available(data['workflow_state']) && !on_special_page) {
            /*
             TLT-668 - only allow shopping for terms that are in the whitelist.
             */
            if (term_allowed(data['enrollment_term_id'])) {
              var c_id = data['id'];
              if (course_id == c_id) {
                var num_enrollments = data['enrollments'].length;
                for (var n = 0; n < num_enrollments; n++) {
                  var erole = data['enrollments'][n]['role'];
                  var type =  data['enrollments'][n]['type'];
                  user_enrolled = true;
                  is_shopper = (erole == 'Shopper');
                  is_student = (erole == 'StudentEnrollment') || (erole == 'Guest');
                  is_teacher =  (type == 'teacher' || type == 'ta' ||type == 'designer' );
                }
              }

              var login_id = '?canvas_login_id=' + sis_user_id;
              var course_and_user_id_param = course_id + login_id;

              var add_shopper_url = shopping_tool_url + '/shop_course/' + course_and_user_id_param;
              var remove_shopper_url = shopping_tool_url + '/remove_shopper_role/' + course_and_user_id_param;
              var manage_shopping_page_url = shopping_tool_url + '/my_list' + login_id;

              var manage_shopping_li_item = jQuery('
', {
                id: 'manage-shopping',
                class: 'menu-item'
              });

              var manage_shopping_link = jQuery('', {
                id: 'manage-shopping-page-link',
                class: 'menu-item-no-drop',
                href: manage_shopping_page_url,
                text: "Courses I'm Shopping"
              });

              /*
               build the Manage Shopping menu item
               */
              if (user_enrolled) {
                manage_shopping_li_item.append(manage_shopping_link);

                /*
                 for each role format the appropriate banner
                 */
                if (is_shopper) {
                  $("ul#menu").append(manage_shopping_li_item);
                  shopping_banner.append(shopping_get_shopper_banner_text(remove_shopper_url));
                }
                else if (is_teacher) {
                  shopping_banner.append(shopping_get_is_active_banner_text());
                }
                else if(is_student){
                  shopping_banner.append(shopping_get_student_banner_text());
                }
                /*
                 display the banner formatted above
                 */
                if (is_shopper || is_teacher || is_student) {
                  $('#breadcrumbs').after(shopping_banner);
                }
              }else{
                /*
                 If logged in user is not enrolled, then display generic shopping message to authorized user
                 */
                $("ul#menu").append(manage_shopping_li_item);
                shopping_banner.append(shopping_get_viewer_banner_text(add_shopper_url));
                $('#breadcrumbs').after(shopping_banner);
              }
            }
          } else if (on_admin_page && term_allowed(data['enrollment_term_id'])) {
            // on course admin page for course in a whitelisted term --> disable is_public_to_auth_users
            var $iptau_checkbox = $('#course_is_public_to_auth_users');
            $iptau_checkbox.closest("div").addClass("selection-disabled");
            $iptau_checkbox.closest("span").after(' (this cannot be changed during shopping period)');
            $iptau_checkbox.attr("disabled", true);
          }
        });
      }
    });
  }
}
<commit_msg>reverting code<commit_after>
/**
 * allowed_terms is a white list of Canvas enrollment_term_ids where shopping is allowed
 * for a specific school
 * NOTE - the term ids in allowed_terms must be strings, not ints
 * @type {string[]}
 */
var allowed_terms = ['3', '4', '179', '595', '596', '603', '487', '569', '1','8','447','591','597', '342'];

var current_user_id = ENV['current_user_id'];
var user_url = '/api/v1/users/' + current_user_id + '/profile';
var course_id = get_course_number();
var course_url = '/api/v1/courses/' + course_id ;
var login_url = window.location.origin+"/login";
var shopping_tool_url = "https://icommons-tools.dev.tlt.harvard.edu/shopping";

/**
 * Tool tip text and html link
 * @type {string}
 */
var shopping_help_doc_url = 'https://wiki.harvard.edu/confluence/display/canvas/Course+Shopping';
var data_tooltip = 'More info about access during shopping period';
var tooltip_link = '';

var no_user_canvas_login = '

Students: ' +
  'login to get more access during shopping period.' + tooltip_link + '

';

var is_course = (course_id > 0);
var user_enrolled = false;
var is_shopper = false;
var is_teacher = false;
var is_student = false;

/**
 * Create the div that will hold the shoping banner
 * @type {html element}
 */
var shopping_banner = jQuery('
', {
  id: 'course-shopping',
  class: 'tltmsg'
});

/**
 * Are we on an admin page
 * @type {boolean}
 */
var on_admin_page = ((window.location.pathname).indexOf('settings') != -1);

/**
 * Are we on the speed grader page
 * @type {boolean}
 */
var on_speed_grader_page = ((window.location.pathname).indexOf('speed_grader') != -1);

/**
 * Are we on the submissions page
 * @type {boolean}
 */
var on_submissions_page = ((window.location.pathname).indexOf('submissions') != -1);

/**
 * Are we on any of the special pages described above
 * @type {boolean}
 */
var on_special_page = on_admin_page || on_speed_grader_page || on_submissions_page;

/**
 * check to see if the '#unauthorized_message' is being rendered  and only proceed
 * with additional checks to show shopping messages if authorized
 * @type {boolean}
 */
var authorized = $('#unauthorized_message').length > 0 ? false : true;
if (authorized){
  var un = $('ul#identity > li.user_name > a').text();
  if ( !un ) {
    $.getJSON(course_url, function( data ) {
      /*
       Check to see the course is in the 'available' (Published) state before showing
       the shopping button.
       */

      if(is_course_available(data['workflow_state']) && !on_special_page) {
        /*
         TLT-668 - only allow shopping for terms that are in the whitelist.
         */
        if (term_allowed(data['enrollment_term_id'])) {
          shopping_banner.append(no_user_canvas_login);
          $('#breadcrumbs').after(shopping_banner);
        }
      }
    });
  }
  else {
    var sis_user_id = '';
    $.getJSON(user_url, function( data ) {
      sis_user_id = get_sis_user_id(data);
      if (course_id > 0) {
        $.getJSON(course_url, function( data ) {
          /*
           Check to see the course is in the 'available' (Published) state before showing
           the shopping button.
           */
          if(is_course_available(data['workflow_state']) && !on_special_page) {
            /*
             TLT-668 - only allow shopping for terms that are in the whitelist.
             */
            if (term_allowed(data['enrollment_term_id'])) {
              var c_id = data['id'];
              if (course_id == c_id) {
                var num_enrollments = data['enrollments'].length;
                for (var n = 0; n < num_enrollments; n++) {
                  var erole = data['enrollments'][n]['role'];
                  var type =  data['enrollments'][n]['type'];
                  user_enrolled = true;
                  is_shopper = (erole == 'Shopper');
                  is_student = (erole == 'StudentEnrollment') || (erole == 'Guest');
                  is_teacher =  (type == 'teacher' || type == 'ta' ||type == 'designer' );
                }
              }

              var login_id = '?canvas_login_id=' + sis_user_id;
              var course_and_user_id_param = course_id + login_id;

              var add_shopper_url = shopping_tool_url + '/shop_course/' + course_and_user_id_param;
              var remove_shopper_url = shopping_tool_url + '/remove_shopper_role/' + course_and_user_id_param;
              var manage_shopping_page_url = shopping_tool_url + '/my_list' + login_id;

              var manage_shopping_li_item = jQuery('
', {
                id: 'manage-shopping',
                class: 'menu-item'
              });

              var manage_shopping_link = jQuery('', {
                id: 'manage-shopping-page-link',
                class: 'menu-item-no-drop',
                href: manage_shopping_page_url,
                text: "Courses I'm Shopping"
              });

              /*
               build the Manage Shopping menu item
               */
              if (user_enrolled) {
                manage_shopping_li_item.append(manage_shopping_link);

                /*
                 for each role format the appropriate banner
                 */
                if (is_shopper) {
                  $("ul#menu").append(manage_shopping_li_item);
                  shopping_banner.append(shopping_get_shopper_banner_text(remove_shopper_url));
                }
                else if (is_teacher) {
                  shopping_banner.append(shopping_get_is_active_banner_text());
                }
                else if(is_student){
                  shopping_banner.append(shopping_get_student_banner_text());
                }
                /*
                 display the banner formatted above
                 */
                if (is_shopper || is_teacher || is_student) {
                  $('#breadcrumbs').after(shopping_banner);
                }
              }else{
                /*
                 If logged in user is not enrolled, then display generic shopping message to authorized user
                 */
                $("ul#menu").append(manage_shopping_li_item);
                shopping_banner.append(shopping_get_viewer_banner_text(add_shopper_url));
                $('#breadcrumbs').after(shopping_banner);
              }
            }
          } else if (on_admin_page && term_allowed(data['enrollment_term_id'])) {
            // on course admin page for course in a whitelisted term --> disable is_public_to_auth_users
            var $iptau_checkbox = $('#course_is_public_to_auth_users');
            $iptau_checkbox.closest("div").addClass("selection-disabled");
            $iptau_checkbox.closest("span").after(' (this cannot be changed during shopping period)');
            $iptau_checkbox.attr("disabled", true);
          }
        });
      }
    });
  }
}
<|endoftext|>


<commit_before>FastRender.debugger = {};
FastRender.debugger._logs = [];
FastRender.debugger.log = function function_name(message/*, args..*/) {
  if(
    typeof console != 'undefined' &&
    typeof Meteor._localStorage != 'undefined' &&
    Meteor._localStorage.getItem('__frlog') == "1")
  {
    FastRender.debugger._logs.push(arguments);
    arguments[0] = "FR: " + arguments[0];
    console.log.apply(console, arguments);
  }
}

FastRender.debugger.showLogs = function() {
  Meteor._localStorage.setItem('__frlog', "1");
  location.reload();
};

FastRender.debugger.hideLogs = function() {
  Meteor._localStorage.removeItem('__frlog');
  location.reload();
};

FastRender.debugger.getLogs = function() {
  return FastRender.debugger._logs;
};

FastRender.debugger.getLogsJSON = function() {
  return JSON.stringify(FastRender.debugger._logs);
};

FastRender.debugger.blockDDP = function() {
  Meteor._localStorage.setItem('__frblockddp', "1");
  location.reload();
};

FastRender.debugger.unblockDDP = function() {
  Meteor._localStorage.removeItem('__frblockddp');
  location.reload();
};

FastRender.debugger.disableFR = function() {
  Meteor._localStorage.setItem('__frdisable', "1");
  location.reload();
};

FastRender.debugger.enableFR = function() {
  Meteor._localStorage.removeItem('__frdisable');
  location.reload();
};

FastRender.debugger.getPayload = function() {
  return FastRender._payload;
};

FastRender.debugger.getPayloadJSON = function() {
  return JSON.stringify(FastRender._payload);
};<commit_msg>Secure debugger against IE8<commit_after>FastRender["debugger"] = {};
FastRender["debugger"]._logs = [];
FastRender["debugger"].log = function function_name(message/*, args..*/) {
  if(
    typeof console != 'undefined' &&
    typeof Meteor._localStorage != 'undefined' &&
    Meteor._localStorage.getItem('__frlog') == "1")
  {
    FastRender["debugger"]._logs.push(arguments);
    arguments[0] = "FR: " + arguments[0];
    console.log.apply(console, arguments);
  }
}

FastRender["debugger"].showLogs = function() {
  Meteor._localStorage.setItem('__frlog', "1");
  location.reload();
};

FastRender["debugger"].hideLogs = function() {
  Meteor._localStorage.removeItem('__frlog');
  location.reload();
};

FastRender["debugger"].getLogs = function() {
  return FastRender.debugger._logs;
};

FastRender["debugger"].getLogsJSON = function() {
  return JSON.stringify(FastRender.debugger._logs);
};

FastRender["debugger"].blockDDP = function() {
  Meteor._localStorage.setItem('__frblockddp', "1");
  location.reload();
};

FastRender["debugger"].unblockDDP = function() {
  Meteor._localStorage.removeItem('__frblockddp');
  location.reload();
};

FastRender["debugger"].disableFR = function() {
  Meteor._localStorage.setItem('__frdisable', "1");
  location.reload();
};

FastRender["debugger"].enableFR = function() {
  Meteor._localStorage.removeItem('__frdisable');
  location.reload();
};

FastRender["debugger"].getPayload = function() {
  return FastRender._payload;
};

FastRender["debugger"].getPayloadJSON = function() {
  return JSON.stringify(FastRender._payload);
};
<|endoftext|>


<commit_before>var express = require('express'),
    exphbs  = require('express3-handlebars'),
    state   = require('../../'),

    app = express();

app.engine('hbs', exphbs());
app.set('view engine', 'hbs');

app.expose({
    flickr_api: 'asdf'
});

app.get('/', function (req, res, next) {
    res.expose({
        user      : {id: '1234'},
        flickr_api: 'fdsa'
    });

    res.expose('Eric', 'user.name');

    res.render('index');
});

app.get('/foo', function (req, res, next) {
    res.expose({
        user: {id: '1234'}
    });

    res.render('index');
});

app.expose('MY APP', 'title', 'app');

app.listen(3000);
<commit_msg>Document "../../" in example as being "express-state"<commit_after>var express = require('express'),
    exphbs  = require('express3-handlebars'),
    state   = require('../../'), // "express-state"

    app = express();

app.engine('hbs', exphbs());
app.set('view engine', 'hbs');

app.expose({
    flickr_api: 'asdf'
});

app.get('/', function (req, res, next) {
    res.expose({
        user      : {id: '1234'},
        flickr_api: 'fdsa'
    });

    res.expose('Eric', 'user.name');

    res.render('index');
});

app.get('/foo', function (req, res, next) {
    res.expose({
        user: {id: '1234'}
    });

    res.render('index');
});

app.expose('MY APP', 'title', 'app');

app.listen(3000);
<|endoftext|>


<commit_before>
/**
 * allowed_terms is a white list of Canvas enrollment_term_ids where shopping is allowed
 * for a specific school
 * NOTE - the term ids in allowed_terms must be strings, not ints
 * @type {string[]}
 */

/**
 * terms for dev
 * var allowed_terms = ['3', '4'];
 */

/**
 * updated allowed terms with correct terms before deploying to prod
 */
var allowed_terms = [];

var course_id_is_valid = (course_id > 0);
var user_enrolled = false;
var is_shopper = false;
var is_teacher = false;
var is_student = false;

/**
 * check to see if the '#unauthorized_message' is being rendered  and only proceed
 * with additional checks to show shopping messages if authorized
 * @type {boolean}
 */
var authorized = $('#unauthorized_message').length > 0 ? false : true;

if (authorized){
  var un = $('ul#identity > li.user_name > a').text();
  if ( !un ) {
    $.getJSON(course_url, function( data ) {
      /*
       Check to see the course is in the 'available' (Published) state before showing
       the shopping button.
       */
      var course_is_available = is_course_available(data['workflow_state']);
      var term_is_allowed = is_term_allowed(data['enrollment_term_id'], allowed_terms);

      if(course_is_available && !on_special_page && term_is_allowed) {
        shopping_banner.append(no_user_canvas_login);
        $('#breadcrumbs').after(shopping_banner);
      }
    });
  }
  else {
    var sis_user_id = '';
    $.getJSON(user_url, function( data ) {
      sis_user_id = get_sis_user_id(data);
      if (course_id_is_valid) {
        $.getJSON(course_url, function( data ) {

          var course_is_available = is_course_available(data['workflow_state']);
          var term_is_allowed = is_term_allowed(data['enrollment_term_id'], allowed_terms);
          var course_enrollments = data['enrollments'];
          var c_id = data['id'];

          /*
           Check to see the course is in the 'available' (Published) state before showing
           the shopping button.
           */
          if(course_is_available && !on_special_page && term_is_allowed && course_id == c_id) {
            var num_enrollments = course_enrollments.length;
            for (var n = 0; n < num_enrollments; n++) {
              var erole = course_enrollments[n]['role'];
              var type =  course_enrollments[n]['type'];
              user_enrolled = true;
              is_shopper = (erole == 'Shopper');
              is_student = (erole == 'StudentEnrollment') || (erole == 'Guest');
              is_teacher =  (type == 'teacher' || type == 'ta' ||type == 'designer' );
            }

            var login_id = '?canvas_login_id=' + sis_user_id;
            var course_and_user_id_param = course_id + login_id;
            var add_shopper_url = shopping_tool_url + '/shop_course/' + course_and_user_id_param;
            var remove_shopper_url = shopping_tool_url + '/remove_shopper_role/' + course_and_user_id_param;
            var manage_shopping_page_url = shopping_tool_url + '/my_list' + login_id;
            var manage_shopping_li_item = jQuery('
', {
              id: 'manage-shopping',
              class: 'menu-item'
            });
            var manage_shopping_link = jQuery('', {
              id: 'manage-shopping-page-link',
              class: 'menu-item-no-drop',
              href: manage_shopping_page_url,
              text: "Courses I'm Shopping"
            });
            /*
             build the Manage Shopping menu item
             */
            if (user_enrolled) {
              manage_shopping_li_item.append(manage_shopping_link);
              if (is_shopper) {
                $("ul#menu").append(manage_shopping_li_item);
                shopping_banner.append(shopping_get_shopper_banner_text(remove_shopper_url));
              }
              else if (is_teacher) {
                shopping_banner.append(shopping_get_teacher_banner_text());
              }
              else if(is_student){
                shopping_banner.append(shopping_get_student_banner_text());
              }
              if (is_shopper || is_teacher || is_student) {
                $('#breadcrumbs').after(shopping_banner);
              }
            }else{
              /*
               If logged in user is not enrolled, then display generic shopping
               message to authorized user
               */
              $("ul#menu").append(manage_shopping_li_item);
              shopping_banner.append(shopping_get_viewer_banner_text(add_shopper_url));
              $('#breadcrumbs').after(shopping_banner);
            }
          } else if (on_admin_page && term_is_allowed) {
            // on course admin page for course in a whitelisted term --> disable is_public_to_auth_users
            var $iptau_checkbox = $('#course_is_public_to_auth_users');
            $iptau_checkbox.closest("div").addClass("selection-disabled");
            $iptau_checkbox.closest("span").after(' (this cannot be changed during shopping period)');
            $iptau_checkbox.attr("disabled", true);
          }
        });
      }
    });
  }
}
<commit_msg>refactored shopping code, I put the global code back in the local school file. There was an issue with the way the javascript is executed.<commit_after>
/**
 * Create the div that will hold the shoping banner
 * @type {html element}
 */
var shopping_banner = jQuery('
', {
  id: 'course-shopping',
  class: 'tltmsg'
});

/**
 * Are we on an admin page
 * @type {boolean}
 */
var on_admin_page = ((window.location.pathname).indexOf('settings') != -1);

/**
 * Are we on the speed grader page
 * @type {boolean}
 */
var on_speed_grader_page = ((window.location.pathname).indexOf('speed_grader') != -1);

/**
 * Are we on the submissions page
 * @type {boolean}
 */
var on_submissions_page = ((window.location.pathname).indexOf('submissions') != -1);

/**
 * Are we on any of the special pages described above
 * @type {boolean}
 */
var on_special_page = on_admin_page || on_speed_grader_page || on_submissions_page;

/**
 *  get the course number for the canvas course
 * @returns {number} course_id
 */
function get_course_number() {
  var page_url = window.location.pathname;
  var pat = /\/courses\/(\d+)/g;
  var match = pat.exec(page_url);
  if (match) {
    course_id = match[1];
    return parseInt(course_id);
  }
  return 0;
}

/**
 * Return the user id from the api data
 * @param canvas_user_api_data
 * @returns {string} user_id
 */
function get_sis_user_id(canvas_user_api_data) {
  var user_id = null;
  if (canvas_user_api_data) {
    if (canvas_user_api_data['sis_user_id'] && canvas_user_api_data['sis_user_id'].trim()) {
      user_id = canvas_user_api_data['sis_user_id'].trim();
    } else if (canvas_user_api_data['login_id'] && canvas_user_api_data['login_id'].trim()) {
      user_id = canvas_user_api_data['login_id'].trim();
    }
  }
  return user_id;
}

/**
 * Check if the course workflow state is 'available'
 * @param course_workflow
 * @returns {boolean}
 */
function is_course_available(course_workflow) {
  return course_workflow.localeCompare('available') == 0;
}

/**
 * Check if the term id is in the allowed terms list
 * @param term_id
 * @returns {boolean}
 */
function is_term_allowed(term_id, allowed_terms) {
  return jQuery.inArray(term_id, allowed_terms) > -1;
}

/**
 * Get the banner text for students and guests
 * @returns {string} student_message_text
 */
function shopping_get_student_banner_text() {
  var student_message_text = '
All Harvard ID holders can view this course site during shopping ' +
    'period. ' + tooltip_link + '

Your contributions will be visible to other students who ' +
    'are also shopping this course.
';
  return student_message_text;
}

/**
 * Get the banner text for shoppers
 * @param remove_shopper_url
 * @returns {string} shopper_message_text
 */
function shopping_get_shopper_banner_text(remove_shopper_url) {
  var shopper_message_text = '

This course has been added to your shopping ' +
    'list ' + tooltip_link + '

This means that you can receive notifications, join discussions, ' +
    'watch lecture videos, and upload assignments during shopping period. Your contributions will be ' +
    'visible to other students who are also shopping this course. You will be removed from this course ' +
    'at the end of shopping period unless you officially enroll through the Registrar’s office.' +
    '

' +
    'Remove Course
';
  return shopper_message_text;
}

/**
 * Get the banner text for authenticated users (previously called viewers)
 * @param add_shopper_url
 * @returns {string} viewer_message_text
 */
function shopping_get_viewer_banner_text(add_shopper_url) {
  var viewer_message_text = '

Students: do you want to add this course to ' +
    'your shopping list?' + tooltip_link + '

Click the Add Course button to receive ' +
    'notifications, join discussions, watch lecture videos, and upload assignments. You must enroll ' +
    'through the Registrar’s office to be officially enrolled as a Student in this course.' +
    '

' +
    'Add Course
';
  return viewer_message_text;
}

/**
 * Get the banner text for teachers
 * @returns {string} shopping_is_active_message
 */
function shopping_get_teacher_banner_text() {
  var shopping_is_active_message = '
Your current class list may include Shoppers. ' + tooltip_link +
    '

All Harvard ID holders can view this course site during shopping period. Students ' +
    'can choose to add themselves as Shoppers to participate in discussions, upload assignments, watch ' +
    'lecture videos, and receive notifications for this course before they are officially enrolled. ' +
    'Student contributions will be visible to other students who are also shopping this course. At the ' +
    'end of shopping period, Shoppers who have not officially enrolled as Students or Guests in the ' +
    'course through the Registrar’s office will be removed from the class list.
';
  return shopping_is_active_message;
}

/**
 * Common shopping code
 */

var current_user_id = ENV['current_user_id'];
var user_url = '/api/v1/users/' + current_user_id + '/profile';
var course_id = get_course_number();
var course_url = '/api/v1/courses/' + course_id;
var login_url = window.location.origin+"/login";

/**
 * dev tool shopping url
 * var shopping_tool_url = "https://icommons-tools.dev.tlt.harvard.edu/shopping";
 */

var shopping_tool_url = "https://icommons-tools.tlt.harvard.edu/shopping";

/**
 * Tool tip text and html link
 * @type {string}
 */
var shopping_help_doc_url = 'https://wiki.harvard.edu/confluence/display/canvas/Course+Shopping';
var data_tooltip = 'More info about access during shopping period';
var tooltip_link = '';

var no_user_canvas_login = '

Students: ' +
  'login to get more access during shopping period.' + tooltip_link + '

';

/**
 * allowed_terms is a white list of Canvas enrollment_term_ids where shopping is allowed
 * for a specific school
 * NOTE - the term ids in allowed_terms must be strings, not ints
 * @type {string[]}
 */

/**
 * terms for dev
 * var allowed_terms = ['3', '4'];
 */

/**
 * updated allowed terms with correct terms before deploying to prod
 */
var allowed_terms = [];

var course_id_is_valid = (course_id > 0);
var user_enrolled = false;
var is_shopper = false;
var is_teacher = false;
var is_student = false;

/**
 * check to see if the '#unauthorized_message' is being rendered  and only proceed
 * with additional checks to show shopping messages if authorized
 * @type {boolean}
 */
var authorized = $('#unauthorized_message').length > 0 ? false : true;

if (authorized){
  var un = $('ul#identity > li.user_name > a').text();
  if ( !un ) {
    $.getJSON(course_url, function( data ) {
      /*
       Check to see the course is in the 'available' (Published) state before showing
       the shopping button.
       */
      var course_is_available = is_course_available(data['workflow_state']);
      var term_is_allowed = is_term_allowed(data['enrollment_term_id'], allowed_terms);

      if(course_is_available && !on_special_page && term_is_allowed) {
        shopping_banner.append(no_user_canvas_login);
        $('#breadcrumbs').after(shopping_banner);
      }
    });
  }
  else {
    var sis_user_id = '';
    $.getJSON(user_url, function( data ) {
      sis_user_id = get_sis_user_id(data);
      if (course_id_is_valid) {
        $.getJSON(course_url, function( data ) {

          var course_is_available = is_course_available(data['workflow_state']);
          var term_is_allowed = is_term_allowed(data['enrollment_term_id'], allowed_terms);
          var course_enrollments = data['enrollments'];
          var c_id = data['id'];

          /*
           Check to see the course is in the 'available' (Published) state before showing
           the shopping button.
           */
          if(course_is_available && !on_special_page && term_is_allowed && course_id == c_id) {
            var num_enrollments = course_enrollments.length;
            for (var n = 0; n < num_enrollments; n++) {
              var erole = course_enrollments[n]['role'];
              var type =  course_enrollments[n]['type'];
              user_enrolled = true;
              is_shopper = (erole == 'Shopper');
              is_student = (erole == 'StudentEnrollment') || (erole == 'Guest');
              is_teacher =  (type == 'teacher' || type == 'ta' ||type == 'designer' );
            }

            var login_id = '?canvas_login_id=' + sis_user_id;
            var course_and_user_id_param = course_id + login_id;
            var add_shopper_url = shopping_tool_url + '/shop_course/' + course_and_user_id_param;
            var remove_shopper_url = shopping_tool_url + '/remove_shopper_role/' + course_and_user_id_param;
            var manage_shopping_page_url = shopping_tool_url + '/my_list' + login_id;
            var manage_shopping_li_item = jQuery('
', {
              id: 'manage-shopping',
              class: 'menu-item'
            });
            var manage_shopping_link = jQuery('', {
              id: 'manage-shopping-page-link',
              class: 'menu-item-no-drop',
              href: manage_shopping_page_url,
              text: "Courses I'm Shopping"
            });
            /*
             build the Manage Shopping menu item
             */
            if (user_enrolled) {
              manage_shopping_li_item.append(manage_shopping_link);
              if (is_shopper) {
                $("ul#menu").append(manage_shopping_li_item);
                shopping_banner.append(shopping_get_shopper_banner_text(remove_shopper_url));
              }
              else if (is_teacher) {
                shopping_banner.append(shopping_get_teacher_banner_text());
              }
              else if(is_student){
                shopping_banner.append(shopping_get_student_banner_text());
              }
              if (is_shopper || is_teacher || is_student) {
                $('#breadcrumbs').after(shopping_banner);
              }
            }else{
              /*
               If logged in user is not enrolled, then display generic shopping
               message to authorized user
               */
              $("ul#menu").append(manage_shopping_li_item);
              shopping_banner.append(shopping_get_viewer_banner_text(add_shopper_url));
              $('#breadcrumbs').after(shopping_banner);
            }
          } else if (on_admin_page && term_is_allowed) {
            // on course admin page for course in a whitelisted term --> disable is_public_to_auth_users
            var $iptau_checkbox = $('#course_is_public_to_auth_users');
            $iptau_checkbox.closest("div").addClass("selection-disabled");
            $iptau_checkbox.closest("span").after(' (this cannot be changed during shopping period)');
            $iptau_checkbox.attr("disabled", true);
          }
        });
      }
    });
  }
}
<|endoftext|>


<commit_before>import React from 'react'
import {createReferenceInput} from 'role:@sanity/form-builder'
import client from 'client:@sanity/base/client'
import {unprefixType} from '../utils/unprefixType'
import debounce from 'debounce-promise'

function fetchSingle(id) {
  return client.fetch('*[.$id == %id]', {id}).then(response => unprefixType(response.result[0]))
}
function createHit(document) {
  return {document}
}

const ReferenceInput = createReferenceInput({
  search: debounce((query, field) => {
    const toField = field.to[0]
    if (!toField.searchField) {
      throw new TypeError(`Unable to peform search: No "searchField" specified on reference type for "${field.name}". Check your schema.`)
    }
    return client.fetch(`*[.$type == %type && .${toField.searchField} == %q]`, {
      type: `beerfiesta.${toField.type}`,
      q: query
    })
    .then(response => response.result.map(unprefixType).map(createHit))
  }, 200),

  materializeReferences(referenceIds) {
    return Promise.all(referenceIds.map(fetchSingle))
  }
})

export default function Reference(props) {
  return (

      <ReferenceInput {...props} />

[Only exact matches are supported for now!]

  )
}
Reference.valueContainer = ReferenceInput.valueContainer
<commit_msg>Use a reference browser instead of autocomplete<commit_after>import {ReferenceInput} from 'role:@sanity/form-builder'
import client from 'client:@sanity/base/client'
import {unprefixType} from '../utils/unprefixType'

function fetchSingle(id) {
  return client.fetch('*[.$id == %id]', {id}).then(response => unprefixType(response.result[0]))
}

export default ReferenceInput.createBrowser({
  fetch(field) {

    const toFieldTypes = field.to.map(toField => toField.type)

    const params = toFieldTypes.reduce((acc, toFieldType, i) => {
      acc[`toFieldType${i}`] = `beerfiesta.${toFieldType}`
      return acc
    }, {})

    const eqls = Object.keys(params).map(key => (
      `.$type == %${key}`
    )).join(' || ')

    return client.fetch(`*[${eqls}]`, params)
      .then(response => response.result.map(unprefixType))
  },
  materializeReferences(referenceIds) {
    return Promise.all(referenceIds.map(fetchSingle))
  }
})
<|endoftext|>


<commit_before>/*global document */

import React from 'react';
import dom from 'react-dom';
import Wrapper from './wrapper';
import { AppContainer } from 'react-hot-loader';

function renderIntoDom(store) {
    dom.render(
        <AppContainer>
            <Wrapper store={store}/>
        </AppContainer>,
        document.getElementById('wrap')
    );
}

export function remountContent(store) {
    renderIntoDom(store);

    if (module.hot) {
        module.hot.accept('./temp', () => {
            renderIntoDom(store);
        });
    }
}
<commit_msg>fixed the hot module matching<commit_after>/*global document */

import React from 'react';
import dom from 'react-dom';
import Wrapper from './wrapper';
import { AppContainer } from 'react-hot-loader';

function renderIntoDom(store) {
    dom.render(
        <AppContainer>
            <Wrapper store={store}/>
        </AppContainer>,
        document.getElementById('wrap')
    );
}

export function remountContent(store) {
    renderIntoDom(store);

    if (module.hot) {
        module.hot.accept('./wrapper', () => {
            renderIntoDom(store);
        });
    }
}
<|endoftext|>


<commit_before>var ChildEntityCache = require('./ChildEntityCache');

class NetworkEntities {

  constructor() {
    this.entities = {};
    this.childCache = new ChildEntityCache();
  }

  registerLocalEntity(networkId, entity) {
    this.entities[networkId] = entity;
  }

  createRemoteEntity(entityData) {
    NAF.log.write('Creating remote entity', entityData);

    var entity = document.createElement('a-entity');
    entity.setAttribute('id', 'naf-' + entityData.networkId);

    var template = entityData.template;
    var components = NAF.schemas.getComponents(template);
    this.initPosition(entity, entityData.components);
    this.initRotation(entity, entityData.components);
    this.addNetworkComponent(entity, entityData, components);
    this.entities[entityData.networkId] = entity;

    if (template) {
      entity.addEventListener('loaded', function () {

      var templateChild = entity.firstChild;
      templateChild.addEventListener('templaterendered', function () {
        var cloned = templateChild.firstChild;
	// mirror the attributes
        Array.prototype.slice.call(cloned.attributes || []).forEach(function (attr) {
          entity.setAttribute(attr.nodeName, attr.nodeValue);
        });
        // take the children
        for (var child = cloned.firstChild; child; child = cloned.firstChild) {
          cloned.removeChild(child);
          entity.appendChild(child);
        }

        cloned.pause && cloned.pause();
        templateChild.pause();
        setTimeout(function() {
          try { templateChild.removeChild(cloned); } catch (e) {}
          try { entity.removeChild(templateChild); } catch (e) {}
	  // delete?
        });
      });

      });
    }

    return entity;
  }

  initPosition(entity, componentData) {
    var hasPosition = componentData.hasOwnProperty('position');
    if (hasPosition) {
      var position = componentData.position;
      entity.setAttribute('position', position);
    }
  }

  initRotation(entity, componentData) {
    var hasRotation = componentData.hasOwnProperty('rotation');
    if (hasRotation) {
      var rotation = componentData.rotation;
      entity.setAttribute('rotation', rotation);
    }
  }

  addNetworkComponent(entity, entityData, components) {
    var networkData = {
      template: entityData.template,
      owner: entityData.owner,
      networkId: entityData.networkId,
      components: components
    };
    if (NAF.options.useShare) {
      networkData.showLocalTemplate = entityData.showTemplate;
      networkData.showRemoteTemplate = entityData.showTemplate;
      entity.setAttribute('networked-share', networkData);
    } else {
      networkData.showTemplate = entityData.showTemplate;
      entity.setAttribute('networked-remote', networkData);
    }
    entity.firstUpdateData = entityData;
  }

  updateEntity(client, dataType, entityData) {
    var isCompressed = entityData[0] == 1;
    var networkId = isCompressed ? entityData[1] : entityData.networkId;

    if (this.hasEntity(networkId)) {
      this.entities[networkId].emit('networkUpdate', {entityData: entityData}, false);
    } else if (!isCompressed) {
      this.receiveFirstUpdateFromEntity(entityData);
    }
  }

  receiveFirstUpdateFromEntity(entityData) {
    var parent = entityData.parent;
    var networkId = entityData.networkId;

    var parentNotCreatedYet = parent && !this.hasEntity(parent);
    if (parentNotCreatedYet) {
      this.childCache.addChild(parent, entityData);
    } else {
      var remoteEntity = this.createRemoteEntity(entityData);
      this.createAndAppendChildren(networkId, remoteEntity);
      this.addEntity(remoteEntity, parent);
    }
  }

  createAndAppendChildren(networkId, parentEntity) {
    var children = this.childCache.getChildren(networkId);
    for (var i = 0; i < children.length; i++) {
      var childEntity = this.createRemoteEntity(children[i]);
      parentEntity.appendChild(childEntity);
    }
  }

  addEntity(entity, parentId) {
    if (this.hasEntity(parentId)) {
      this.addEntityToParent(entity, parentId);
    } else {
      this.addEntityToScene(entity);
    }
  }

  addEntityToScene(entity) {
    var scene = document.querySelector('a-scene');
    scene.appendChild(entity);
  }

  addEntityToParent(entity, parentId) {
    var parentEl = document.getElementById('naf-' + parentId);
    parentEl.appendChild(entity);
  }

  completeSync() {
    for (var id in this.entities) {
      if (this.entities.hasOwnProperty(id)) {
        this.entities[id].emit('syncAll', null, false);
      }
    }
  }

  removeRemoteEntity(toClient, dataType, data) {
    var id = data.networkId;
    return this.removeEntity(id);
  }

  removeEntitiesFromUser(user) {
    var entityList = [];
    for (var id in this.entities) {
      var entityOwner = NAF.utils.getNetworkOwner(this.entities[id]);
      if (entityOwner == user) {
        var entity = this.removeEntity(id);
        entityList.push(entity);
      }
    }
    return entityList;
  }

  removeEntity(id) {
    if (this.hasEntity(id)) {
      var entity = this.entities[id];
      delete this.entities[id];
      entity.parentNode.removeChild(entity);
      return entity;
    } else {
      return null;
    }
  }

  getEntity(id) {
    if (this.entities.hasOwnProperty(id)) {
      return this.entities[id];
    }
    return null;
  }

  hasEntity(id) {
    return this.entities.hasOwnProperty(id);
  }
}

module.exports = NetworkEntities;
<commit_msg>support receiving inline data URI as template, so arbitrary entities can be sent across the wire now<commit_after>var ChildEntityCache = require('./ChildEntityCache');

class NetworkEntities {

  constructor() {
    this.entities = {};
    this.childCache = new ChildEntityCache();
  }

  registerLocalEntity(networkId, entity) {
    this.entities[networkId] = entity;
  }

  createRemoteEntity(entityData) {
    NAF.log.write('Creating remote entity', entityData);

    var entity = document.createElement('a-entity');
    entity.setAttribute('id', 'naf-' + entityData.networkId);

    var template = entityData.template;
    if (template.substring(0,5) === 'data:') {
      // data URI, may need to replace with blob URL
      var split = template.split(',', 2);
      var inlineData = split[1];
      var uriType = split[0].substring(5);
      var isBase64 = uriType.endsWith(';base64');
      if (isBase64) { uriType = uriType.substring(0, uriType.length - 7); }
      inlineData = isBase64 ? window.atob(inlineData) : decodeURIComponent(inlineData);
      var script = document.createElement('script');
      var id = 'tpl-' + entityData.networkId;
      script.setAttribute('id', id);
      script.setAttribute('type', uriType);
      script.innerHTML = inlineData;
      document.body.appendChild(script);
      entityData.template = template = '#' + id;
      console.log('createRemoteEntity: data URI => template ' + template);
    }
    var components = NAF.schemas.getComponents(template);
    this.initPosition(entity, entityData.components);
    this.initRotation(entity, entityData.components);
    this.addNetworkComponent(entity, entityData, components);
    this.entities[entityData.networkId] = entity;

    if (template) {
      entity.addEventListener('loaded', function () {

      var templateChild = entity.firstChild;
      templateChild.addEventListener('templaterendered', function () {
        var cloned = templateChild.firstChild;
	// mirror the attributes
        Array.prototype.slice.call(cloned.attributes || []).forEach(function (attr) {
          entity.setAttribute(attr.nodeName, attr.nodeValue);
        });
        // take the children
        for (var child = cloned.firstChild; child; child = cloned.firstChild) {
          cloned.removeChild(child);
          entity.appendChild(child);
        }

        cloned.pause && cloned.pause();
        templateChild.pause();
        setTimeout(function() {
          try { templateChild.removeChild(cloned); } catch (e) {}
          try { entity.removeChild(templateChild); } catch (e) {}
	  // delete?
        });
      });

      });
    }

    return entity;
  }

  initPosition(entity, componentData) {
    var hasPosition = componentData.hasOwnProperty('position');
    if (hasPosition) {
      var position = componentData.position;
      entity.setAttribute('position', position);
    }
  }

  initRotation(entity, componentData) {
    var hasRotation = componentData.hasOwnProperty('rotation');
    if (hasRotation) {
      var rotation = componentData.rotation;
      entity.setAttribute('rotation', rotation);
    }
  }

  addNetworkComponent(entity, entityData, components) {
    var networkData = {
      template: entityData.template,
      owner: entityData.owner,
      networkId: entityData.networkId,
      components: components
    };
    if (NAF.options.useShare) {
      networkData.showLocalTemplate = entityData.showTemplate;
      networkData.showRemoteTemplate = entityData.showTemplate;
      entity.setAttribute('networked-share', networkData);
    } else {
      networkData.showTemplate = entityData.showTemplate;
      entity.setAttribute('networked-remote', networkData);
    }
    entity.firstUpdateData = entityData;
  }

  updateEntity(client, dataType, entityData) {
    var isCompressed = entityData[0] == 1;
    var networkId = isCompressed ? entityData[1] : entityData.networkId;

    if (this.hasEntity(networkId)) {
      this.entities[networkId].emit('networkUpdate', {entityData: entityData}, false);
    } else if (!isCompressed) {
      this.receiveFirstUpdateFromEntity(entityData);
    }
  }

  receiveFirstUpdateFromEntity(entityData) {
    var parent = entityData.parent;
    var networkId = entityData.networkId;

    var parentNotCreatedYet = parent && !this.hasEntity(parent);
    if (parentNotCreatedYet) {
      this.childCache.addChild(parent, entityData);
    } else {
      var remoteEntity = this.createRemoteEntity(entityData);
      this.createAndAppendChildren(networkId, remoteEntity);
      this.addEntity(remoteEntity, parent);
    }
  }

  createAndAppendChildren(networkId, parentEntity) {
    var children = this.childCache.getChildren(networkId);
    for (var i = 0; i < children.length; i++) {
      var childEntity = this.createRemoteEntity(children[i]);
      parentEntity.appendChild(childEntity);
    }
  }

  addEntity(entity, parentId) {
    if (this.hasEntity(parentId)) {
      this.addEntityToParent(entity, parentId);
    } else {
      this.addEntityToScene(entity);
    }
  }

  addEntityToScene(entity) {
    var scene = document.querySelector('a-scene');
    scene.appendChild(entity);
  }

  addEntityToParent(entity, parentId) {
    var parentEl = document.getElementById('naf-' + parentId);
    parentEl.appendChild(entity);
  }

  completeSync() {
    for (var id in this.entities) {
      if (this.entities.hasOwnProperty(id)) {
        this.entities[id].emit('syncAll', null, false);
      }
    }
  }

  removeRemoteEntity(toClient, dataType, data) {
    var id = data.networkId;
    return this.removeEntity(id);
  }

  removeEntitiesFromUser(user) {
    var entityList = [];
    for (var id in this.entities) {
      var entityOwner = NAF.utils.getNetworkOwner(this.entities[id]);
      if (entityOwner == user) {
        var entity = this.removeEntity(id);
        entityList.push(entity);
      }
    }
    return entityList;
  }

  removeEntity(id) {
    if (this.hasEntity(id)) {
      var entity = this.entities[id];
      delete this.entities[id];
      entity.parentNode.removeChild(entity);
      return entity;
    } else {
      return null;
    }
  }

  getEntity(id) {
    if (this.entities.hasOwnProperty(id)) {
      return this.entities[id];
    }
    return null;
  }

  hasEntity(id) {
    return this.entities.hasOwnProperty(id);
  }
}

module.exports = NetworkEntities;
<|endoftext|>


<commit_before>
describe('insert_or_replace()', function () {
	it('should insert new item', function(done) {
		DynamoDB
			.table($tableName)
			.insert_or_replace({
				hash: 'hash1',
				range: 1,
				number: 5,
				array: [0,null,{},"string"],
				delete_me_later: {}
			},function(err,data) {
				if (err) {
					throw err
					return
				}
				DynamoDB
					.table($tableName)
					.where('hash').eq('hash1')
					.where('range').eq(1)
					.get(function(err,data) {
						if (err) {
							throw err
							return
						}
						assert.deepEqual(data, {hash: 'hash1', range: 1, number: 5, array: [0,null,{},"string"], delete_me_later: {} })
						done()
					})
			})
	})
	it('should replace existing item', function(done) {
		DynamoDB
			.table($tableName)
			.insert_or_replace({
				hash: 'hash1',
				range: 1,
				a: 'a'
			}, function(err) {
				DynamoDB
					.table($tableName)
					.where('hash').eq('hash1')
					.where('range').eq(1)
					.get(function(err,data) {
						if (err) {
							throw err
							return
						}
						assert.deepEqual(data, {hash: 'hash1', range: 1, a: 'a'})
						done()
					})
			})
	})
	it('test ALL_OLD  on replace for existing item', function(done) {
		DynamoDB
			.table($tableName)
			.return(DynamoDB.ALL_OLD)
			.insert_or_replace({
				hash: 'hash1',
				range: 1,
				something: 'somevalue',
			}, function(err, data ) {
				if (err) throw err

				assert.deepEqual(data, {hash: 'hash1', range: 1, a: 'a'})
				done()
			})
	})
	it('removing all items...', function(done) {
		DynamoDB
			.table($tableName)
			.scan(function(err, data) {
				if (err)
					throw err
				else {
					async.each(data, function(item,cb) {
						DynamoDB.table($tableName).where('hash').eq(item.hash).where('range').eq(item.range).delete(function(err) { cb(err) })
					}, function(err) {
						if (err)
							throw err
						else
							done()
					})
				}
			})
	})
})
<commit_msg>promise tests for insert_or_replace()<commit_after>
describe('insert_or_replace()', function () {
	it('should insert new item', function(done) {
		DynamoDB
			.table($tableName)
			.insert_or_replace({
				hash: 'hash1',
				range: 1,
				number: 5,
				array: [0,null,{},"string"],
				delete_me_later: {}
			},function(err,data) {
				if (err) {
					throw err
					return
				}
				DynamoDB
					.table($tableName)
					.where('hash').eq('hash1')
					.where('range').eq(1)
					.get(function(err,data) {
						if (err) {
							throw err
							return
						}
						assert.deepEqual(data, {hash: 'hash1', range: 1, number: 5, array: [0,null,{},"string"], delete_me_later: {} })
						done()
					})
			})
	})
	it('should replace existing item', function(done) {
		DynamoDB
			.table($tableName)
			.insert_or_replace({
				hash: 'hash1',
				range: 1,
				a: 'a'
			}, function(err) {
				DynamoDB
					.table($tableName)
					.where('hash').eq('hash1')
					.where('range').eq(1)
					.get(function(err,data) {
						if (err) {
							throw err
							return
						}
						assert.deepEqual(data, {hash: 'hash1', range: 1, a: 'a'})
						done()
					})
			})
	})
	it('test ALL_OLD  on replace for existing item', function(done) {
		DynamoDB
			.table($tableName)
			.return(DynamoDB.ALL_OLD)
			.insert_or_replace({
				hash: 'hash1',
				range: 1,
				something: 'somevalue',
			}, function(err, data ) {
				if (err) throw err

				assert.deepEqual(data, {hash: 'hash1', range: 1, a: 'a'})
				done()
			})
	})

	it('.insert_or_replace().then()', function(done) {
		DynamoDB
			.table($tableName)
			.insert_or_replace({
				hash: 'promise',
				range: 1,
			})
			.then(function(data) {
				done()
			})
	})
	it('.insert_or_replace() - unhandled', function(done) {
		DynamoDB
			.table($tableName)
			.insert_or_replace({
				hash: 1,
				range: 1,
			})
		setTimeout(function() {
			done()
		},5000)
	})
	it('.insert_or_replace().catch()', function(done) {
		DynamoDB
			.table($tableName)
			.insert_or_replace({
				hash: 1,
				range: 1,
			})
			.catch(function(err) {
				done()
			})
	})
	it('.insert_or_replace().then(,errorHandler)', function(done) {
		DynamoDB
			.table($tableName)
			.insert_or_replace({
				hash: 1,
				range: 1,
			})
			.then( null, function(err) {
				done()
			})
	})

	it('cleanup...', function(done) {
		DynamoDB
			.table($tableName)
			.scan(function(err, data) {
				if (err)
					throw err
				else {
					async.each(data, function(item,cb) {
						DynamoDB.table($tableName).where('hash').eq(item.hash).where('range').eq(item.range).delete(function(err) { cb(err) })
					}, function(err) {
						if (err)
							throw err
						else
							done()
					})
				}
			})
	})
})
<|endoftext|>


<commit_before>function ScrubberView() {
  this.makeAccessors();
  this.createDOM();
  this.attachListeners();
  this.onValueChanged = function () {};
}

ScrubberView.prototype.resize = function () {
  this.width = this.elt.offsetWidth;
  this.left = this.elt.offsetLeft;
  this.redraw();
};

ScrubberView.prototype.makeAccessors = function () {
  var value = 0;
  var min = 0;
  var max = 1;

  this.value = function (_value) {
    if (_value === undefined) return value;
    value = _value;
    this.redraw();
    this.onValueChanged(_value);
    return this;
  };

  this.min = function (_min) {
    if (_min === undefined) return min;
    min = _min;
    this.redraw();
    return this;
  };

  this.max = function (_max) {
    if (_max === undefined) return max;
    max = _max;
    this.redraw();
    return this;
  };
};

ScrubberView.prototype.createDOM = function () {
  this.elt = document.createElement('div');
  this.track = document.createElement('div');
  this.thumb = document.createElement('div');

  this.elt.className = 'scrubber';
  this.track.className = 'track';
  this.thumb.className = 'thumb';

  this.elt.appendChild(this.track);
  this.elt.appendChild(this.thumb);
};

ScrubberView.prototype.redraw = function () {

  var frac = this.value()/(this.max() - this.min());

  var translateString = "translateX(" + Math.max(0, Math.min(1, frac))*this.width + "px)";

  this.thumb.style['-webkit-transform'] = translateString;
  this.thumb.style['-ms-transform'] = translateString;
  this.thumb.style.transform = translateString;
};

ScrubberView.prototype.setValueFromPageX = function (pageX) {
  var frac = Math.min(1, Math.max((pageX - this.left)/this.width, 0));

  this.value((1-frac)*this.min() + frac*this.max());
};

ScrubberView.prototype.attachListeners = function ()  {
  var self = this;
  var mousedown = false;

  var start = function () {
    mousedown = true;
    self.resize();
  };

  this.elt.addEventListener('mousedown', start);
  this.elt.addEventListener('touchstart', start);

  document.addEventListener('mousemove', function (evt) {
    if (!mousedown) return;
    evt.preventDefault();
    self.setValueFromPageX(evt.pageX);
  });

  document.addEventListener('touchmove', function (evt) {
    if (!mousedown) return;
    evt.preventDefault();
    self.setValueFromPageX(evt.changedTouches[0].pageX);
  });

  this.elt.addEventListener('mouseup', function (evt) {
    if (!mousedown) return;
    evt.preventDefault();
    self.setValueFromPageX(evt.pageX);
  });

  this.elt.addEventListener('touchend', function (evt) {
    if (!mousedown) return;
    evt.preventDefault();
    self.setValueFromPageX(evt.changedTouches[0].pageX);
  });

  document.addEventListener('mouseup', function () {
    mousedown = false;
  });

  document.addEventListener('touchend', function (evt) {
    mousedown = false;
  });
};
<commit_msg>Check for changes in accessors before doing work/calling callbacks.<commit_after>function ScrubberView() {
  this.makeAccessors();
  this.createDOM();
  this.attachListeners();
  this.onValueChanged = function () {};
}

ScrubberView.prototype.resize = function () {
  this.width = this.elt.offsetWidth;
  this.left = this.elt.offsetLeft;
  this.redraw();
};

ScrubberView.prototype.makeAccessors = function () {
  var value = 0;
  var min = 0;
  var max = 1;

  this.value = function (_value) {
    if (_value === undefined) return value;
    if (value === _value) return this;
    value = _value;
    this.redraw();
    this.onValueChanged(_value);
    return this;
  };

  this.min = function (_min) {
    if (_min === undefined) return min;
    if (min === _min) return this;
    min = _min;
    this.redraw();
    return this;
  };

  this.max = function (_max) {
    if (_max === undefined) return max;
    if (max === _max) return this;
    max = _max;
    this.redraw();
    return this;
  };
};

ScrubberView.prototype.createDOM = function () {
  this.elt = document.createElement('div');
  this.track = document.createElement('div');
  this.thumb = document.createElement('div');

  this.elt.className = 'scrubber';
  this.track.className = 'track';
  this.thumb.className = 'thumb';

  this.elt.appendChild(this.track);
  this.elt.appendChild(this.thumb);
};

ScrubberView.prototype.redraw = function () {

  var frac = this.value()/(this.max() - this.min());

  var translateString = "translateX(" + Math.max(0, Math.min(1, frac))*this.width + "px)";

  this.thumb.style['-webkit-transform'] = translateString;
  this.thumb.style['-ms-transform'] = translateString;
  this.thumb.style.transform = translateString;
};

ScrubberView.prototype.setValueFromPageX = function (pageX) {
  var frac = Math.min(1, Math.max((pageX - this.left)/this.width, 0));

  this.value((1-frac)*this.min() + frac*this.max());
};

ScrubberView.prototype.attachListeners = function ()  {
  var self = this;
  var mousedown = false;

  var start = function () {
    mousedown = true;
    self.resize();
  };

  this.elt.addEventListener('mousedown', start);
  this.elt.addEventListener('touchstart', start);

  document.addEventListener('mousemove', function (evt) {
    if (!mousedown) return;
    evt.preventDefault();
    self.setValueFromPageX(evt.pageX);
  });

  document.addEventListener('touchmove', function (evt) {
    if (!mousedown) return;
    evt.preventDefault();
    self.setValueFromPageX(evt.changedTouches[0].pageX);
  });

  this.elt.addEventListener('mouseup', function (evt) {
    if (!mousedown) return;
    evt.preventDefault();
    self.setValueFromPageX(evt.pageX);
  });

  this.elt.addEventListener('touchend', function (evt) {
    if (!mousedown) return;
    evt.preventDefault();
    self.setValueFromPageX(evt.changedTouches[0].pageX);
  });

  document.addEventListener('mouseup', function () {
    mousedown = false;
  });

  document.addEventListener('touchend', function (evt) {
    mousedown = false;
  });
};
<|endoftext|>