<commit_before>
let pad = number => number <= 99 ? ("0"+number).slice(-2) : number;

var $loginStatus = $(".login-status");
var $lastRequestLabel = $(".last-request");
var $selectExclude = $("#exclude-pokemon");
var excludedPokemon = [];
try {
    excludedPokemon = JSON.parse(localStorage.excludedPokemon);
    console.log(excludedPokemon);
} catch (e) {}

var d = "displayPokemons" in localStorage ? localStorage.displayPokemons : 'true';
document.getElementById('pokemon-checkbox').checked = (d === 'true');
d = "displayGyms" in localStorage ? localStorage.displayGyms : 'true';
document.getElementById('gyms-checkbox').checked = (d === 'true');

$.getJSON("static/locales/pokemon.en.json").done(function(data) {
    var pokeList = []

    $.each(data, function(key, value) {
        pokeList.push( { id: key, text: value } );
    });

    $selectExclude.select2({
        placeholder: "Type to exclude Pokemon",
        data: pokeList,
    });
    $selectExclude.val(excludedPokemon).trigger("change");
});

$selectExclude.on("change", function (e) {
    excludedPokemon = $selectExclude.val().map(Number);
    localStorage.excludedPokemon = JSON.stringify(excludedPokemon);
    clearStaleMarkers();
});

var map;
function initMap() {
    map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: center_lat, lng: center_lng},
        zoom: 15,
        mapTypeControl: false,
        streetViewControl: false
    });

    marker = new google.maps.Marker({
        position: {lat: center_lat, lng: center_lng},
        map: map,
        animation: google.maps.Animation.DROP
    });
    displayCoverage();

};

function pokemonLabel(name, disappear_time, id, disappear_time, latitude, longitude) {
    disappear_date = new Date(disappear_time)

    var label = `

            ${name}
             -

                #${id}

            Disappears at ${pad(disappear_date.getHours())}:${pad(disappear_date.getMinutes())}:${pad(disappear_date.getSeconds())}
            (00m00s)

            Get Directions

`;
    return label;
};

function gymLabel(team_name, team_id, gym_points) {
    var gym_color = [ "0, 0, 0, .4", "74, 138, 202, .6", "240, 68, 58, .6", "254, 217, 40, .6" ];
    var str;
    if (team_name == 0) {
        str = `

                ${team_name}

`;
    } else {
        str = `

Gym owned by:

                Team ${team_name}

Prestige: ${gym_points}

`;
    }

    return str;
}

map_pokemons = {} // dict containing all pokemons on the map.
map_gyms = {}
var gym_types = [ "Uncontested", "Mystic", "Valor", "Instinct" ];

function setupPokemonMarker(item) {
    var myIcon = new google.maps.MarkerImage('static/icons/'+item.pokemon_id+'.png', null, null, null, new google.maps.Size(30,30));

    var marker = new google.maps.Marker({
        position: {lat: item.latitude, lng: item.longitude},
        map: map,
        icon: myIcon
    });

    marker.infoWindow = new google.maps.InfoWindow({
        content: pokemonLabel(item.pokemon_name, item.disappear_time, item.pokemon_id, item.disappear_time, item.latitude, item.longitude)
    });

    addListeners(marker);
    return marker;
};

function setupGymMarker(item) {
    var marker = new google.maps.Marker({
        position: {lat: item.latitude, lng: item.longitude},
        map: map,
        icon: 'static/forts/'+gym_types[item.team_id]+'.png'
    });

    marker.infoWindow = new google.maps.InfoWindow({
        content: gymLabel(gym_types[item.team_id], item.team_id, item.gym_points)
    });

    addListeners(marker);
    return marker;
};

function addListeners(marker){
    marker.addListener('click', function() {
        marker.infoWindow.open(map, marker);
        updateLabelDiffTime();
        marker.persist = true;
    });

    google.maps.event.addListener(marker.infoWindow,'closeclick',function(){
        marker.persist = null;
    });

    marker.addListener('mouseover', function() {
        marker.infoWindow.open(map, marker);
        updateLabelDiffTime();
    });

    marker.addListener('mouseout', function() {
        if (!marker.persist) {
            marker.infoWindow.close();
        }
    });
    return marker
};

function clearStaleMarkers(){
    $.each(map_pokemons, function(key, value) {

        if (map_pokemons[key]['disappear_time'] < new Date().getTime() ||
                excludedPokemon.indexOf(map_pokemons[key]['pokemon_id']) >= 0) {
            map_pokemons[key].marker.setMap(null);
            console.log("removing marker with key "+key);
            delete map_pokemons[key];
        }
    });
};

function updateMap() {
    $.ajax({
        url: "map-data",
        type: 'GET',
        data: {'pokemon': localStorage.displayPokemons,
               'pokestops': document.getElementById('pokestops-checkbox').checked,
               'pokestops-lured': document.getElementById('pokestops-lured-checkbox').checked,
               'gyms': localStorage.displayGyms},
        dataType: "json"
    }).done(function(result){
        statusLabels(result["server_status"]);

        $.each(result.pokemons, function(i, item){
            if (!document.getElementById('pokemon-checkbox').checked) {
                return false; // in case the checkbox was unchecked in the meantime.
            }

            if (!(item.encounter_id in map_pokemons) &&
                    excludedPokemon.indexOf(item.pokemon_id) < 0) {
                // add marker to map and item to dict
                if (item.marker) item.marker.setMap(null);
                item.marker = setupPokemonMarker(item);
                map_pokemons[item.encounter_id] = item;
            }
        });

        $.each(result.gyms, function(i, item){
            if (!document.getElementById('gyms-checkbox').checked) {
                return false; // in case the checkbox was unchecked in the meantime.
            }

            if (item.gym_id in map_gyms) {
                // if team has changed, create new marker (new icon)
                if (map_gyms[item.gym_id].team_id != item.team_id) {
                    map_gyms[item.gym_id].marker.setMap(null);
                    map_gyms[item.gym_id].marker = setupGymMarker(item);
                } else { // if it hasn't changed generate new label only (in case prestige has changed)
                    map_gyms[item.gym_id].marker.infoWindow = new google.maps.InfoWindow({
                        content: gymLabel(gym_types[item.team_id], item.team_id, item.gym_points)
                    });

                }
            }
            else { // add marker to map and item to dict
                if (item.marker) item.marker.setMap(null);
                item.marker = setupGymMarker(item);
                map_gyms[item.gym_id] = item;
            }

        });
        clearStaleMarkers();
    });
};

window.setInterval(updateMap, 10000);
updateMap();

$('#gyms-checkbox').change(function() {
    localStorage.displayGyms = this.checked;
    if(this.checked) {
        updateMap();
    } else {
        $.each(map_gyms, function(key, value) {
            map_gyms[key].marker.setMap(null);
        });
        map_gyms = {}
    }
});

$('#pokemon-checkbox').change(function() {
    localStorage.displayPokemons = this.checked;
    if(this.checked) {
        updateMap();
    } else {
        $.each(map_pokemons, function(key, value) {
            map_pokemons[key].marker.setMap(null);
        });
        map_pokemons = {}
    }
});

var coverage;
function displayCoverage() {
    $.getJSON("cover", {format: "json"}).done(function(data) {
        $.each(data, function(i, point) {
            var circle = new google.maps.Circle({
                strokeColor: '#FF0000',
                strokeOpacity: 0.6,
                strokeWeight: 1,
                fillColor: '#FF0000',
                fillOpacity: 0.08,
                clickable: false,
                map: map,
                center: point,
                radius: 100
            });
        });
    });
}

function statusLabels(status) {
    console.log("setup");
    if (status['login_time'] == 0) {
        $loginStatus.html('Login failed');
        $loginStatus.removeClass('label-success');
        $loginStatus.addClass('label-warning');
    } else {
        $loginStatus.html('Logged in');
        $loginStatus.removeClass('label-warning');
        $loginStatus.addClass('label-success');
    }

    var difference = -status['last-successful-request'];
    var hours = Math.floor(difference / 3600);
    var minutes = Math.floor(difference % 3600 / 60);
    var seconds = Math.floor(difference % 3600 % 60);
    var milli = Math.floor((difference % 3600 % 60 - seconds)*100);

    timestring = "";
    if(hours > 0) timestring += hours + "h";
    if(minutes > 0) timestring += pad(minutes) + "m";
    timestring += pad(seconds) + "." + pad(milli) + "s";
    $lastRequestLabel.html("Last scan: "+timestring+ " ago");

    console.log(difference);
    if (difference <= 2) {
        $lastRequestLabel.removeClass('label-danger');
        $lastRequestLabel.removeClass('label-warning');
        $lastRequestLabel.addClass('label-success');
    } if (difference > 2 && difference <= 10) {
        $lastRequestLabel.removeClass('label-danger');
        $lastRequestLabel.removeClass('label-success');
        $lastRequestLabel.addClass('label-warning');
    } if (difference > 10) {
        $lastRequestLabel.removeClass('label-warning');
        $lastRequestLabel.removeClass('label-success');
        $lastRequestLabel.addClass('label-danger');
    }

}

var updateLabelDiffTime = function() {
    $('.label-countdown').each(function (index, element) {
        var disappearsAt = new Date(parseInt(element.getAttribute("disappears-at")));
        var now = new Date();

        var difference = Math.abs(disappearsAt - now);
        var hours = Math.floor(difference / 36e5);
        var minutes = Math.floor((difference - (hours * 36e5)) / 6e4);
        var seconds = Math.floor((difference - (hours * 36e5) - (minutes * 6e4)) / 1e3);

        if(disappearsAt < now){
            timestring = "(expired)";
        }
        else {
            timestring = "(";
            if(hours > 0)
                timestring = hours + "h";

            timestring += ("0" + minutes).slice(-2) + "m";
            timestring += ("0" + seconds).slice(-2) + "s";
            timestring += ")";
        }

        $(element).text(timestring)
    });
};

window.setInterval(updateLabelDiffTime, 1000);
<commit_msg>fix label<commit_after>
let pad = number => number <= 99 ? ("0"+number).slice(-2) : number;

var $loginStatus = $(".login-status");
var $lastRequestLabel = $(".last-request");
var $selectExclude = $("#exclude-pokemon");
var excludedPokemon = [];
try {
    excludedPokemon = JSON.parse(localStorage.excludedPokemon);
    console.log(excludedPokemon);
} catch (e) {}

var d = "displayPokemons" in localStorage ? localStorage.displayPokemons : 'true';
document.getElementById('pokemon-checkbox').checked = (d === 'true');
d = "displayGyms" in localStorage ? localStorage.displayGyms : 'true';
document.getElementById('gyms-checkbox').checked = (d === 'true');

$.getJSON("static/locales/pokemon.en.json").done(function(data) {
    var pokeList = []

    $.each(data, function(key, value) {
        pokeList.push( { id: key, text: value } );
    });

    $selectExclude.select2({
        placeholder: "Type to exclude Pokemon",
        data: pokeList,
    });
    $selectExclude.val(excludedPokemon).trigger("change");
});

$selectExclude.on("change", function (e) {
    excludedPokemon = $selectExclude.val().map(Number);
    localStorage.excludedPokemon = JSON.stringify(excludedPokemon);
    clearStaleMarkers();
});

var map;
function initMap() {
    map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: center_lat, lng: center_lng},
        zoom: 15,
        mapTypeControl: false,
        streetViewControl: false
    });

    marker = new google.maps.Marker({
        position: {lat: center_lat, lng: center_lng},
        map: map,
        animation: google.maps.Animation.DROP
    });
    displayCoverage();

};

function pokemonLabel(name, disappear_time, id, disappear_time, latitude, longitude) {
    disappear_date = new Date(disappear_time)

    var label = `

            ${name}
             -

                #${id}

            Disappears at ${pad(disappear_date.getHours())}:${pad(disappear_date.getMinutes())}:${pad(disappear_date.getSeconds())}
            (00m00s)

            Get Directions

`;
    return label;
};

function gymLabel(team_name, team_id, gym_points) {
    var gym_color = [ "0, 0, 0, .4", "74, 138, 202, .6", "240, 68, 58, .6", "254, 217, 40, .6" ];
    var str;
    if (team_name == 0) {
        str = `

                ${team_name}

`;
    } else {
        str = `

Gym owned by:

                Team ${team_name}

Prestige: ${gym_points}

`;
    }

    return str;
}

map_pokemons = {} // dict containing all pokemons on the map.
map_gyms = {}
var gym_types = [ "Uncontested", "Mystic", "Valor", "Instinct" ];

function setupPokemonMarker(item) {
    var myIcon = new google.maps.MarkerImage('static/icons/'+item.pokemon_id+'.png', null, null, null, new google.maps.Size(30,30));

    var marker = new google.maps.Marker({
        position: {lat: item.latitude, lng: item.longitude},
        map: map,
        icon: myIcon
    });

    marker.infoWindow = new google.maps.InfoWindow({
        content: pokemonLabel(item.pokemon_name, item.disappear_time, item.pokemon_id, item.disappear_time, item.latitude, item.longitude)
    });

    addListeners(marker);
    return marker;
};

function setupGymMarker(item) {
    var marker = new google.maps.Marker({
        position: {lat: item.latitude, lng: item.longitude},
        map: map,
        icon: 'static/forts/'+gym_types[item.team_id]+'.png'
    });

    marker.infoWindow = new google.maps.InfoWindow({
        content: gymLabel(gym_types[item.team_id], item.team_id, item.gym_points)
    });

    addListeners(marker);
    return marker;
};

function addListeners(marker){
    marker.addListener('click', function() {
        marker.infoWindow.open(map, marker);
        updateLabelDiffTime();
        marker.persist = true;
    });

    google.maps.event.addListener(marker.infoWindow,'closeclick',function(){
        marker.persist = null;
    });

    marker.addListener('mouseover', function() {
        marker.infoWindow.open(map, marker);
        updateLabelDiffTime();
    });

    marker.addListener('mouseout', function() {
        if (!marker.persist) {
            marker.infoWindow.close();
        }
    });
    return marker
};

function clearStaleMarkers(){
    $.each(map_pokemons, function(key, value) {

        if (map_pokemons[key]['disappear_time'] < new Date().getTime() ||
                excludedPokemon.indexOf(map_pokemons[key]['pokemon_id']) >= 0) {
            map_pokemons[key].marker.setMap(null);
            console.log("removing marker with key "+key);
            delete map_pokemons[key];
        }
    });
};

function updateMap() {
    $.ajax({
        url: "map-data",
        type: 'GET',
        data: {'pokemon': localStorage.displayPokemons,
               'pokestops': document.getElementById('pokestops-checkbox').checked,
               'pokestops-lured': document.getElementById('pokestops-lured-checkbox').checked,
               'gyms': localStorage.displayGyms},
        dataType: "json"
    }).done(function(result){
        statusLabels(result["server_status"]);

        $.each(result.pokemons, function(i, item){
            if (!document.getElementById('pokemon-checkbox').checked) {
                return false; // in case the checkbox was unchecked in the meantime.
            }

            if (!(item.encounter_id in map_pokemons) &&
                    excludedPokemon.indexOf(item.pokemon_id) < 0) {
                // add marker to map and item to dict
                if (item.marker) item.marker.setMap(null);
                item.marker = setupPokemonMarker(item);
                map_pokemons[item.encounter_id] = item;
            }
        });

        $.each(result.gyms, function(i, item){
            if (!document.getElementById('gyms-checkbox').checked) {
                return false; // in case the checkbox was unchecked in the meantime.
            }

            if (item.gym_id in map_gyms) {
                // if team has changed, create new marker (new icon)
                if (map_gyms[item.gym_id].team_id != item.team_id) {
                    map_gyms[item.gym_id].marker.setMap(null);
                    map_gyms[item.gym_id].marker = setupGymMarker(item);
                } else { // if it hasn't changed generate new label only (in case prestige has changed)
                    map_gyms[item.gym_id].marker.infoWindow = new google.maps.InfoWindow({
                        content: gymLabel(gym_types[item.team_id], item.team_id, item.gym_points)
                    });

                }
            }
            else { // add marker to map and item to dict
                if (item.marker) item.marker.setMap(null);
                item.marker = setupGymMarker(item);
                map_gyms[item.gym_id] = item;
            }

        });
        clearStaleMarkers();
    });
};

window.setInterval(updateMap, 10000);
updateMap();

$('#gyms-checkbox').change(function() {
    localStorage.displayGyms = this.checked;
    if(this.checked) {
        updateMap();
    } else {
        $.each(map_gyms, function(key, value) {
            map_gyms[key].marker.setMap(null);
        });
        map_gyms = {}
    }
});

$('#pokemon-checkbox').change(function() {
    localStorage.displayPokemons = this.checked;
    if(this.checked) {
        updateMap();
    } else {
        $.each(map_pokemons, function(key, value) {
            map_pokemons[key].marker.setMap(null);
        });
        map_pokemons = {}
    }
});

var coverage;
function displayCoverage() {
    $.getJSON("cover", {format: "json"}).done(function(data) {
        $.each(data, function(i, point) {
            var circle = new google.maps.Circle({
                strokeColor: '#FF0000',
                strokeOpacity: 0.6,
                strokeWeight: 1,
                fillColor: '#FF0000',
                fillOpacity: 0.08,
                clickable: false,
                map: map,
                center: point,
                radius: 100
            });
        });
    });
}

function statusLabels(status) {
    console.log("setup");
    if (status['login_time'] == 0) {
        $loginStatus.html('Login failed');
        $loginStatus.removeClass('label-success');
        $loginStatus.addClass('label-warning');
    } else {
        $loginStatus.html('Logged in');
        $loginStatus.removeClass('label-warning');
        $loginStatus.addClass('label-success');
    }

    var difference = -status['last-successful-request'];
    var hours = Math.floor(difference / 3600);
    var minutes = Math.floor(difference % 3600 / 60);
    var seconds = Math.floor(difference % 3600 % 60);
    var milli = Math.floor((difference % 3600 % 60 - seconds)*100);

    if (difference > 31536000) return;

    timestring = "";
    if(hours > 0) timestring += hours + "h";
    if(minutes > 0) timestring += pad(minutes) + "m";
    timestring += pad(seconds) + "." + pad(milli) + "s";
    $lastRequestLabel.html("Last scan: "+timestring+ " ago");

    console.log(difference);
    if (difference <= 2) {
        $lastRequestLabel.removeClass('label-danger');
        $lastRequestLabel.removeClass('label-warning');
        $lastRequestLabel.addClass('label-success');
    } if (difference > 2 && difference <= 10) {
        $lastRequestLabel.removeClass('label-danger');
        $lastRequestLabel.removeClass('label-success');
        $lastRequestLabel.addClass('label-warning');
    } if (difference > 10) {
        $lastRequestLabel.removeClass('label-warning');
        $lastRequestLabel.removeClass('label-success');
        $lastRequestLabel.addClass('label-danger');
    }

}

var updateLabelDiffTime = function() {
    $('.label-countdown').each(function (index, element) {
        var disappearsAt = new Date(parseInt(element.getAttribute("disappears-at")));
        var now = new Date();

        var difference = Math.abs(disappearsAt - now);
        var hours = Math.floor(difference / 36e5);
        var minutes = Math.floor((difference - (hours * 36e5)) / 6e4);
        var seconds = Math.floor((difference - (hours * 36e5) - (minutes * 6e4)) / 1e3);

        if(disappearsAt < now){
            timestring = "(expired)";
        }
        else {
            timestring = "(";
            if(hours > 0)
                timestring = hours + "h";

            timestring += ("0" + minutes).slice(-2) + "m";
            timestring += ("0" + seconds).slice(-2) + "s";
            timestring += ")";
        }

        $(element).text(timestring)
    });
};

window.setInterval(updateLabelDiffTime, 1000);
<|endoftext|>


<commit_before>

var map;
function initMap() {
    map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: center_lat, lng: center_lng},
        zoom: 16
    });

    marker = new google.maps.Marker({
        position: {lat: center_lat, lng: center_lng},
        map: map,
        animation: google.maps.Animation.DROP
    });

};

function pokemonLabel(name, disappear_time, id, disappear_time, latitude, longitude) {
    disappear_date = new Date(disappear_time)
    let pad = number => number <= 99 ? ("0"+number).slice(-2) : number;

    var label = `

            ${name}
             -

                #${id}

            Disappears at ${pad(disappear_date.getHours())}:${pad(disappear_date.getMinutes())}:${pad(disappear_date.getSeconds())}
            (00m00s)

            Get Directions

`;
    return label;
};

map_objects = {} // dict containing all markers (pokemon, stops, gyms) on the map.

function setupPokemonMarker(item) {
    var marker = new google.maps.Marker({
        position: {lat: item.latitude, lng: item.longitude},
        map: map,
        icon: 'static/icons/'+item.pokemon_id+'.png'
    });

    item.disappear_time -= 7200000 // TODO!
    marker.infoWindow = new google.maps.InfoWindow({
        content: pokemonLabel(item.pokemon_name, item.disappear_time, item.pokemon_id, item.disappear_time, item.latitude, item.longitude)
    });

    marker.addListener('click', function() {
        marker.infoWindow.open(map, marker);
        updateLabelDiffTime();
        marker.persist = true;
    });

    google.maps.event.addListener(marker.infoWindow,'closeclick',function(){
        marker.persist = null;
    });

    marker.addListener('mouseover', function() {
        marker.infoWindow.open(map, marker);
        updateLabelDiffTime();
    });

    marker.addListener('mouseout', function() {
        if (!marker.persist) {
            marker.infoWindow.close();
        }
    });

    return marker;
};

function clearStaleMarkers(){
    $.each(map_objects, function(key, value) {

        if (map_objects[key]['disappear_time'] < new Date().getTime()) {
            map_objects[key].marker.setMap(null);
            console.log("removing marker with key "+key);
            delete map_objects[key];
        }
    });
};

function updateMap() {
    $.ajax({
        url: "/map-data",
        type: 'GET',
        data: {'pokemon': document.getElementById('pokemon-checkbox').checked,
               'pokestops': document.getElementById('pokestops-checkbox').checked,
               'pokestops-lured': document.getElementById('pokestops-lured-checkbox').checked,
               'gyms': document.getElementById('gyms-checkbox').checked},
        dataType: "json"
    }).done(function(result){
        $.each(result, function(i, item){

            if (item.encounter_id in map_objects) {
                // do nothing
            }
            else { // add marker to map and item to dict
                item.marker = setupPokemonMarker(item);
                map_objects[item.encounter_id] = item;
            }

        });
        clearStaleMarkers();
    });
};

window.setInterval(updateMap, 5000);
updateMap();

function displayCoverage() {
    $.getJSON("/cover", {format: "json"}).done(function(data) {
        var bermudaTriangle = new google.maps.Polygon({
            paths: data,
            strokeColor: '#FF0000',
            strokeOpacity: 0.8,
            strokeWeight: 1,
            fillColor: '#FF0000',
            fillOpacity: 0.15
        });
        bermudaTriangle.setMap(map);

    });
}
displayCoverage();

var updateLabelDiffTime = function() {
    $('.label-countdown').each(function (index, element) {
        var disappearsAt = new Date(parseInt(element.getAttribute("disappears-at")));
        var now = new Date();

        var difference = Math.abs(disappearsAt - now);
        var hours = Math.floor(difference / 36e5);
        var minutes = Math.floor((difference - (hours * 36e5)) / 6e4);
        var seconds = Math.floor((difference - (hours * 36e5) - (minutes * 6e4)) / 1e3);

        if(disappearsAt < now){
            timestring = "(expired)";
        }
        else {
            timestring = "(";
            if(hours > 0)
                timestring = hours + "h";

            timestring += ("0" + minutes).slice(-2) + "m";
            timestring += ("0" + seconds).slice(-2) + "s";
            timestring += ")";
        }

        $(element).text(timestring)
    });
};

window.setInterval(updateLabelDiffTime, 1000);
<commit_msg>Fixed double arguments bug<commit_after>

var map;
function initMap() {
    map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: center_lat, lng: center_lng},
        zoom: 16
    });

    marker = new google.maps.Marker({
        position: {lat: center_lat, lng: center_lng},
        map: map,
        animation: google.maps.Animation.DROP
    });

};

function pokemonLabel(name, id, disappear_time, latitude, longitude) {
    disappear_date = new Date(disappear_time)
    let pad = number => number <= 99 ? ("0"+number).slice(-2) : number;

    var label = `

            ${name}
             -

                #${id}

            Disappears at ${pad(disappear_date.getHours())}:${pad(disappear_date.getMinutes())}:${pad(disappear_date.getSeconds())}
            (00m00s)

            Get Directions

`;
    return label;
};

map_objects = {} // dict containing all markers (pokemon, stops, gyms) on the map.

function setupPokemonMarker(item) {
    var marker = new google.maps.Marker({
        position: {lat: item.latitude, lng: item.longitude},
        map: map,
        icon: 'static/icons/'+item.pokemon_id+'.png'
    });

    item.disappear_time -= 7200000 // TODO!
    marker.infoWindow = new google.maps.InfoWindow({
        content: pokemonLabel(item.pokemon_name, item.pokemon_id, item.disappear_time, item.latitude, item.longitude)
    });

    marker.addListener('click', function() {
        marker.infoWindow.open(map, marker);
        updateLabelDiffTime();
        marker.persist = true;
    });

    google.maps.event.addListener(marker.infoWindow,'closeclick',function(){
        marker.persist = null;
    });

    marker.addListener('mouseover', function() {
        marker.infoWindow.open(map, marker);
        updateLabelDiffTime();
    });

    marker.addListener('mouseout', function() {
        if (!marker.persist) {
            marker.infoWindow.close();
        }
    });

    return marker;
};

function clearStaleMarkers(){
    $.each(map_objects, function(key, value) {

        if (map_objects[key]['disappear_time'] < new Date().getTime()) {
            map_objects[key].marker.setMap(null);
            console.log("removing marker with key "+key);
            delete map_objects[key];
        }
    });
};

function updateMap() {
    $.ajax({
        url: "/map-data",
        type: 'GET',
        data: {'pokemon': document.getElementById('pokemon-checkbox').checked,
               'pokestops': document.getElementById('pokestops-checkbox').checked,
               'pokestops-lured': document.getElementById('pokestops-lured-checkbox').checked,
               'gyms': document.getElementById('gyms-checkbox').checked},
        dataType: "json"
    }).done(function(result){
        $.each(result, function(i, item){

            if (item.encounter_id in map_objects) {
                // do nothing
            }
            else { // add marker to map and item to dict
                item.marker = setupPokemonMarker(item);
                map_objects[item.encounter_id] = item;
            }

        });
        clearStaleMarkers();
    });
};

window.setInterval(updateMap, 5000);
updateMap();

function displayCoverage() {
    $.getJSON("/cover", {format: "json"}).done(function(data) {
        var bermudaTriangle = new google.maps.Polygon({
            paths: data,
            strokeColor: '#FF0000',
            strokeOpacity: 0.8,
            strokeWeight: 1,
            fillColor: '#FF0000',
            fillOpacity: 0.15
        });
        bermudaTriangle.setMap(map);

    });
}
displayCoverage();

var updateLabelDiffTime = function() {
    $('.label-countdown').each(function (index, element) {
        var disappearsAt = new Date(parseInt(element.getAttribute("disappears-at")));
        var now = new Date();

        var difference = Math.abs(disappearsAt - now);
        var hours = Math.floor(difference / 36e5);
        var minutes = Math.floor((difference - (hours * 36e5)) / 6e4);
        var seconds = Math.floor((difference - (hours * 36e5) - (minutes * 6e4)) / 1e3);

        if(disappearsAt < now){
            timestring = "(expired)";
        }
        else {
            timestring = "(";
            if(hours > 0)
                timestring = hours + "h";

            timestring += ("0" + minutes).slice(-2) + "m";
            timestring += ("0" + seconds).slice(-2) + "s";
            timestring += ")";
        }

        $(element).text(timestring)
    });
};

window.setInterval(updateLabelDiffTime, 1000);
<|endoftext|>


<commit_before>// utils
import request from '../utils/request';

// Main dependecies
import Registry from '../registry/Registry';
import IdentityModule from '../identity/IdentityModule';
import PolicyEngine from '../policy/PolicyEngine';
import MessageBus from '../bus/MessageBus';

/**
* Runtime User Agent Interface
*/
class RuntimeUA {

  constructor(sandboxFactory) {

    if (!sandboxFactory) throw new Error('The sandbox factory is a needed parameter');

    let _this = this;

    // TODO: post and return registry/hypertyRuntimeInstance to and from Back-end Service
    // for the request you can use the module request in utils;
    // the response is like: hyperty-runtime://sp1/protostub/123

    let hypertyRuntimeURL = 'hyperty-runtime://sp1/protostub/123';

    _this.registry = new Registry(hypertyRuntimeURL);
    _this.identityModule = new IdentityModule();
    _this.policyEngine = new PolicyEngine();
    _this.messageBus = new MessageBus(_this.registry);

    _this.registry.registerMessageBus(_this.messageBus);

    sandboxFactory.messageBus = _this.messageBus;
    _this.sandboxFactory = sandboxFactory;

  }

  /**
  * Accomodate interoperability in H2H and proto on the fly for newly discovered devices in M2M
  * @param  {CatalogueDataObject.HypertyDescriptor}   descriptor    descriptor
  */
  discoverHiperty(descriptor) {
    // Body...
  }

  /**
  * Register Hyperty deployed by the App that is passed as input parameter. To be used when App and Hyperties are from the same domain otherwise the RuntimeUA will raise an exception and the App has to use the loadHyperty(..) function.
  * @param  {Object} Object                   hypertyInstance
  * @param  {URL.HypertyCatalogueURL}         descriptor      descriptor
  */
  registerHyperty(hypertyInstance, descriptor) {
    // Body...
  }

  downloadHypertyCode(hypertyURL) {

  }

  /**
  * Deploy Hyperty from Catalogue URL
  * @param  {URL.URL}    hyperty hypertyInstance url;
  */
  loadHyperty(hyperty) {

    let _this = this;

    if (!hyperty) throw new Error('Hyperty descriptor url parameter is needed');

    return new Promise(function(resolve, reject) {

      let _hypertyURL;
      let _hypertySandbox;
      let _hypertyDescriptor;
      let _hypertySourceCode;
      let _hypertyConfiguration = {
        url: 'ws://193.136.93.214:9090/ws',
        runtimeURL: 'runtime:/alice'
      };

      let errorReason = function(reason) {
        // console.log('Hyperty Error:', reason);
        reject(reason);
      };

      // Get Hyperty descriptor
      return request.get(hyperty).then(function(hypertyDescriptor) {

        console.info('1: return hyperty descriptor');

        _hypertyDescriptor = hypertyDescriptor;

        // TODO: Update this variables with result of the request
        // This values are only for testes, should be removed;
        let hypertySourceCodeUrl = hyperty;

        // Get the hyperty source code
        return request.get(hypertySourceCodeUrl);
      })
      .then(function(hypertySourceCode) {

        console.info('2: return hyperty source code');
        _hypertySourceCode = hypertySourceCode;

        // TODO: remove or update this message, because we don't now if the registerHyperty have a messageBus instance or an message object;
        let message = {
          body: {
            value: 'hyperty-runtime://sp1/protostub/HelloHyperty'
          }
        };

        // Register hyperty;
        return _this.registry.registerHyperty(message, _hypertyDescriptor);
      })
      .then(function(hypertyURL) {
        console.info('3: return hyperty url, after register hyperty');

        _hypertyURL = hypertyURL;
        let inSameSandbox = true;

        // TODO: Check if the app and hyperty is in the same sandbox and
        if (inSameSandbox) {
          // TODO: getAppSandbox, this will return a promise;

          _hypertySandbox = _this.sandboxFactory.createAppSandbox();
          _hypertySandbox.deployComponent(_hypertySourceCode, _hypertyURL, _hypertyConfiguration);
        } else {
          // TODO: getHypertySandbox, this will return a promise;

          _hypertySandbox = _this.sandboxFactory.createSandbox();
          _hypertySandbox.deployComponent(_hypertySourceCode, _hypertyURL, _hypertyConfiguration);
        }

        return _hypertySandbox;
      })
      .then(function(sandboxInstance) {
        console.info('4: return the sandbox instance after check if is in the same sandbox or not');

        // Add the message bus listener
        _this.messageBus.addListener(_hypertyURL, sandboxInstance);

      })
      // .then(function(result) {
      //   console.info('5: return deploy component for sandbox status');
      // })
      .catch(errorReason);

    });

  }

  /**
  * Deploy Stub from Catalogue URL or domain url
  * @param  {URL.URL}     domain          domain
  */
  loadStub(domain) {

    let _this = this;

    if (!domain) throw new Error('domain parameter is needed');

    return new Promise(function(resolve, reject) {

      let stubDescriptor;

      // TODO: temporary address this only static for testing
      let componentDownloadURL = 'dist/VertxProtoStub.js';
      let configuration = {
        url: 'ws://193.136.93.243:9090/ws',
        runtimeURL: 'runtime:/alice'
      };

      let _stubSandbox;
      let _runtimeSandboxURL;
      let _runtimeProtoStubURL;
      let _protoStubSourceCode;

      // Discover Protocol Stub
      return _this.registry.discoverProtostub(domain).then(function(descriptor) {
        // Is registed?
        console.info('1. Proto Stub Discovered: ', descriptor);
        stubDescriptor = descriptor;
        return stubDescriptor;
      }, function(reason) {
        // is not registed?
        console.info('1. Proto Stub not found:', reason);

        // TODO: get protostub | <sp-domain>/.well-known/protostub
        // for the request you can use the module request in utils;
        // return request.get(domain);
        return {};
      })
      .then(function(descriptor) {
        console.info('2. return the ProtoStub descriptor:', descriptor);
        stubDescriptor = descriptor;

        // Get the component source code referent to component download url;
        return request.get(componentDownloadURL);
      })
      .then(function(protoStubSourceCode) {
        console.info('3. return the ProtoStub Source Code: ');
        _protoStubSourceCode = protoStubSourceCode;

        return _this.registry.registerStub(domain);
      })
      .then(function(runtimeProtoStubURL) {
        console.info('4. return the runtimeProtoStubURL, After Register Stub');
        _runtimeProtoStubURL = runtimeProtoStubURL;

        // TODO: Check on PEP (policy Engine) if we need the sandbox and check if the Sandbox Factory have the context sandbox;
        // Instantiate the Sandbox
        _stubSandbox = _this.sandboxFactory.createSandbox();

        return _this.registry.registerSandbox(_stubSandbox, domain);
      })
      .then(function(runtimeSandboxURL) {
        console.info('5: return the sandbox runtime url', runtimeSandboxURL);
        _runtimeSandboxURL = runtimeSandboxURL;

        // Deploy Component
        return _stubSandbox.deployComponent(_protoStubSourceCode, _runtimeProtoStubURL, configuration);
      }, function() {
        // TODO: delete this fallback;
        console.info('5.1: return the sandbox runtime url');
        _runtimeSandboxURL = 'ptinovacao.pt/sandbox/1234';

        // Deploy Component
        return _stubSandbox.deployComponent(_protoStubSourceCode, _runtimeProtoStubURL, configuration);
      })
      .then(function(result) {
        console.info('6: return deploy component for sandbox status');

        // Handle with deployed component
        console.log('Component is deployed');

        // Add the message bus listener
        console.info('add message bus listener to: ', _runtimeProtoStubURL, ' on ', _stubSandbox);
        _this.messageBus.addListener(_runtimeProtoStubURL, _stubSandbox);

        // Load Stub function resolved with success;
        resolve('Stub successfully loaded');
      })
      .catch(function(reason) {
        console.log('Reason:', reason);
      });

    });

  }

  /**
  * Used to check for updates about components handled in the Catalogue including protocol stubs and Hyperties. check relationship with lifecycle management provided by Service Workers
  * @param  {CatalogueURL}       url url
  */
  checkForUpdate(url) {
    // Body...
  }

}

export default RuntimeUA;
<commit_msg>Update RuntimeUA.js<commit_after>// utils
import request from '../utils/request';

// Main dependecies
import Registry from '../registry/Registry';
import IdentityModule from '../identity/IdentityModule';
import PolicyEngine from '../policy/PolicyEngine';
import MessageBus from '../bus/MessageBus';

/**
* Runtime User Agent Interface
*/
class RuntimeUA {

  constructor(sandboxFactory) {

    if (!sandboxFactory) throw new Error('The sandbox factory is a needed parameter');

    let _this = this;

    // TODO: post and return registry/hypertyRuntimeInstance to and from Back-end Service
    // for the request you can use the module request in utils;
    // the response is like: hyperty-runtime://sp1/protostub/123

    let hypertyRuntimeURL = 'hyperty-runtime://sp1/protostub/123';

    _this.registry = new Registry(hypertyRuntimeURL);
    _this.identityModule = new IdentityModule();
    _this.policyEngine = new PolicyEngine();
    _this.messageBus = new MessageBus(_this.registry);

    _this.registry.registerMessageBus(_this.messageBus);

    sandboxFactory.messageBus = _this.messageBus;
    _this.sandboxFactory = sandboxFactory;

  }

  /**
  * Accomodate interoperability in H2H and proto on the fly for newly discovered devices in M2M
  * @param  {CatalogueDataObject.HypertyDescriptor}   descriptor    descriptor
  */
  discoverHiperty(descriptor) {
    // Body...
  }

  /**
  * Register Hyperty deployed by the App that is passed as input parameter. To be used when App and Hyperties are from the same domain otherwise the RuntimeUA will raise an exception and the App has to use the loadHyperty(..) function.
  * @param  {Object} Object                   hypertyInstance
  * @param  {URL.HypertyCatalogueURL}         descriptor      descriptor
  */
  registerHyperty(hypertyInstance, descriptor) {
    // Body...
  }

  downloadHypertyCode(hypertyURL) {

  }

  /**
  * Deploy Hyperty from Catalogue URL
  * @param  {URL.URL}    hyperty hypertyInstance url;
  */
  loadHyperty(hyperty) {

    let _this = this;

    if (!hyperty) throw new Error('Hyperty descriptor url parameter is needed');

    return new Promise(function(resolve, reject) {

      let _hypertyURL;
      let _hypertySandbox;
      let _hypertyDescriptor;
      let _hypertySourceCode;
      let _hypertyConfiguration = {
        url: 'ws://193.136.93.214:9090/ws',
        runtimeURL: 'runtime:/alice'
      };

      let errorReason = function(reason) {
        // console.log('Hyperty Error:', reason);
        reject(reason);
      };

      // Get Hyperty descriptor
      return request.get(hyperty).then(function(hypertyDescriptor) {

        // hyperty contains the full path of the catalogue URL, e.g.
        // catalogue.rethink.eu/.well-known/..........

        console.info('1: return hyperty descriptor');

        _hypertyDescriptor = hypertyDescriptor;

        // TODO: Update this variables with result of the request
        // This values are only for testes, should be removed;
        // TODO: need to extract the hypertySourceCodeURL from _hypertyDescriptor.
        // This can be simple done by extending the hyperty URL that was passed
        // before, since we have well-known path components.
        let hypertySourceCodeUrl = hyperty;

        // Get the hyperty source code
        return request.get(hypertySourceCodeUrl);
      })
      .then(function(hypertySourceCode) {

        console.info('2: return hyperty source code');
        _hypertySourceCode = hypertySourceCode;

        // at this point, we have completed "step 4" as shown in https://github.com/reTHINK-project/core-framework/blob/master/docs/specs/runtime/dynamic-view/basics/deploy-hyperty.md

        // TODO: remove or update this message, because we don't now if the registerHyperty have a messageBus instance or an message object;
        // can be ignored, was for initial testing
        // The following is just a test "message" to make things work.  At this point, it is
        // entirely unclear what this "message" is supposed to be.  This part of the code needs to be implemented
        // by the provided of the registry class.
        //
        // message.body.value has to contain the path to the runtime hyperty instance.
        //
        //
        // After discussion between PTN and Fokus on 2015-10-29, the message parameter of registry.registerHyperty() does
        // make no sence and should be skipped.
        //
        // TODO: Paulo will open an issue to discuss this problem.  Issue to be closed on Monday, in which the decision
        // will take place if the message parameter will be dropped.
        // Attention: dropping the message parameter requries changing the existing specification, im particular the
        // message sequence diagrams.
        // https://github.com/reTHINK-project/core-framework/blob/master/docs/specs/runtime/dynamic-view/basics/register-hyperty.md
        // https://github.com/reTHINK-project/core-framework/blob/master/docs/specs/runtime/dynamic-view/basics/deploy-hyperty.md
         let message = {
          body: {
            value: 'hyperty-runtime://sp1/protostub/HelloHyperty'
          }
         };

        // Register hyperty;
        return _this.registry.registerHyperty(message, _hypertyDescriptor);
      })
      .then(function(hypertyURL) {
        // hypertyURL is the URL to the instantiated hyperty.

        // we have completed step 7 of https://github.com/reTHINK-project/core-framework/blob/master/docs/specs/runtime/dynamic-view/basics/deploy-hyperty.md right now.
        //
        // steps 8 -- 11 are skipped.
        //
        // As a result of the sipped steps, we know at this point if we execute
        // inSameSandbox or not.
        console.info('3: return hyperty url, after register hyperty');

        _hypertyURL = hypertyURL;

        // For testing, just assume we execute in same Sandbox.
        let inSameSandbox = true;

        // TODO: Check if the app and hyperty is in the same sandbox and
        if (inSameSandbox) {
          // Steps 12 -- 18

          // the following one lines are the mock-up for the missing steps 12 & 13
          // TODO: getAppSandbox, this will return a promise;
          _hypertySandbox = _this.sandboxFactory.createAppSandbox();

          // step 14
          // Discussion between PT and Fokus 2015-10-29:  unclear if deployComponent returns a
          // promise or not. Align with spec as well: https://github.com/reTHINK-project/core-framework/blob/master/docs/specs/runtime/dynamic-view/basics/deploy-hyperty.md
          _hypertySandbox.deployComponent(_hypertySourceCode, _hypertyURL, _hypertyConfiguration);

          // we have completed step 16 here.

          // Note, steps 17 & 18 are not part of the if-statement as the appear both at the end of the
          // if statement and of the else statement.  --> common code taken outside
          // TODO:  Spec needs to be aligned, we need to exlude steps 17 & 18 from the two alternatives.

        } else {
          // Steps 19 -- 28
          // TODO: getHypertySandbox, this will return a promise;

          _hypertySandbox = _this.sandboxFactory.createSandbox();
          _hypertySandbox.deployComponent(_hypertySourceCode, _hypertyURL, _hypertyConfiguration);
        }

        return _hypertySandbox;
      })
      .then(function(sandboxInstance) {
        console.info('4: return the sandbox instance after check if is in the same sandbox or not');

        // Add the message bus listener
        _this.messageBus.addListener(_hypertyURL, sandboxInstance);

      })
      // .then(function(result) {
      //   console.info('5: return deploy component for sandbox status');
      // })
      .catch(errorReason);

    });

  }

  /**
  * Deploy Stub from Catalogue URL or domain url
  * @param  {URL.URL}     domain          domain
  */
  loadStub(domain) {

    let _this = this;

    if (!domain) throw new Error('domain parameter is needed');

    return new Promise(function(resolve, reject) {

      let stubDescriptor;

      // TODO: temporary address this only static for testing
      let componentDownloadURL = 'dist/VertxProtoStub.js';
      let configuration = {
        url: 'ws://193.136.93.243:9090/ws',
        runtimeURL: 'runtime:/alice'
      };

      let _stubSandbox;
      let _runtimeSandboxURL;
      let _runtimeProtoStubURL;
      let _protoStubSourceCode;

      // Discover Protocol Stub
      return _this.registry.discoverProtostub(domain).then(function(descriptor) {
        // Is registed?
        console.info('1. Proto Stub Discovered: ', descriptor);
        stubDescriptor = descriptor;
        return stubDescriptor;
      }, function(reason) {
        // is not registed?
        console.info('1. Proto Stub not found:', reason);

        // TODO: get protostub | <sp-domain>/.well-known/protostub
        // for the request you can use the module request in utils;
        // return request.get(domain);
        return {};
      })
      .then(function(descriptor) {
        console.info('2. return the ProtoStub descriptor:', descriptor);
        stubDescriptor = descriptor;

        // Get the component source code referent to component download url;
        return request.get(componentDownloadURL);
      })
      .then(function(protoStubSourceCode) {
        console.info('3. return the ProtoStub Source Code: ');
        _protoStubSourceCode = protoStubSourceCode;

        return _this.registry.registerStub(domain);
      })
      .then(function(runtimeProtoStubURL) {
        console.info('4. return the runtimeProtoStubURL, After Register Stub');
        _runtimeProtoStubURL = runtimeProtoStubURL;

        // TODO: Check on PEP (policy Engine) if we need the sandbox and check if the Sandbox Factory have the context sandbox;
        // Instantiate the Sandbox
        _stubSandbox = _this.sandboxFactory.createSandbox();

        return _this.registry.registerSandbox(_stubSandbox, domain);
      })
      .then(function(runtimeSandboxURL) {
        console.info('5: return the sandbox runtime url', runtimeSandboxURL);
        _runtimeSandboxURL = runtimeSandboxURL;

        // Deploy Component
        return _stubSandbox.deployComponent(_protoStubSourceCode, _runtimeProtoStubURL, configuration);
      }, function() {
        // TODO: delete this fallback;
        console.info('5.1: return the sandbox runtime url');
        _runtimeSandboxURL = 'ptinovacao.pt/sandbox/1234';

        // Deploy Component
        return _stubSandbox.deployComponent(_protoStubSourceCode, _runtimeProtoStubURL, configuration);
      })
      .then(function(result) {
        console.info('6: return deploy component for sandbox status');

        // Handle with deployed component
        console.log('Component is deployed');

        // Add the message bus listener
        console.info('add message bus listener to: ', _runtimeProtoStubURL, ' on ', _stubSandbox);
        _this.messageBus.addListener(_runtimeProtoStubURL, _stubSandbox);

        // Load Stub function resolved with success;
        resolve('Stub successfully loaded');
      })
      .catch(function(reason) {
        console.log('Reason:', reason);
      });

    });

  }

  /**
  * Used to check for updates about components handled in the Catalogue including protocol stubs and Hyperties. check relationship with lifecycle management provided by Service Workers
  * @param  {CatalogueURL}       url url
  */
  checkForUpdate(url) {
    // Body...
  }

}

export default RuntimeUA;
<|endoftext|>


<commit_before>import io from 'socket.io-client';
import { isEmpty } from '../helpers/util';
import { takeEvery, call, put, take } from 'redux-saga/effects';
import { eventChannel } from 'redux-saga';
import { typingActions as typingActionTypes,
         competitionActions as competitionActionTypes } from '../actions/action-types';
import * as competitionActions from '../actions/competition';
import * as competition from '../fetch/competition';

/*
 * Watchers
 */
export function* watchTypingTestEnd() {
  yield takeEvery(typingActionTypes.TYPINGTEST_DONE, storeResult);
}

export function* watchCompetitionLoad() {
  yield takeEvery(competitionActionTypes.COMPETITION_LOAD_REQUEST, loadCompetition);
}

export function* watchCompetitionCreate() {
  yield takeEvery(competitionActionTypes.COMPETITION_CREATE_REQUEST, createCompetition);
}

export function* watchCompetitionListUpdate() {
  const socket = yield call(getSocket);
  const socketChannel = yield call(createEventChannel, socket, 'competitionListUpdate');

  while (true) {
    const competitions = yield take(socketChannel);
    // Competition results come as an object (that maps from user id to a result)
    // from the back-end. It's more suitable for the front-end to process the
    // results as an array, so let's convert.
    Object.keys(competitions).forEach(compId => {
      const comp = competitions[compId];
      let results = [];

      if (!isEmpty(comp.results)) {
        Object.keys(comp.results).forEach(userId => {
          results.push(comp.results[userId]);
        });
      }
      comp.results = results;
    });
    yield put(competitionActions.updateCompetitionList(competitions));
  }
}

export function* watchCompetitionResultsUpdate() {
  const socket = yield call(getSocket);
  const socketChannel = yield call(createEventChannel, socket, 'competitionResultsUpdate');

  while (true) {
    const data = yield take(socketChannel);
    const competitionId = parseInt(data.competition, 10);
    // Sort results by wpm in descending order.
    // Better of two equal WPM results will be the one that was
    // typed first.
    let results = [];
    for (let userId in data.results) {
      if (data.results.hasOwnProperty(userId))
        results.push(data.results[userId]);
    }
    yield put(competitionActions.updateCompetitionResults(competitionId,
      results.sort((a, b) => {
        if (a.wpm > b.wpm)
          return -1;
        else if (a.wpm < b.wpm)
          return 1;
        else
          return a.endTime - b.endTime;
      })
    ));
  }
}

/*
 * Workers
 */

/*
 * Save a competition results
 */
function* storeResult(action) {
  const { userId, competitionId, wpm, acc, startTime, endTime } = action;
  let response = yield call(competition.saveResult, userId, competitionId,
                                                     wpm, acc, startTime, endTime);

  switch(response.status) {
    case 201:
      yield* put(competitionActions.saveResultSuccess());
      yield* put(competitionActions.requestLoadCompetition(competitionId));
      break;
    default:
      // TODO: handle error
      break;
  }
}

/*
 * Fetches all results for a competition.
 */
function* loadCompetition(action) {
  let response = yield call(competition.loadCompetition, action.competitionId);

  switch(response.status) {
    case 200:
      const body = yield call(() => response.json().then(data => data));
      yield put(competitionActions.loadCompetitionSuccess(body.id, body));
      break;
    default:
      yield put(competitionActions.loadCompetitionFail());
  }
}

function* createCompetition(action) {
  let response = yield call(competition.createCompetition, action.language, action.content);

  switch(response.status) {
    case 201:
      yield put(competitionActions.createCompetitionSuccess());
      break;
    case 401:
    case 500:
      yield put(competitionActions.createCompetitionFail());
      break;
    default:
      break;
  }
}

// Creates an event channel that emits websocket events
function createEventChannel(socket, event) {
  return eventChannel(emit => {
    socket.on(event, e => emit(e));
    return () => socket.close();
  });
}

// Websocket connection
let socket = null;

function getSocket() {
  if (socket === null)
    socket = io();

  return socket;
}
<commit_msg>Keep competition results sorted<commit_after>import io from 'socket.io-client';
import { isEmpty } from '../helpers/util';
import { takeEvery, call, put, take } from 'redux-saga/effects';
import { eventChannel } from 'redux-saga';
import { typingActions as typingActionTypes,
         competitionActions as competitionActionTypes } from '../actions/action-types';
import * as competitionActions from '../actions/competition';
import * as competition from '../fetch/competition';

/*
 * Watchers
 */
export function* watchTypingTestEnd() {
  yield takeEvery(typingActionTypes.TYPINGTEST_DONE, storeResult);
}

export function* watchCompetitionLoad() {
  yield takeEvery(competitionActionTypes.COMPETITION_LOAD_REQUEST, loadCompetition);
}

export function* watchCompetitionCreate() {
  yield takeEvery(competitionActionTypes.COMPETITION_CREATE_REQUEST, createCompetition);
}

export function* watchCompetitionListUpdate() {
  const socket = yield call(getSocket);
  const socketChannel = yield call(createEventChannel, socket, 'competitionListUpdate');

  while (true) {
    const competitions = yield take(socketChannel);
    // Competition results come as an object (that maps from user id to a result)
    // from the back-end. It's more suitable for the front-end to process the
    // results as an array, so let's convert.
    Object.keys(competitions).forEach(compId => {
      const comp = competitions[compId];
      let results = [];

      if (!isEmpty(comp.results)) {
        Object.keys(comp.results).forEach(userId => {
          results.push(comp.results[userId]);
        });
      }
      comp.results = sortResults(results);
    });
    yield put(competitionActions.updateCompetitionList(competitions));
  }
}

export function* watchCompetitionResultsUpdate() {
  const socket = yield call(getSocket);
  const socketChannel = yield call(createEventChannel, socket, 'competitionResultsUpdate');

  while (true) {
    const data = yield take(socketChannel);
    const competitionId = parseInt(data.competition, 10);
    let results = [];
    for (let userId in data.results) {
      if (data.results.hasOwnProperty(userId))
        results.push(data.results[userId]);
    }
    yield put(competitionActions.updateCompetitionResults(competitionId, sortResults(results)));
  }
}

/*
 * Workers
 */

/*
 * Save a competition results
 */
function* storeResult(action) {
  const { userId, competitionId, wpm, acc, startTime, endTime } = action;
  let response = yield call(competition.saveResult, userId, competitionId,
                                                     wpm, acc, startTime, endTime);

  switch(response.status) {
    case 201:
      yield* put(competitionActions.saveResultSuccess());
      yield* put(competitionActions.requestLoadCompetition(competitionId));
      break;
    default:
      // TODO: handle error
      break;
  }
}

/*
 * Fetches all results for a competition.
 */
function* loadCompetition(action) {
  let response = yield call(competition.loadCompetition, action.competitionId);

  switch(response.status) {
    case 200:
      const body = yield call(() => response.json().then(data => data));
      yield put(competitionActions.loadCompetitionSuccess(body.id, body));
      break;
    default:
      yield put(competitionActions.loadCompetitionFail());
  }
}

function* createCompetition(action) {
  let response = yield call(competition.createCompetition, action.language, action.content);

  switch(response.status) {
    case 201:
      yield put(competitionActions.createCompetitionSuccess());
      break;
    case 401:
    case 500:
      yield put(competitionActions.createCompetitionFail());
      break;
    default:
      break;
  }
}

// Creates an event channel that emits websocket events
function createEventChannel(socket, event) {
  return eventChannel(emit => {
    socket.on(event, e => emit(e));
    return () => socket.close();
  });
}

// Sorts competition result array
function sortResults(results) {
  return results.sort((a, b) => {
    // Sort results by wpm in descending order.
    // Better of two equal WPM results will be the one that was
    // typed first.
    if (a.wpm > b.wpm)
      return -1;
    else if (a.wpm < b.wpm)
      return 1;
    else
      return a.endTime - b.endTime;
  });
}

// Websocket connection
let socket = null;

function getSocket() {
  if (socket === null)
    socket = io();

  return socket;
}
<|endoftext|>


<commit_before>/**
 * @name pc.scene
 * @namespace High level Graphics API
 */
pc.scene = {
    BLEND_SUBTRACTIVE: 0,
    BLEND_ADDITIVE: 1,
    BLEND_NORMAL: 2,
    BLEND_NONE: 3,
    BLEND_PREMULTIPLIED: 4,
    BLEND_MULTIPLICATIVE: 5,

    RENDERSTYLE_SOLID: 0,
    RENDERSTYLE_WIREFRAME: 1,
    RENDERSTYLE_POINTS: 2,

    LAYER_HUD: 0,
    LAYER_GIZMO: 1,
    LAYER_FX: 2,
    LAYER_WORLD: 3,

    /**
     * @enum pc.scene.FOG
     * @name pc.scene.FOG_NONE
     * @description No fog is applied to the scene.
     */
    FOG_NONE: 'none',
    /**
     * @enum pc.scene.FOG
     * @name pc.scene.FOG_LINEAR
     * @description Fog rises linearly from zero to 1 between a start and end depth.
     */
    FOG_LINEAR: 'linear',
    /**
     * @enum pc.scene.FOG
     * @name pc.scene.FOG_EXP
     * @description Fog rises according to an exponential curve controlled by a density value.
     */
    FOG_EXP: 'exp',
    /**
     * @enum pc.scene.FOG
     * @name pc.scene.FOG_EXP2
     * @description Fog rises according to an exponential curve controlled by a density value.
     */
    FOG_EXP2: 'exp2',

    TONEMAP_LINEAR: 0,
    TONEMAP_FILMIC: 1,

    SPECULAR_PHONG: 0,
    SPECULAR_BLINN: 1,

    FRESNEL_NONE: 0,
    FRESNEL_SIMPLE: 1,
    FRESNEL_SCHLICK: 2,
    FRESNEL_COMPLEX: 3
};

pc.extend(pc.scene, function () {

    /**
     * @name pc.scene.Scene
     * @class A scene is a container for models, lights and cameras. Scenes are rendered via a renderer.
     * PlayCanvas currently only supports a single renderer: the forward renderer (pc.scene.ForwardRenderer).
     * @constructor Creates a new scene.
     * @property {pc.Color} ambientLight The color of the scene's ambient light.
     * @property {String} fog The type of fog used by the scene (see pc.scene.FOG_).
     * @property {pc.Color} fogColor The color of the fog, in enabled.
     * @property {Number} fogDensity The density of the fog. This property is only valid if the fog property
     * is set to pc.scene.FOG_EXP or pc.scene.FOG_EXP2.
     * @property {Number} fogEnd The distance from the viewpoint where linear fog reaches its maximum. This
     * property is only valid if the fog property is set to pc.scene.FOG_LINEAR.
     * @property {Number} fogStart The distance from the viewpoint where linear fog begins. This property is
     * only valid if the fog property is set to pc.scene.FOG_LINEAR.
     * @property {Number} shadowDistance The distance from the viewpoint beyond which shadows are no longer
     * @property {Boolean} gammaCorrection If true then all materials will apply gamma correction
     * rendered.
     */
    var Scene = function Scene() {
        this.drawCalls = [];     // All mesh instances and commands
        this.shadowCasters = []; // All mesh instances that cast shadows

        this.fog = pc.scene.FOG_NONE;
        this.fogColor = new pc.Color(0, 0, 0);
        this.fogStart = 1;
        this.fogEnd = 1000;
        this.fogDensity = 0;

        this.ambientLight = new pc.Color(0, 0, 0);

        this.shadowDistance = 40;
        this._gammaCorrection = false;
        this._toneMapping = 0;
        this.exposure = 1.0;

        this._prefilteredCubeMapPreset = null;
        this._prefilteredCubeMap128 = null;
        this._prefilteredCubeMap64 = null;
        this._prefilteredCubeMap32 = null;
        this._prefilteredCubeMap16 = null;
        this._prefilteredCubeMap8 = null;
        this._prefilteredCubeMap4 = null;

        // Models
        this._models = [];

        // Lights
        this._lights = [];
        this._globalLights = []; // All currently enabled directionals
        this._localLights = [[], []]; // All currently enabled points and spots

        this.updateShaders = true;
    };

    Object.defineProperty(Scene.prototype, 'fog', {
        get: function () {
            return this._fog;
        },
        set: function (type) {
            if (type !== this._fog) {
                this._fog = type;
                this.updateShaders = true;
            }
        }
    });

    Object.defineProperty(Scene.prototype, 'gammaCorrection', {
        get: function () {
            return this._gammaCorrection;
        },
        set: function (value) {
            if (value !== this._gammaCorrection) {
                this._gammaCorrection = value;
                pc.gfx.shaderChunks.defaultGamma = value ? pc.gfx.shaderChunks.gamma2_2PS : pc.gfx.shaderChunks.gamma1_0PS;
                this.updateShaders = true;
            }
        }
    });

    Object.defineProperty(Scene.prototype, 'toneMapping', {
        get: function () {
            return this._toneMapping;
        },
        set: function (value) {
            if (value !== this._toneMapping) {
                this._toneMapping = value;
                pc.gfx.shaderChunks.defaultTonemapping = value ? pc.gfx.shaderChunks.tonemappingFilmicPS : pc.gfx.shaderChunks.tonemappingLinearPS;
                this.updateShaders = true;
            }
        }
    });

    Object.defineProperty(Scene.prototype, 'prefilteredCubeMapPreset', {
        get: function () {
            return this._prefilteredCubeMapPreset;
        },
        set: function (value) {
            if (value !== this._prefilteredCubeMapPreset) {
                this._prefilteredCubeMapPreset = value;
                this._prefilteredCubeMap128 = null;
                this._prefilteredCubeMap64 = null;
                this._prefilteredCubeMap32 = null;
                this._prefilteredCubeMap16 = null;
                this._prefilteredCubeMap8 = null;
                this._prefilteredCubeMap4 = null;
                this.updateShaders = true;
            }
        }
    });

    // Shaders have to be updated if:
    // - the fog mode changes
    // - lights are added or removed
    // - gamma correction changes
    Scene.prototype._updateShaders = function (device) {
        var i;

        if (this._prefilteredCubeMapPreset) {
            if ((!this._prefilteredCubeMap128) || (!this._prefilteredCubeMap64) || (!this._prefilteredCubeMap32)
                 || (!this._prefilteredCubeMap16) || (!this._prefilteredCubeMap8) || (!this._prefilteredCubeMap4)) {
                // Did I ever tell you the definition of hacks?
                var cubeName = this._prefilteredCubeMapPreset;
                var resources = [];
                var loaded = 0;
                var scene = this;
                for(var mip=0; mip<6; mip++) {
                    for(var face=0; face<6; face++) {
                        var loadId = mip * 6 + face;
                        resources[loadId] = new Image();
                        resources[loadId].crossOrigin = "anonymous"; // for local testing and just in case
                        resources[loadId].onload = function () {
                            loaded++;
                            if (loaded >= 36) {
                                var cubeMaps = [];
                                for(var mip2=0; mip2<6; mip2++) {
                                    sources = [];
                                    for (var face2=0; face2<6; face2++) {
                                        sources[face2] = resources[mip2 * 6 + face2];
                                    }
                                    cubeMaps[mip2] = new pc.gfx.Texture(device, {
                                        cubemap: true,
                                        hdr: true
                                    });
                                    cubeMaps[mip2].setSource(sources);
                                }
                                scene._prefilteredCubeMap128 = cubeMaps[0];
                                scene._prefilteredCubeMap64 = cubeMaps[1];
                                scene._prefilteredCubeMap32 = cubeMaps[2];
                                scene._prefilteredCubeMap16 = cubeMaps[3];
                                scene._prefilteredCubeMap8 = cubeMaps[4];
                                scene._prefilteredCubeMap4 = cubeMaps[5];
                                scene.updateShaders = true;
                            }
                        };
                        resources[loadId].src = "http://static.playcanvas.com/cubemaps/hdr/"+cubeName+"/"+cubeName+"_m0"+mip+"_c0"+face+".png";
                     }
                }
            }
        } else {
            this._prefilteredCubeMap128 = null;
            this._prefilteredCubeMap64 = null;
            this._prefilteredCubeMap32 = null;
            this._prefilteredCubeMap16 = null;
            this._prefilteredCubeMap8 = null;
            this._prefilteredCubeMap4 = null;
        }

        var materials = [];
        var drawCalls = this.drawCalls;
        for (i = 0; i < drawCalls.length; i++) {
            var drawCall = drawCalls[i];
            if (drawCall.material !== undefined) {
                if (materials.indexOf(drawCall.material) === -1) {
                    materials.push(drawCall.material);
                }
            }
        }
        for (i = 0; i < materials.length; i++) {
            materials[i].updateShader(device, this);
        }
    };

    Scene.prototype.getModels = function () {
        return this._models;
    };

    /**
     * @function
     * @name pc.scene.Scene#addModel
     * @description Adds the specified model to the scene.
     * @author Will Eastcott
     */
    Scene.prototype.addModel = function (model) {
        var i;

        // Check the model is not already in the scene
        var index = this._models.indexOf(model);
        if (index === -1) {
            this._models.push(model);

            var materials = model.getMaterials();
            for (i = 0; i < materials.length; i++) {
                materials[i].scene = this;
            }

            // Insert the model's mesh instances into lists ready for rendering
            var meshInstance;
            var numMeshInstances = model.meshInstances.length;
            for (i = 0; i < numMeshInstances; i++) {
                meshInstance = model.meshInstances[i];
                if (this.drawCalls.indexOf(meshInstance) === -1) {
                    this.drawCalls.push(meshInstance);
                }
                if (meshInstance.castShadow) {
                    if (this.shadowCasters.indexOf(meshInstance) === -1) {
                        this.shadowCasters.push(meshInstance);
                    }
                }
            }

            // Add all model lights to the scene
            var lights = model.getLights();
            for (i = 0, len = lights.length; i < len; i++) {
                this.addLight(lights[i]);
            }
        }
    };

    /**
     * @function
     * @name pc.scene.Scene#removeModel
     * @description Removes the specified model from the scene.
     * @author Will Eastcott
     */
    Scene.prototype.removeModel = function (model) {
        var i;

        // Verify the model is in the scene
        var index = this._models.indexOf(model);
        if (index !== -1) {
            this._models.splice(index, 1);

            var materials = model.getMaterials();
            for (i = 0; i < materials.length; i++) {
                materials[i].scene = null;
            }

            // Remove the model's mesh instances from render queues
            var meshInstance;
            var numMeshInstances = model.meshInstances.length;
            for (i = 0; i < numMeshInstances; i++) {
                meshInstance = model.meshInstances[i];
                index = this.drawCalls.indexOf(meshInstance);
                if (index !== -1) {
                    this.drawCalls.splice(index, 1);
                }
                if (meshInstance.castShadow) {
                    index = this.shadowCasters.indexOf(meshInstance);
                    if (index !== -1) {
                        this.shadowCasters.splice(index, 1);
                    }
                }
            }

            // Remove all model lights from the scene
            var lights = model.getLights();
            for (i = 0, len = lights.length; i < len; i++) {
                this.removeLight(lights[i]);
            }
        }
    };

    Scene.prototype.containsModel = function (model) {
        return this._models.indexOf(model) >= 0;
    };

    Scene.prototype.addLight = function (light) {
        var index = this._lights.indexOf(light);
        if (index !== -1) {
            console.warn("pc.scene.Scene#addLight: light is already in the scene");
        } else {
            this._lights.push(light);
            light._scene = this;
            this.updateShaders = true;
        }
    };

    Scene.prototype.removeLight = function (light) {
        var index = this._lights.indexOf(light);
        if (index === -1) {
            console.warn("pc.scene.Scene#removeLight: light is not in the scene");
        } else {
            this._lights.splice(index, 1);
            light._scene = null;
            this.updateShaders = true;
        }
    };

    /**
     * @function
     * @name pc.scene.Scene#update
     * @description Synchronizes the graph node hierarchy of every model in the scene.
     * @author Will Eastcott
     */
    Scene.prototype.update = function () {
        for (var i = 0, len = this._models.length; i < len; i++) {
            this._models[i].getGraph().syncHierarchy();
        }
    };

    return {
        Scene: Scene
    };
}());
<commit_msg>Scene-wide skybox<commit_after>/**
 * @name pc.scene
 * @namespace High level Graphics API
 */
pc.scene = {
    BLEND_SUBTRACTIVE: 0,
    BLEND_ADDITIVE: 1,
    BLEND_NORMAL: 2,
    BLEND_NONE: 3,
    BLEND_PREMULTIPLIED: 4,
    BLEND_MULTIPLICATIVE: 5,

    RENDERSTYLE_SOLID: 0,
    RENDERSTYLE_WIREFRAME: 1,
    RENDERSTYLE_POINTS: 2,

    LAYER_HUD: 0,
    LAYER_GIZMO: 1,
    LAYER_FX: 2,
    LAYER_WORLD: 3,

    /**
     * @enum pc.scene.FOG
     * @name pc.scene.FOG_NONE
     * @description No fog is applied to the scene.
     */
    FOG_NONE: 'none',
    /**
     * @enum pc.scene.FOG
     * @name pc.scene.FOG_LINEAR
     * @description Fog rises linearly from zero to 1 between a start and end depth.
     */
    FOG_LINEAR: 'linear',
    /**
     * @enum pc.scene.FOG
     * @name pc.scene.FOG_EXP
     * @description Fog rises according to an exponential curve controlled by a density value.
     */
    FOG_EXP: 'exp',
    /**
     * @enum pc.scene.FOG
     * @name pc.scene.FOG_EXP2
     * @description Fog rises according to an exponential curve controlled by a density value.
     */
    FOG_EXP2: 'exp2',

    TONEMAP_LINEAR: 0,
    TONEMAP_FILMIC: 1,

    SPECULAR_PHONG: 0,
    SPECULAR_BLINN: 1,

    FRESNEL_NONE: 0,
    FRESNEL_SIMPLE: 1,
    FRESNEL_SCHLICK: 2,
    FRESNEL_COMPLEX: 3
};

pc.extend(pc.scene, function () {

    /**
     * @name pc.scene.Scene
     * @class A scene is a container for models, lights and cameras. Scenes are rendered via a renderer.
     * PlayCanvas currently only supports a single renderer: the forward renderer (pc.scene.ForwardRenderer).
     * @constructor Creates a new scene.
     * @property {pc.Color} ambientLight The color of the scene's ambient light.
     * @property {String} fog The type of fog used by the scene (see pc.scene.FOG_).
     * @property {pc.Color} fogColor The color of the fog, in enabled.
     * @property {Number} fogDensity The density of the fog. This property is only valid if the fog property
     * is set to pc.scene.FOG_EXP or pc.scene.FOG_EXP2.
     * @property {Number} fogEnd The distance from the viewpoint where linear fog reaches its maximum. This
     * property is only valid if the fog property is set to pc.scene.FOG_LINEAR.
     * @property {Number} fogStart The distance from the viewpoint where linear fog begins. This property is
     * only valid if the fog property is set to pc.scene.FOG_LINEAR.
     * @property {Number} shadowDistance The distance from the viewpoint beyond which shadows are no longer
     * @property {Boolean} gammaCorrection If true then all materials will apply gamma correction
     * rendered.
     */
    var Scene = function Scene() {
        this.drawCalls = [];     // All mesh instances and commands
        this.shadowCasters = []; // All mesh instances that cast shadows

        this.fog = pc.scene.FOG_NONE;
        this.fogColor = new pc.Color(0, 0, 0);
        this.fogStart = 1;
        this.fogEnd = 1000;
        this.fogDensity = 0;

        this.ambientLight = new pc.Color(0, 0, 0);

        this.shadowDistance = 40;
        this._gammaCorrection = false;
        this._toneMapping = 0;
        this.exposure = 1.0;

        this._prefilteredCubeMapPreset = null;
        this._prefilteredCubeMap128 = null;
        this._prefilteredCubeMap64 = null;
        this._prefilteredCubeMap32 = null;
        this._prefilteredCubeMap16 = null;
        this._prefilteredCubeMap8 = null;
        this._prefilteredCubeMap4 = null;

        this._skyboxCubeMap = null;
        this._skyboxModel = null;

        // Models
        this._models = [];

        // Lights
        this._lights = [];
        this._globalLights = []; // All currently enabled directionals
        this._localLights = [[], []]; // All currently enabled points and spots

        this.updateShaders = true;
    };

    Object.defineProperty(Scene.prototype, 'fog', {
        get: function () {
            return this._fog;
        },
        set: function (type) {
            if (type !== this._fog) {
                this._fog = type;
                this.updateShaders = true;
            }
        }
    });

    Object.defineProperty(Scene.prototype, 'gammaCorrection', {
        get: function () {
            return this._gammaCorrection;
        },
        set: function (value) {
            if (value !== this._gammaCorrection) {
                this._gammaCorrection = value;
                pc.gfx.shaderChunks.defaultGamma = value ? pc.gfx.shaderChunks.gamma2_2PS : pc.gfx.shaderChunks.gamma1_0PS;
                this.updateShaders = true;
            }
        }
    });

    Object.defineProperty(Scene.prototype, 'toneMapping', {
        get: function () {
            return this._toneMapping;
        },
        set: function (value) {
            if (value !== this._toneMapping) {
                this._toneMapping = value;
                pc.gfx.shaderChunks.defaultTonemapping = value ? pc.gfx.shaderChunks.tonemappingFilmicPS : pc.gfx.shaderChunks.tonemappingLinearPS;
                this.updateShaders = true;
            }
        }
    });

    Object.defineProperty(Scene.prototype, 'prefilteredCubeMapPreset', {
        get: function () {
            return this._prefilteredCubeMapPreset;
        },
        set: function (value) {
            if (value !== this._prefilteredCubeMapPreset) {
                this._prefilteredCubeMapPreset = value;
                this._prefilteredCubeMap128 = null;
                this._prefilteredCubeMap64 = null;
                this._prefilteredCubeMap32 = null;
                this._prefilteredCubeMap16 = null;
                this._prefilteredCubeMap8 = null;
                this._prefilteredCubeMap4 = null;
                this.updateShaders = true;
            }
        }
    });

    Object.defineProperty(Scene.prototype, 'skybox', {
        get: function () {
            return this._skyboxCubeMap;
        },
        set: function (value) {
            if (value !== this._skyboxCubeMap) {
                this._skyboxCubeMap = value;
                if (this._skyboxModel) {
                    if (this.containsModel(this._skyboxModel)) {
                        this.removeModel(this._skyboxModel);
                    }
                }
                this._skyboxModel = null;
                this.updateShaders = true;
            }
        }
    });

    // Shaders have to be updated if:
    // - the fog mode changes
    // - lights are added or removed
    // - gamma correction changes
    Scene.prototype._updateShaders = function (device) {
        var i;

        if (this._prefilteredCubeMapPreset) {
            if (!this._prefilteredCubeMap128 || !this._prefilteredCubeMap64 || !this._prefilteredCubeMap32
                 || !this._prefilteredCubeMap16 || !this._prefilteredCubeMap8 || !this._prefilteredCubeMap4) {
                // Did I ever tell you the definition of hacks?
                var cubeName = this._prefilteredCubeMapPreset;
                var resources = [];
                var loaded = 0;
                var scene = this;
                for(var mip=0; mip<6; mip++) {
                    for(var face=0; face<6; face++) {
                        var loadId = mip * 6 + face;
                        resources[loadId] = new Image();
                        resources[loadId].crossOrigin = "anonymous"; // for local testing and just in case
                        resources[loadId].onload = function () {
                            loaded++;
                            if (loaded >= 36) {
                                var cubeMaps = [];
                                for(var mip2=0; mip2<6; mip2++) {
                                    sources = [];
                                    for (var face2=0; face2<6; face2++) {
                                        sources[face2] = resources[mip2 * 6 + face2];
                                    }
                                    cubeMaps[mip2] = new pc.gfx.Texture(device, {
                                        cubemap: true,
                                        hdr: true
                                    });
                                    cubeMaps[mip2].setSource(sources);
                                }
                                scene._prefilteredCubeMap128 = cubeMaps[0];
                                scene._prefilteredCubeMap64 = cubeMaps[1];
                                scene._prefilteredCubeMap32 = cubeMaps[2];
                                scene._prefilteredCubeMap16 = cubeMaps[3];
                                scene._prefilteredCubeMap8 = cubeMaps[4];
                                scene._prefilteredCubeMap4 = cubeMaps[5];
                                scene.skybox = scene._prefilteredCubeMap128;
                                scene.updateShaders = true;
                            }
                        };
                        resources[loadId].src = "http://static.playcanvas.com/cubemaps/hdr/"+cubeName+"/"+cubeName+"_m0"+mip+"_c0"+face+".png";
                     }
                }
            }
        } else {
            this._prefilteredCubeMap128 = null;
            this._prefilteredCubeMap64 = null;
            this._prefilteredCubeMap32 = null;
            this._prefilteredCubeMap16 = null;
            this._prefilteredCubeMap8 = null;
            this._prefilteredCubeMap4 = null;
        }

        if (this._skyboxCubeMap && !this._skyboxModel) {
            var material = new pc.scene.Material();
            var scene = this;
            material.updateShader = function() {
                var library = device.getProgramLibrary();
                var shader = library.getProgram('skybox', {hdr:scene._skyboxCubeMap.hdr, prefiltered:scene._skyboxCubeMap.hdr, gamma:scene.gammaCorrection, toneMapping:scene.toneMapping});
                this.setShader(shader);
            };

            material.updateShader();
            material.setParameter("texture_cubeMap", this._skyboxCubeMap);
            material.cull = pc.gfx.CULLFACE_NONE;

            var node = new pc.scene.GraphNode();
            var mesh = pc.scene.procedural.createBox(device);
            var meshInstance = new pc.scene.MeshInstance(node, mesh, material);

            var model = new pc.scene.Model();
            model.graph = node;
            model.meshInstances = [ meshInstance ];
            this._skyboxModel = model;

            this.addModel(model);
        }

        var materials = [];
        var drawCalls = this.drawCalls;
        for (i = 0; i < drawCalls.length; i++) {
            var drawCall = drawCalls[i];
            if (drawCall.material !== undefined) {
                if (materials.indexOf(drawCall.material) === -1) {
                    materials.push(drawCall.material);
                }
            }
        }
        for (i = 0; i < materials.length; i++) {
            materials[i].updateShader(device, this);
        }
    };

    Scene.prototype.getModels = function () {
        return this._models;
    };

    /**
     * @function
     * @name pc.scene.Scene#addModel
     * @description Adds the specified model to the scene.
     * @author Will Eastcott
     */
    Scene.prototype.addModel = function (model) {
        var i;

        // Check the model is not already in the scene
        var index = this._models.indexOf(model);
        if (index === -1) {
            this._models.push(model);

            var materials = model.getMaterials();
            for (i = 0; i < materials.length; i++) {
                materials[i].scene = this;
            }

            // Insert the model's mesh instances into lists ready for rendering
            var meshInstance;
            var numMeshInstances = model.meshInstances.length;
            for (i = 0; i < numMeshInstances; i++) {
                meshInstance = model.meshInstances[i];
                if (this.drawCalls.indexOf(meshInstance) === -1) {
                    this.drawCalls.push(meshInstance);
                }
                if (meshInstance.castShadow) {
                    if (this.shadowCasters.indexOf(meshInstance) === -1) {
                        this.shadowCasters.push(meshInstance);
                    }
                }
            }

            // Add all model lights to the scene
            var lights = model.getLights();
            for (i = 0, len = lights.length; i < len; i++) {
                this.addLight(lights[i]);
            }
        }
    };

    /**
     * @function
     * @name pc.scene.Scene#removeModel
     * @description Removes the specified model from the scene.
     * @author Will Eastcott
     */
    Scene.prototype.removeModel = function (model) {
        var i;

        // Verify the model is in the scene
        var index = this._models.indexOf(model);
        if (index !== -1) {
            this._models.splice(index, 1);

            var materials = model.getMaterials();
            for (i = 0; i < materials.length; i++) {
                materials[i].scene = null;
            }

            // Remove the model's mesh instances from render queues
            var meshInstance;
            var numMeshInstances = model.meshInstances.length;
            for (i = 0; i < numMeshInstances; i++) {
                meshInstance = model.meshInstances[i];
                index = this.drawCalls.indexOf(meshInstance);
                if (index !== -1) {
                    this.drawCalls.splice(index, 1);
                }
                if (meshInstance.castShadow) {
                    index = this.shadowCasters.indexOf(meshInstance);
                    if (index !== -1) {
                        this.shadowCasters.splice(index, 1);
                    }
                }
            }

            // Remove all model lights from the scene
            var lights = model.getLights();
            for (i = 0, len = lights.length; i < len; i++) {
                this.removeLight(lights[i]);
            }
        }
    };

    Scene.prototype.containsModel = function (model) {
        return this._models.indexOf(model) >= 0;
    };

    Scene.prototype.addLight = function (light) {
        var index = this._lights.indexOf(light);
        if (index !== -1) {
            console.warn("pc.scene.Scene#addLight: light is already in the scene");
        } else {
            this._lights.push(light);
            light._scene = this;
            this.updateShaders = true;
        }
    };

    Scene.prototype.removeLight = function (light) {
        var index = this._lights.indexOf(light);
        if (index === -1) {
            console.warn("pc.scene.Scene#removeLight: light is not in the scene");
        } else {
            this._lights.splice(index, 1);
            light._scene = null;
            this.updateShaders = true;
        }
    };

    /**
     * @function
     * @name pc.scene.Scene#update
     * @description Synchronizes the graph node hierarchy of every model in the scene.
     * @author Will Eastcott
     */
    Scene.prototype.update = function () {
        for (var i = 0, len = this._models.length; i < len; i++) {
            this._models[i].getGraph().syncHierarchy();
        }
    };

    return {
        Scene: Scene
    };
}());
<|endoftext|>


<commit_before>// ==UserScript==
// @name        SubScene Filter
// @namespace   www.subscene.com
// @description Add filter to subscene searches
// @include     https://*subscene.com/subtitles/*
// @exclude     https://*subscene.com/subtitles/title?q*
// @exclude     https://*subscene.com/subtitles/*/*
// @require  http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// @version     1
// @grant       none
// ==/UserScript==

$("#flagWrapper").after(
  '<div>\
    <select id="langChoice">\
      <option id="langDefault" value="">All</option>\
    </select>\
    <input id="myFilterQuery" type="text">\
    <label>\
      <input type="checkbox" id="caseInsensitiveBox">\
      Case Insensitive\
    </label>\
    <select id="earChoice">\
      <option id="earDefault" value="">Any</option>\
      <option value="hi">HI</option>\
      <option value="nohi">No HI</option>\
    </select>\
    <select id="authorChoice">\
      <option id="authorDefault" value="">Any</option>\
    </select>\
    <button id="filterButton" type="button">Filter</button>\
    <button id="clearButton" type="button">Clear</button>\
  </div>'
);
var rows = $("tr").filter(function(ix,el) {
  return $(this).find("span.l").text();
});
var filtered = rows;
var visibles = rows;

var langs = [];
$("tr td.a1 span.l").each(function() {
  lang = $(this).text().trim();
  if( langs.indexOf(lang) == -1 ) {
    langs.push(lang);
  }
});
var el = $("#langChoice");
$.each(langs, function(key,value) {
  el.append($("<option></option>")
      .attr("value",value).text(value));
});

var authors = [];
/* TODO:
 *  - populate authors
 *  - update author selection "#authorChoice"
 */

var authorsPopulate = function() {
  authors = [];
  filtered.find("td.a5").each(function() {
    author = $(this).text().trim();
    if( authors.indexOf(author) == -1 ) {
      authors.push(author);
    }
  });
};

var updateAuthorChoice = function() {
  $("#authorChoice option:gt(0)").remove();
  var el = $("#authorChoice");
  $.each(authors,function(key, value) {
    el.append($("<option></option>")
      .attr("value",value).text(value));
  });
}

var render = function() {
  rows.hide();
  filtered.show();
};

$("#filterButton").click(function() {
  // Get the regex to search for
  var isValid = true;
  try {
    if($("#caseInsensitiveBox").prop('checked')) {
      var inputRegex = new RegExp($("#myFilterQuery").val(),"i");
    } else {
      var inputRegex = new RegExp($("#myFilterQuery").val());
    }
  } catch(e) {
    isValid = false;
  }

  // Get the language filter params
  do_filter = $("#langChoice").val() != "";
  var filter_lang = $("#langChoice").val();

  // Get the hearing impairment filter params
  do_hi = $("#earChoice").val() != "";
  var filter_hi = $("#earChoice").val();
  if(filter_hi == "hi") {
    var hi_class = "a41";
  } else if (filter_hi == "nohi") {
    var hi_class = "a40";
  }

  filtered = rows.filter(function(ix,el) {
      if(!do_filter) {
        return true;
      }
      return $(this).find("span.l").text().trim() == filter_lang;
    })
    .filter(function(ix,el) {
      if(!isValid) {
        return true;
      }
      return $(this).find("td.a1 a span:nth-child(2)").text().trim().match(inputRegex);
    })
    .filter(function(ix,el) {
      if(!do_hi) {
        return true;
      }
      return $(this).find("td:nth-child(3)").attr('class') == hi_class;
    });

  render();
});
$("#clearButton").click(function() {
  filtered = visibles = rows;
  render();

  // restore the filters to the empy state
  $("#langChoice").val($("#langDefault").val());
  $("#earChoice").val($("#earDefault").val());
  $("#caseInsensitiveBox").prop('checked',false);
  $("#myFilterQuery").val("");
});
<commit_msg>Choose author<commit_after>// ==UserScript==
// @name        SubScene Filter
// @namespace   www.subscene.com
// @description Add filter to subscene searches
// @include     https://*subscene.com/subtitles/*
// @exclude     https://*subscene.com/subtitles/title?q*
// @exclude     https://*subscene.com/subtitles/*/*
// @require  http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// @version     1
// @grant       none
// ==/UserScript==

$("#flagWrapper").after(
  '<div>\
    <select id="langChoice">\
      <option id="langDefault" value="">All</option>\
    </select>\
    <input id="myFilterQuery" type="text">\
    <label>\
      <input type="checkbox" id="caseInsensitiveBox">\
      Case Insensitive\
    </label>\
    <select id="earChoice">\
      <option id="earDefault" value="">Any</option>\
      <option value="hi">HI</option>\
      <option value="nohi">No HI</option>\
    </select>\
    <select id="authorChoice">\
      <option id="authorDefault" value="">Any</option>\
    </select>\
    <button id="filterButton" type="button">Filter</button>\
    <button id="clearButton" type="button">Clear</button>\
  </div>'
);
var rows = $("tr").filter(function(ix,el) {
  return $(this).find("span.l").text();
});
var filtered = rows;
var visibles = rows;

var langs = [];
$("tr td.a1 span.l").each(function() {
  lang = $(this).text().trim();
  if( langs.indexOf(lang) == -1 ) {
    langs.push(lang);
  }
});
var el = $("#langChoice");
$.each(langs, function(key,value) {
  el.append($("<option></option>")
      .attr("value",value).text(value));
});

// Get authors list and set selection
var authors = [];
var authorsPopulate = function() {
  authors = [];
  filtered.find("td.a5").each(function() {
    author = $(this).text().trim();
    if( authors.indexOf(author) == -1 ) {
      authors.push(author);
    }
  });
};
var updateAuthorChoice = function() {
  authorVal = $("#authorChoice").val();
  $("#authorChoice option:gt(0)").remove();
  var el = $("#authorChoice");
  $.each(authors,function(key, value) {
    el.append($("<option></option>")
      .attr("value",value).text(value));
  });
  $("#authorChoice").val(authorVal);
};
authorsPopulate();
updateAuthorChoice();

var render = function() {
  rows.hide();

  author_filter = $("#authorChoice").val();
  if(author_filter == $("#authorDefault").val()){
    visibles = filtered;
  } else {
    visibles = filtered.filter(function(ix,el) {
      return $(this).find("td.a5").text().trim() == author_filter;
    });
  }
  visibles.show();

  authorsPopulate();
  updateAuthorChoice();
};

$("#filterButton").click(function() {
  // Get the regex to search for
  var isValid = true;
  try {
    if($("#caseInsensitiveBox").prop('checked')) {
      var inputRegex = new RegExp($("#myFilterQuery").val(),"i");
    } else {
      var inputRegex = new RegExp($("#myFilterQuery").val());
    }
  } catch(e) {
    isValid = false;
  }

  // Get the language filter params
  do_filter = $("#langChoice").val() != "";
  var filter_lang = $("#langChoice").val();

  // Get the hearing impairment filter params
  do_hi = $("#earChoice").val() != "";
  var filter_hi = $("#earChoice").val();
  if(filter_hi == "hi") {
    var hi_class = "a41";
  } else if (filter_hi == "nohi") {
    var hi_class = "a40";
  }

  filtered = rows.filter(function(ix,el) {
      if(!do_filter) {
        return true;
      }
      return $(this).find("span.l").text().trim() == filter_lang;
    })
    .filter(function(ix,el) {
      if(!isValid) {
        return true;
      }
      return $(this).find("td.a1 a span:nth-child(2)").text().trim().match(inputRegex);
    })
    .filter(function(ix,el) {
      if(!do_hi) {
        return true;
      }
      return $(this).find("td:nth-child(3)").attr('class') == hi_class;
    });

  render();
});
$("#clearButton").click(function() {
  filtered = visibles = rows;

  // restore the filters to the empy state
  $("#langChoice").val($("#langDefault").val());
  $("#earChoice").val($("#earDefault").val());
  $("#authorChoice").val($("#authorDefault").val())
  $("#caseInsensitiveBox").prop('checked',false);
  $("#myFilterQuery").val("");

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


<commit_before>/**
 * Created by irmo on 16/10/11.
 */

'use strict'

import React, {Component, PropTypes} from 'react';
import {
    StyleSheet,
    Text,
    View,
    TouchableHighlight,
} from 'react-native';

export default class TodayScene extends Component {
    constructor() {
        super();
    }

    static propTypes = {
        title: PropTypes.string.isRequired,
        onBack: PropTypes.func.isRequired,
    }

    render() {
        return (
            <View style={styles.container}>
                <TouchableHighlight onPress={this.props.onBack}>
                    <Text style={styles.backButtonText}>Back</Text>
                </TouchableHighlight>
                <Text style={styles.commonText}> Today Scene </Text>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        padding: 10,
        flex: 1,
        backgroundColor: '#000000',
    },
    backButtonText: {
        color: "#FFFFFF",
        fontSize: 50,
    },
    commonText: {
        color: "#AFAFAF",
    }
})
<commit_msg>Add geolocation<commit_after>/**
 * Created by irmo on 16/10/11.
 */

'use strict'

import React, {Component, PropTypes} from 'react';
import {
    StyleSheet,
    Image,
    Text,
    TextInput,
    View,
    TouchableHighlight,
} from 'react-native';

var GeolocationExample = React.createClass({
    // watchID: (null: ?number),

    getInitialState: function () {
        return {
            initialPosition: 'unknown',
            lastPosition: 'unknown',
        };
    },

    componentDidMount: function () {
        navigator.geolocation.getCurrentPosition(
            (initialPosition) => this.setState({initialPosition}),
            (error) => alert(error.message),
            {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
        );
        this.watchID = navigator.geolocation.watchPosition((lastPosition) => {
            this.setState({lastPosition});
        });
    },

    componentWillUnmount: function () {
        navigator.geolocation.clearWatch(this.watchID);
    },

    render: function () {
        return (
            <View>
                <Text></Text>
                <Text style={styles.commonText}>
                    <Text>Initial position: </Text>
                    {JSON.stringify(this.state.initialPosition)}
                </Text>
                <Text>

                </Text>
                <Text style={styles.commonText}>
                    <Text>Current position: </Text>
                    {JSON.stringify(this.state.lastPosition)}
                </Text>
            </View>
        );
    }
});

export default class TodayScene extends Component {
    constructor() {
        super();
        this.state = {
            text: 'Default Text',
            location: 'unknown',
        }
    }

    static propTypes = {
        title: PropTypes.string.isRequired,
        onBack: PropTypes.func.isRequired,
    }

    render() {
        return (
            <View style={styles.container}>
                <TouchableHighlight onPress={this.props.onBack}>
                    <Text style={styles.backButtonText}>
                        Back
                    </Text>
                </TouchableHighlight>
                <TextInput
                    style={styles.input}
                    onChangeText={(text) => this.setState({text})}
                    value={this.state.text}
                />
                <GeolocationExample />
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        padding: 10,
        flex: 1,
        backgroundColor: 'black',
    },
    backButtonText: {
        color: "#FFFFFF",
        fontSize: 50,
    },
    commonText: {
        padding: 5,
        paddingBottom: 3,
        color: "#AFAFAF",
    },
    input: {
        height: 100,
        borderColor: 'white',
        borderWidth: 1,
        color: '#AFAFAF',
        fontSize: 15,
        alignItems: 'flex-start',
    }
})
<|endoftext|>