<commit_before>/**
 * Script designed to help with tasts in UserVoice Helpdesk software
 */
//(function() {

// Globals
    var alt = false;
    var UVrootURL = window.location.host + "/admin";

    // end function for catching end of keystroke
    function keyup(e) {
        if (e.keyCode == 18) {
            alt = false;
        }
    }

    // function for catching key stokes
    function keydown(e) {
        var key = e.keyCode;
        if (e.keyCode == 18) {
            alt = true;
        }
        if (alt) {
            switch (key) {
                case 65: // A
                    // hide all
                    $('.ticket-reply-content').hide();
                    // make sure the reply to sticks around
                    $($('.ticket-reply-content')[0]).show();
                    break;
                case 90: //Z
                    // show all
                    $('.ticket-reply-content').show();
                    break;
                case 88: // X
                    // update();
                    break;
                case 89: // Y
                    toggleFlag();
                    break;
                case 67: // C
                    // updateAndClose();
                    break;
                case 86: // V
                    // function here that adds close message
                    getResponse(closed);
                    // updateAndClose();
                    break;
                case 84: // T
                    focusOnTicket();
                    addTargetWrapper();
                    break;
                case 83: // S
                    var elem = document.getElementById(subjectField);
                    var sub = prompt('Subject Text: ', elem.value);
                    elem.value = sub;
                    break;
                case 78: // N
                    focusOnNote();
                    break;
                case 77: // M  - change name of user
                    focusOnMessage();
                    break;
                case 81: // Q
                    // snap to personal tickets
                    window.location = UVrootURL + '/tickets/?q=assignee%3Ame+status%3Aopen';
                    break;
                case 73: // I
                    // snap to inbox
                    window.location = UVrootURL + '/tickets/?q=assignee%3A"none"+status%3Aopen';
                    break;
                case 82: // R
                    // snapps user to the most recent update
                    location = "#request_history_box_wrap_box_body";
                    break;
            }
        }
    }

    function toggleFlag() {
        // not yet implemented
    }

    function update() {
        $('.ticket-submit-open').click();
    }

    function focusOnTicket() {
        $('.ticket-content').click();
        highlightSubject();
    }

    function focusOnMessage() {
        $('.ticket-reply-tab-message > a').click();
    }

    function focusOnNote() {
        $('.ticket-reply-tab-note > a').click();
    }

    function highlightSubject() {
        $('.ticket-item-subject').css('background-color','yellow');
    }

    function addTargetWrapper() {
        // wrap anchor around all search results so they can be targeted by Vimium
        try {
            // removed due to Scope:   onclick="javascript:focusOnTicket();"
            $('.ticket-item-title').wrap('');
        } catch (err) {
            console.log(err);
        }
    }

    // enable click on email name to show or hide response details
    function enableMessageFolding() {
        var pics = $('.ticket-reply-avatar')
        // check to see if the event is already on the elements.
        if( pics.length && !$(pics[0]).data('events')){
            pics.click(function(i,e){
                $(this).parent().parent().find('.ticket-reply-content').toggle();
            });
        };
    };

    // =====================================================================

    // Event listenets to get everything working...
    document.body.addEventListener('keydown', keydown);
    document.body.addEventListener('keyup', keyup);
    window.addEventListener("hashchange", addTargetWrapper, false);
    window.addEventListener("hashchange", focusOnTicket, false);

    addTargetWrapper();

    window.onload = function() {
        focusOnTicket();

        $('.ticket-item-title').focus(addTargetWrapper);

        highlightSubject();

        enableMessageFolding();

         /*
         * Because messages are loaded over ajax we have to keep checking
         * back to make sure all messages are updated with the listeners
         * the enableMessageFolding should only set listener once of the
         * icons
         */
        setInterval(enableMessageFolding,2500);
    };
//})();
<commit_msg>Updates to fix endpoints for jump to queue<commit_after>/**
 * Script designed to help with tasts in UserVoice Helpdesk software
 */
//(function() {

// Globals
    var alt = false;
    var UVrootURL = window.location.host + "/admin";

    // end function for catching end of keystroke
    function keyup(e) {
        if (e.keyCode == 18) {
            alt = false;
        }
    }

    // function for catching key stokes
    function keydown(e) {
        var key = e.keyCode;
        if (e.keyCode == 18) {
            alt = true;
        }
        if (alt) {
            switch (key) {
                case 65: // A
                    // hide all
                    $('.ticket-reply-content').hide();
                    // make sure the reply to sticks around
                    $($('.ticket-reply-content')[0]).show();
                    break;
                case 90: //Z
                    // show all
                    $('.ticket-reply-content').show();
                    break;
                case 88: // X
                    // update();
                    break;
                case 89: // Y
                    toggleFlag();
                    break;
                case 67: // C
                    // updateAndClose();
                    break;
                case 86: // V
                    // function here that adds close message
                    getResponse(closed);
                    // updateAndClose();
                    break;
                case 84: // T
                    focusOnTicket();
                    addTargetWrapper();
                    break;
                case 83: // S
                    var elem = document.getElementById(subjectField);
                    var sub = prompt('Subject Text: ', elem.value);
                    elem.value = sub;
                    break;
                case 78: // N
                    focusOnNote();
                    break;
                case 77: // M  - change name of user
                    focusOnMessage();
                    break;
                case 81: // Q
                    // snap to personal tickets
                    window.location.href = '//' + UVrootURL + '/tickets/?q=assignee%3Ame+status%3Aopen';
                    break;
                case 73: // I
                    // snap to inbox
                    window.location = '//' +  UVrootURL + '/tickets/?q=assignee%3A"none"+status%3Aopen';
                    break;
                case 82: // R
                    // snapps user to the most recent update
                    location = "#request_history_box_wrap_box_body";
                    break;
            }
        }
    }

    function toggleFlag() {
        // not yet implemented
    }

    function update() {
        $('.ticket-submit-open').click();
    }

    function focusOnTicket() {
        $('.ticket-content').click();
        highlightSubject();
    }

    function focusOnMessage() {
        $('.ticket-reply-tab-message > a').click();
    }

    function focusOnNote() {
        $('.ticket-reply-tab-note > a').click();
    }

    function highlightSubject() {
        $('.ticket-item-subject').css('background-color','yellow');
    }

    function addTargetWrapper() {
        // wrap anchor around all search results so they can be targeted by Vimium
        try {
            // removed due to Scope:   onclick="javascript:focusOnTicket();"
            $('.ticket-item-title').wrap('');
        } catch (err) {
            console.log(err);
        }
    }

    // enable click on email name to show or hide response details
    function enableMessageFolding() {
        var pics = $('.ticket-reply-avatar')
        // check to see if the event is already on the elements.
        if( pics.length && !$(pics[0]).data('events')){
            pics.click(function(i,e){
                $(this).parent().parent().find('.ticket-reply-content').toggle();
            });
        };
    };

    // =====================================================================

    // Event listenets to get everything working...
    document.body.addEventListener('keydown', keydown);
    document.body.addEventListener('keyup', keyup);
    window.addEventListener("hashchange", addTargetWrapper, false);
    window.addEventListener("hashchange", focusOnTicket, false);

    addTargetWrapper();

    window.onload = function() {
        focusOnTicket();

        $('.ticket-item-title').focus(addTargetWrapper);

        highlightSubject();

        enableMessageFolding();

         /*
         * Because messages are loaded over ajax we have to keep checking
         * back to make sure all messages are updated with the listeners
         * the enableMessageFolding should only set listener once of the
         * icons
         */
        setInterval(enableMessageFolding,2500);
    };
//})();
<|endoftext|>


<commit_before>function showGailForm() {
    $("#calcularGailButton").hide();
    $("#gailForm").show();
}

function searchPerson() {
    var id = $("#searchPersonInput").val();
    if (id > 0) {
        window.location = "pedigree.html?id=" + id;
    }
}

function calculatePREMM126() {

    $("#calc_results").empty();
    $("#statsWidgets").hide();
    toggleLoading(true);

    $.getJSON("/api/model_calculator/premm126?patient_id=" + currentPatient.id, function (data) {

        console.log(data);
        var result = $("#calc_results");
        if (data.status == "ERROR") {
            $("#statsWidgets").hide();
            result.append("ERROR: " + data.message);
        }
        else {
            $("#statsWidgets").show();
            $('#text_chart_group1').hide();
            $('#chart_group2').hide();
            $('#chart_group3').hide();
            $('#chart_group4').hide();
            $('#chart1').data('easyPieChart').update((data.results * 100));
            $('#perc1').text((data.results * 100).toFixed(2) + "%");
        }

        toggleLoading(false);
    });
}
function calculateGail() {

    $("#calc_results").empty();
    var menarcheAge = $("#gailMenarcheAge").val();
    var numberBiopsy = $("#gailBiopsies").val();
    $("#statsWidgets").hide();
    toggleLoading(true);
    $.getJSON("api/pedigree/query?type=table&model=gail&id=" + currentPatient.id + "&menarcheAge=" + menarcheAge + "&numberBiopsy=" + numberBiopsy, function (data) {

        console.log(data);

        var result = $("#calc_results");
        if (data.status == "ERROR") {
            $("#statsWidgets").hide();
            result.append("ERROR: " + data.message);
        }
        else {
            $("#statsWidgets").show();
            $('#text_chart_group1').show();
            $('#chart_group2').show();
            $('#chart_group3').show();
            $('#chart_group4').show();
            //result.append("Riesgo absoluto de este paciente en 5 años: " + (data.absoluteRiskIn5Years * 100).toFixed(2) + "%");
            $('#chart1').data('easyPieChart').update((data.absoluteRiskIn5Years * 100));
            $('#perc1').text((data.absoluteRiskIn5Years * 100).toFixed(2) + "%");
            //result.append("
Riesgo promedio de una persona en 5 años: " + (data.averageRiskIn5Years * 100).toFixed(2) + "%");
            $('#chart2').data('easyPieChart').update((data.averageRiskIn5Years * 100));
            $('#perc2').text((data.averageRiskIn5Years * 100).toFixed(2) + "%");
            //result.append("
Riesgo absoluto de este paciente hasta los 90 años: " + (data.absoluteRiskAt90yo * 100).toFixed(2) + "%");
            $('#chart3').data('easyPieChart').update((data.absoluteRiskAt90yo * 100));
            $('#perc3').text((data.absoluteRiskAt90yo * 100).toFixed(2) + "%");
            //result.append("
Riesgo promedio de una persona hasta los 90 años: " + (data.averageRiskAt90yo * 100).toFixed(2) + "%");
            $('#chart4').data('easyPieChart').update((data.averageRiskAt90yo * 100));
            $('#perc4').text((data.averageRiskAt90yo * 100).toFixed(2) + "%");
        }

        toggleLoading(false);
    });

}

$.urlParam = function (name) {
    var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
    if (results == null) {
        return null;
    }
    else {
        return results[1] || 0;
    }
};
init();
var currentPatient;
var family;
toggleLoading(true);
$("#current_patient").hide();
function getPeopleNodesFromFamily(family) {
    var nodos = {};
    var people = [];

    $.each(family.patients, function (key, val) {
        nodos[val.neo_id] = val;
        val.attributes_go = [];
        for (var i = 0; i < val.patient_diseases.length; i++) {
            var enf = val.patient_diseases[i].name;

            switch (enf) {
                case "Cancer de Ovario":
                    val.attributes_go.push("B");
                    break;
                case "Cancer de Mama":
                    val.attributes_go.push("H");
                    break;
                default:
                    val.attributes_go.push("E");
                    break;
            }
        }
    });

    $.each(family.relations, function (key, val) {
        if (val.name == "MADRE") {
            nodos[val.from].mother = val.to;
            if (nodos[val.from].father != undefined) {
                nodos[nodos[val.from].mother].husband = nodos[val.from].father;
                nodos[nodos[val.from].father].wife = nodos[val.from].mother;
            }
        } else if (val.name == "PADRE") {
            nodos[val.from].father = val.to;
            if (nodos[val.from].mother != undefined) {
                nodos[nodos[val.from].father].wife = nodos[val.from].mother;
                nodos[nodos[val.from].mother].husband = nodos[val.from].father;
            }
        }
    });

    $.each(nodos, function (key, val) {
        var p = {};
        //si es mayor de 90, tachar con una raya roja
        if (val.status == 'dead') {
            val.attributes_go.push("S");
            p.n = val.name + " " + val.lastname;
        }
        else {
            p.n = val.name + " " + val.lastname + ", edad: " + val.age;
        }

        p.key = val.neo_id;

        p.s = val.gender.toUpperCase();
        if (val.mother != undefined) p.m = val.mother;
        if (val.father != undefined) p.f = val.father;
        if (val.wife != undefined) p.ux = val.wife;
        if (val.husband != undefined) p.vir = val.husband;
        if (val.attributes_go != undefined) p.a = val.attributes_go;
        people.push(p);
    });

    console.log(people);
    return people;
}
$.getJSON("api/pedigrees/" + $.urlParam('id'), function (data) {

    family = data.pedigree;
    $("#pedigreeId").val(family.id);
    console.log(data);
    currentPatient = (data.pedigree.current);

    var people = getPeopleNodesFromFamily(family);
    setupDiagram(myDiagram, people, currentPatient.neo_id);

    myDiagram.addDiagramListener("ObjectSingleClicked",
        function (e) {
            var part = e.subject.part;
            var patient = get_patient_object(family.patients, part.data.key);
            if (!(part instanceof go.Link)) set_current_patient(patient);
        });

    toggleLoading(false);
    set_current_patient(currentPatient);
});

function reloadDiagram() {
    var people = getPeopleNodesFromFamily(family);
    setupDiagram(myDiagram, people, currentPatient.neo_id);
}

function addChild(newChild) {
    family.patients.push(newChild);
    var newRelation = {
        "from": newChild.neo_id,
        "to": currentPatient.neo_id,
        "name": currentPatient.gender == "M" ? "PADRE" : "MADRE"
    };

    family.relations.push(newRelation);
    console.log(family);
    reloadDiagram();
}

function addMother(madre) {
    family.patients.push(madre);
    var newRelation = {
        "from": currentPatient.neo_id,
        "to": madre.neo_id,
        "name": "MADRE"
    };

    family.relations.push(newRelation);
    console.log(family);
    reloadDiagram();
}

function addFather(padre) {
    family.patients.push(padre);
    var newRelation = {
        "from": currentPatient.neo_id,
        "to": padre.neo_id,
        "name": "PADRE"
    };

    family.relations.push(newRelation);
    console.log(family);
    reloadDiagram();
}

function showCreateModal(type) {
    $("#patientForm")[0].reset();
    $("#typeRelationForm").val(type);
    switch (type) {
        case "CHILD":
            break;
        case "MOTHER":
            break;
        case "FATHER":
            break;
    }
    $("#modal-create-family-member").modal("show")
}

function createRelative() {
    console.log($("#patientForm").serialize());
    $.post("/api/patients", $("#patientForm").serialize())
        .done(function (data) {
            console.log(data);
            switch ($("#typeRelationForm").val()) {
                case "CHILD":
                    addChild(data.patient);
                    break;
                case "MOTHER":
                    addMother(data.patient);
                    break;
                case "FATHER":
                    addFather(data.patient);
                    break;
            }
            $.ajax({
                url: "/api/pedigrees/" + family.id,
                type: 'PUT',
                contentType: "application/json; charset=utf-8",
                data: JSON.stringify({"relations": family.relations}),
                dataType: "json"})
                .done(function (data) {
                    console.log("Pedigree Updated");
                    console.log(data);
                });
            $("#modal-create-family-member").modal("hide");
        });
}

function set_current_patient(patient) {
    currentPatient = patient;
    $("#current_patient").text(patient.name + " " + patient.lastname + " edad: " + patient.age + " sexo: " + patient.gender + " id: " + patient.id);
    $("#current_patient").show();
}

function get_patient_object(people, id) {
    var patient;
    $.each(people, function (key, val) {
        console.log("patient", val);
        if (val.neo_id == id) patient = val;
    });

    return patient;
}<commit_msg>Gail fixed front<commit_after>function showGailForm() {
    $("#calcularGailButton").hide();
    $("#gailForm").show();
}

function searchPerson() {
    var id = $("#searchPersonInput").val();
    if (id > 0) {
        window.location = "pedigree.html?id=" + id;
    }
}

function calculatePREMM126() {

    $("#calc_results").empty();
    $("#statsWidgets").hide();
    toggleLoading(true);

    $.getJSON("/api/model_calculator/premm126?patient_id=" + currentPatient.neo_id, function (data) {

        console.log(data);
        var result = $("#calc_results");
        if (data.status == "ERROR") {
            $("#statsWidgets").hide();
            result.append("ERROR: " + data.message);
        }
        else {
            $("#statsWidgets").show();
            $('#text_chart_group1').hide();
            $('#chart_group2').hide();
            $('#chart_group3').hide();
            $('#chart_group4').hide();
            $('#chart1').data('easyPieChart').update((data.results * 100));
            $('#perc1').text((data.results * 100).toFixed(2) + "%");
        }

        toggleLoading(false);
    });
}
function calculateGail() {

    $("#calc_results").empty();
    var menarcheAge = $("#gailMenarcheAge").val();
    var numberBiopsy = $("#gailBiopsies").val();
    $("#statsWidgets").hide();
    toggleLoading(true);
    $.getJSON("api/model_calculator/gail?patient_id=" + currentPatient.id + "&menarcheAge=" + menarcheAge + "&numberBiopsy=" + numberBiopsy, function (data) {

        console.log(data);

        var result = $("#calc_results");
        if (data.status == "ERROR") {
            $("#statsWidgets").hide();
            result.append("ERROR: " + data.message);
        }
        else {
            var calc =  data.model_calculator.calculations;
            $("#statsWidgets").show();
            $('#text_chart_group1').show();
            $('#chart_group2').show();
            $('#chart_group3').show();
            $('#chart_group4').show();
            //result.append("Riesgo absoluto de este paciente en 5 años: " + (data.absoluteRiskIn5Years * 100).toFixed(2) + "%");
            $('#chart1').data('easyPieChart').update((calc.absoluteRiskIn5Years * 100));
            $('#perc1').text((calc.absoluteRiskIn5Years * 100).toFixed(2) + "%");
            //result.append("
Riesgo promedio de una persona en 5 años: " + (calc.averageRiskIn5Years * 100).toFixed(2) + "%");
            $('#chart2').data('easyPieChart').update((calc.averageRiskIn5Years * 100));
            $('#perc2').text((calc.averageRiskIn5Years * 100).toFixed(2) + "%");
            //result.append("
Riesgo absoluto de este paciente hasta los 90 años: " + (calc.absoluteRiskAt90yo * 100).toFixed(2) + "%");
            $('#chart3').data('easyPieChart').update((calc.absoluteRiskAt90yo * 100));
            $('#perc3').text((calc.absoluteRiskAt90yo * 100).toFixed(2) + "%");
            //result.append("
Riesgo promedio de una persona hasta los 90 años: " + (calc.averageRiskAt90yo * 100).toFixed(2) + "%");
            $('#chart4').data('easyPieChart').update((calc.averageRiskAt90yo * 100));
            $('#perc4').text((calc.averageRiskAt90yo * 100).toFixed(2) + "%");
        }

        toggleLoading(false);
    });

}

$.urlParam = function (name) {
    var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
    if (results == null) {
        return null;
    }
    else {
        return results[1] || 0;
    }
};
init();
var currentPatient;
var family;
toggleLoading(true);
$("#current_patient").hide();
function getPeopleNodesFromFamily(family) {
    var nodos = {};
    var people = [];

    $.each(family.patients, function (key, val) {
        nodos[val.neo_id] = val;
        val.attributes_go = [];
        for (var i = 0; i < val.patient_diseases.length; i++) {
            var enf = val.patient_diseases[i].name;

            switch (enf) {
                case "Cancer de Ovario":
                    val.attributes_go.push("B");
                    break;
                case "Cancer de Mama":
                    val.attributes_go.push("H");
                    break;
                default:
                    val.attributes_go.push("E");
                    break;
            }
        }
    });

    $.each(family.relations, function (key, val) {
        if (val.name == "MADRE") {
            nodos[val.from].mother = val.to;
            if (nodos[val.from].father != undefined) {
                nodos[nodos[val.from].mother].husband = nodos[val.from].father;
                nodos[nodos[val.from].father].wife = nodos[val.from].mother;
            }
        } else if (val.name == "PADRE") {
            nodos[val.from].father = val.to;
            if (nodos[val.from].mother != undefined) {
                nodos[nodos[val.from].father].wife = nodos[val.from].mother;
                nodos[nodos[val.from].mother].husband = nodos[val.from].father;
            }
        }
    });

    $.each(nodos, function (key, val) {
        var p = {};
        //si es mayor de 90, tachar con una raya roja
        if (val.status == 'dead') {
            val.attributes_go.push("S");
            p.n = val.name + " " + val.lastname;
        }
        else {
            p.n = val.name + " " + val.lastname + ", edad: " + val.age;
        }

        p.key = val.neo_id;

        p.s = val.gender.toUpperCase();
        if (val.mother != undefined) p.m = val.mother;
        if (val.father != undefined) p.f = val.father;
        if (val.wife != undefined) p.ux = val.wife;
        if (val.husband != undefined) p.vir = val.husband;
        if (val.attributes_go != undefined) p.a = val.attributes_go;
        people.push(p);
    });

    console.log(people);
    return people;
}
$.getJSON("api/pedigrees/" + $.urlParam('id'), function (data) {

    family = data.pedigree;
    $("#pedigreeId").val(family.id);
    console.log(data);
    currentPatient = (data.pedigree.current);

    var people = getPeopleNodesFromFamily(family);
    setupDiagram(myDiagram, people, currentPatient.neo_id);

    myDiagram.addDiagramListener("ObjectSingleClicked",
        function (e) {
            var part = e.subject.part;
            var patient = get_patient_object(family.patients, part.data.key);
            if (!(part instanceof go.Link)) set_current_patient(patient);
        });

    toggleLoading(false);
    set_current_patient(currentPatient);
});

function reloadDiagram() {
    var people = getPeopleNodesFromFamily(family);
    setupDiagram(myDiagram, people, currentPatient.neo_id);
}

function addChild(newChild) {
    family.patients.push(newChild);
    var newRelation = {
        "from": newChild.neo_id,
        "to": currentPatient.neo_id,
        "name": currentPatient.gender == "M" ? "PADRE" : "MADRE"
    };

    family.relations.push(newRelation);
    console.log(family);
    reloadDiagram();
}

function addMother(madre) {
    family.patients.push(madre);
    var newRelation = {
        "from": currentPatient.neo_id,
        "to": madre.neo_id,
        "name": "MADRE"
    };

    family.relations.push(newRelation);
    console.log(family);
    reloadDiagram();
}

function addFather(padre) {
    family.patients.push(padre);
    var newRelation = {
        "from": currentPatient.neo_id,
        "to": padre.neo_id,
        "name": "PADRE"
    };

    family.relations.push(newRelation);
    console.log(family);
    reloadDiagram();
}

function showCreateModal(type) {
    $("#patientForm")[0].reset();
    $("#typeRelationForm").val(type);
    switch (type) {
        case "CHILD":
            break;
        case "MOTHER":
            break;
        case "FATHER":
            break;
    }
    $("#modal-create-family-member").modal("show")
}

function createRelative() {
    console.log($("#patientForm").serialize());
    $.post("/api/patients", $("#patientForm").serialize())
        .done(function (data) {
            console.log(data);
            switch ($("#typeRelationForm").val()) {
                case "CHILD":
                    addChild(data.patient);
                    break;
                case "MOTHER":
                    addMother(data.patient);
                    break;
                case "FATHER":
                    addFather(data.patient);
                    break;
            }
            $.ajax({
                url: "/api/pedigrees/" + family.id,
                type: 'PUT',
                contentType: "application/json; charset=utf-8",
                data: JSON.stringify({"relations": family.relations}),
                dataType: "json"})
                .done(function (data) {
                    console.log("Pedigree Updated");
                    console.log(data);
                });
            $("#modal-create-family-member").modal("hide");
        });
}

function set_current_patient(patient) {
    currentPatient = patient;
    $("#current_patient").text(patient.name + " " + patient.lastname + " edad: " + patient.age + " sexo: " + patient.gender + " id: " + patient.id);
    $("#current_patient").show();
}

function get_patient_object(people, id) {
    var patient;
    $.each(people, function (key, val) {
        console.log("patient", val);
        if (val.neo_id == id) patient = val;
    });

    return patient;
}<|endoftext|>


<commit_before>/*eslint-env node */

module.exports = function(grunt) {
  "use strict";

  var tsConfig = {
    dev: {
      src: ["src/**/*.ts", "typings/**/*.d.ts"],
      outDir: "build/src/",
      options: {
        target: "es5",
        noImplicitAny: true,
        sourceMap: false,
        declaration: true,
        compiler: "./node_modules/typescript/bin/tsc",
        removeComments: false
      }
    },
    test: {
      src: ["test/*.ts", "typings/**/*.d.ts", "build/plottable.d.ts"],
      outDir: "build/test/",
      // watch: "test",
      options: {
        target: "es5",
        sourceMap: false,
        noImplicitAny: true,
        declaration: false,
        compiler: "./node_modules/typescript/bin/tsc",
        removeComments: false
      }
    },
    verifyDefinitionFiles: {
      src: ["typings/d3/d3.d.ts",
            "plottable.d.ts",
            "bower_components/svg-typewriter/svgtypewriter.d.ts"]
    }
  };

  var bumpConfig = {
    options: {
      files: ["package.json", "bower.json"],
      updateConfigs: ["pkg"],
      commit: false,
      createTag: false,
      push: false,
      prereleaseName: "rc"
    }
  };

  var FILES_TO_COMMIT = [
    "plottable.js",
    "plottable.min.js",
    "plottable.d.ts",
    "plottable.css",
    "plottable.zip",
    "bower.json",
    "package.json"
  ];

  var prefixMatch = "\\n *(function |var |static )?";
  var varNameMatch = "[^(:;]*(\\([^)]*\\))?"; // catch function args too
  var nestedBraceMatch = ": \\{[^{}]*\\}";
  var typeNameMatch = ": [^;]*";
  var finalMatch = "((" + nestedBraceMatch + ")|(" + typeNameMatch + "))?\\n?;";
  var jsdocInit = "\\n *\\/\\*\\* *\\n";
  var jsdocMid = "( *\\*[^\\n]*\\n)+";
  var jsdocEnd = " *\\*\\/ *";
  var jsdoc = "(" + jsdocInit + jsdocMid + jsdocEnd + ")?";

  var sedConfig = {
    privateDefinitions: {
      pattern: jsdoc + prefixMatch + "private " + varNameMatch + finalMatch,
      replacement: "",
      path: "build/plottable.d.ts"
    },
    plottableMultifile: {
      pattern: '/// *<reference path="([^."]*).ts" */>',
      replacement: 'synchronousRequire("/build/src/$1.js");',
      path: "plottable_multifile.js"
    },
    definitions: {
      pattern: '/// *<reference path=[\'"].*[\'"] */>',
      replacement: "",
      path: "build/plottable.d.ts"
    },
    testsMultifile: {
      pattern: '/// *<reference path="([^."]*).ts" */>',
      replacement: 'synchronousRequire("/build/test/$1.js");',
      path: "test/tests_multifile.js"
    },
    sublime: {
      pattern: "(.*\\.ts)",
      replacement: '/// <reference path="../$1" />',
      path: "build/sublime.d.ts"
    },
    versionNumber: {
      pattern: "@VERSION",
      replacement: "<%= pkg.version %>",
      path: "plottable.js"
    }
  };

  // e.g. ["components/foo.ts", ...]
  // the important thing is that they are sorted by hierarchy,
  // leaves first, roots last
  var tsFiles;
  // since src/reference.ts might have changed, I need to update this
  // on each recompile
  var updateTsFiles = function() {
    tsFiles = grunt.file.read("src/reference.ts")
      .split("\n")
      .filter(function(s) {
        return s !== "";
      }).map(function(s) {
        return s.match(/"(.*\.ts)"/)[1];
      });
  };
  updateTsFiles();

  var testTsFiles;
  var updateTestTsFiles = function() {
    testTsFiles = grunt.file.read("test/testReference.ts")
      .split("\n")
      .filter(function(s) {
        return s !== "";
      }).map(function(s) {
        return s.match(/"(.*\.ts)"/)[1];
      });
  };
  updateTestTsFiles();

  var browsers = [{
    browserName: "firefox",
    platform: "linux"
  }, {
    browserName: "chrome",
    platform: "linux"
  }, {
    browserName: "internet explorer",
    version: "9",
    platform: "WIN7"
  }];

  var configJSON = {
    pkg: grunt.file.readJSON("package.json"),
    bump: bumpConfig,
    umd: {
      all: {
        src: "plottable.js",
        template: "unit",
        objectToExport: "Plottable"
      }
    },
    concat: {
      header: {
        src: ["license_header.txt", "plottable.js"],
        dest: "plottable.js"
      },
      plottableMultifile: {
        src: ["synchronousRequire.js", "src/reference.ts"],
        dest: "plottable_multifile.js"
      },
      testsMultifile: {
        src: ["synchronousRequire.js", "test/testReference.ts"],
        dest: "test/tests_multifile.js"
      },
      plottable: {
        src: tsFiles.map(function(s) {
              return "build/src/" + s.replace(".ts", ".js");
          }),
        dest: "plottable.js"
      },
      tests: {
        src: testTsFiles.map(function(s) {
              return "build/test/" + s.replace(".ts", ".js");
          }),
        dest: "test/tests.js"
      },
      definitions: {
        src: tsFiles.map(function(s) {
              return "build/src/" + s.replace(".ts", ".d.ts");
          }),
        dest: "build/plottable.d.ts"
      },
      svgtypewriter: {
        src: ["plottable.js", "bower_components/svg-typewriter/svgtypewriter.js"],
        dest: "plottable.js"
      }
    },
    ts: tsConfig,
    tslint: {
      options: {
        configuration: grunt.file.readJSON("tslint.json")
      },
      all: {
        src: ["src/**/*.ts", "test/**/*.ts"]
      }
    },
    jshint: {
      files: ["Gruntfile.js", "quicktests/**/*.js"],
      options: {
        jshintrc: ".jshintrc"
      }
    },
    jscs: {
      files: ["Gruntfile.js", "quicktests/**/*.js"],
      options: {
        config: ".jscsrc"
      }
    },
    eslint: {
      target: ["Gruntfile.js", "quicktests/**/*.js"],
      options: {
        configFile: ".eslintrc"
      }
    },
    parallelize: {
      tslint: {
        all: 4
      }
    },
    watch: {
      "options": {
        livereload: true
      },
      "rebuild": {
        "tasks": ["dev-compile"],
        "files": ["src/**/*.ts", "examples/**/*.ts"]
      },
      "tests": {
        "tasks": ["test-compile"],
        "files": ["test/**/*.ts"]
      },
      "quicktests": {
        "tasks": ["update-quicktests"],
        "files": ["quicktests/overlaying/tests/**/*.js"]
      }
    },
    "blanket_mocha": {
      all: ["test/coverage.html"],
      options: {
        threshold: 70
      }
    },
    connect: {
      server: {
        options: {
          port: 9999,
          hostname: "*",
          base: "",
          livereload: true
        }
      }
    },
    clean: {
      tscommand: ["tscommand*.tmp.txt"]
    },
    sed: sedConfig,
    gitcommit: {
      version: {
        options: {
          message: "Release version <%= pkg.version %>"
        },
        files: {
          src: FILES_TO_COMMIT
        }
      },
      built: {
        options: {
          message: "Update built files"
        },
        files: {
          src: FILES_TO_COMMIT
        }
      }
    },
    compress: {
      main: {
        options: {
          archive: "plottable.zip"
        },
        files: [
        {src: "plottable.js",     dest: "."},
        {src: "plottable.min.js", dest: "."},
        {src: "plottable.d.ts",   dest: "."},
        {src: "plottable.css",    dest: "."},
        {src: "README.md",        dest: "."},
        {src: "LICENSE",          dest: "."}]
      }
    },
    uglify: {
      main: {
        files: {"plottable.min.js": ["plottable.js"]}
      }
    },
    shell: {
      sublime: {
        command: "(echo 'src/reference.ts'; find typings -name '*.d.ts') > build/sublime.d.ts"
      }
    },
    "saucelabs-mocha": {
      all: {
        options: {
          urls: ["http://127.0.0.1:9999/test/tests.html"],
          testname: "Plottable Sauce Unit Tests",
          browsers: browsers,
          build: process.env.TRAVIS_JOB_ID,
          "tunnel-identifier": process.env.TRAVIS_JOB_NUMBER
        }
      }
    }
  };

  // project configuration
  grunt.initConfig(configJSON);

  require("load-grunt-tasks")(grunt);

  // default task (this is what runs when a task isn't specified)
  grunt.registerTask("update_ts_files", updateTsFiles);
  grunt.registerTask("update_test_ts_files", updateTestTsFiles);
  grunt.registerTask("definitions_prod", function() {
    grunt.file.copy("build/plottable.d.ts", "plottable.d.ts");
  });
  grunt.registerTask("test-compile", [
    "ts:test",
    "concat:testsMultifile",
    "sed:testsMultifile",
    "concat:tests"
  ]);
  grunt.registerTask("default", "launch");

  grunt.registerTask("dev-compile", [
    "update_ts_files",
    "update_test_ts_files",
    "ts:dev",
    "concat:plottable",
    "concat:svgtypewriter",
    "concat:definitions",
    "sed:definitions",
    "sed:privateDefinitions",
    "umd:all",
    "concat:header",
    "sed:versionNumber",
    "definitions_prod",
    "test-compile",
    "concat:plottableMultifile",
    "sed:plottableMultifile",
    "clean:tscommand",
    "update-quicktests"
  ]);

  grunt.registerTask("release:patch", ["bump:patch", "dist-compile", "gitcommit:version"]);
  grunt.registerTask("release:minor", ["bump:minor", "dist-compile", "gitcommit:version"]);
  grunt.registerTask("release:major", ["bump:major", "dist-compile", "gitcommit:version"]);

  grunt.registerTask("dist-compile", [
    "dev-compile",
    "blanket_mocha",
    "parallelize:tslint",
    "ts:verifyDefinitionFiles",
    "uglify",
    "compress"
  ]);

  grunt.registerTask("commitjs", ["dist-compile", "gitcommit:built"]);
  grunt.registerTask("launch", ["connect", "dev-compile", "watch"]);
  grunt.registerTask("test-sauce", ["connect", "saucelabs-mocha"]);
  grunt.registerTask("test", [
    "dev-compile",
    "blanket_mocha",
    "parallelize:tslint",
    "jshint",
    "ts:verifyDefinitionFiles",
    "jscs",
    "eslint"
  ]);

  // Disable saucelabs for external pull requests. Check if we can see the SAUCE_USERNAME
  var travisTests = ["test"];
  if (process.env.SAUCE_USERNAME) {
    travisTests.push("test-sauce");
  }
  grunt.registerTask("test-travis", travisTests);
  grunt.registerTask("bm", ["blanket_mocha"]);

  grunt.registerTask("sublime", [
    "shell:sublime",
    "sed:sublime"
  ]);

  grunt.registerTask("update-quicktests", function() {
    var qtJSON = [];
    var rawtests = grunt.file.expand("quicktests/overlaying/tests/**/*.js");
    rawtests.forEach(function(value) {
      qtJSON.push({ path: value });
    });
    qtJSON = JSON.stringify(qtJSON);
    qtJSON = qtJSON.split(",").join(",\n") + "\n";
    grunt.file.write("quicktests/overlaying/list_of_quicktests.json", qtJSON);
  });

};
<commit_msg>[gruntfileRefactor] Extracting configs part 1<commit_after>/*eslint-env node */

module.exports = function(grunt) {
  "use strict";

  var tsConfig = {
    dev: {
      src: ["src/**/*.ts", "typings/**/*.d.ts"],
      outDir: "build/src/",
      options: {
        target: "es5",
        noImplicitAny: true,
        sourceMap: false,
        declaration: true,
        compiler: "./node_modules/typescript/bin/tsc",
        removeComments: false
      }
    },
    test: {
      src: ["test/*.ts", "typings/**/*.d.ts", "build/plottable.d.ts"],
      outDir: "build/test/",
      // watch: "test",
      options: {
        target: "es5",
        sourceMap: false,
        noImplicitAny: true,
        declaration: false,
        compiler: "./node_modules/typescript/bin/tsc",
        removeComments: false
      }
    },
    verifyDefinitionFiles: {
      src: ["typings/d3/d3.d.ts",
            "plottable.d.ts",
            "bower_components/svg-typewriter/svgtypewriter.d.ts"]
    }
  };

  var bumpConfig = {
    options: {
      files: ["package.json", "bower.json"],
      updateConfigs: ["pkg"],
      commit: false,
      createTag: false,
      push: false,
      prereleaseName: "rc"
    }
  };

  var FILES_TO_COMMIT = [
    "plottable.js",
    "plottable.min.js",
    "plottable.d.ts",
    "plottable.css",
    "plottable.zip",
    "bower.json",
    "package.json"
  ];

  var prefixMatch = "\\n *(function |var |static )?";
  var varNameMatch = "[^(:;]*(\\([^)]*\\))?"; // catch function args too
  var nestedBraceMatch = ": \\{[^{}]*\\}";
  var typeNameMatch = ": [^;]*";
  var finalMatch = "((" + nestedBraceMatch + ")|(" + typeNameMatch + "))?\\n?;";
  var jsdocInit = "\\n *\\/\\*\\* *\\n";
  var jsdocMid = "( *\\*[^\\n]*\\n)+";
  var jsdocEnd = " *\\*\\/ *";
  var jsdoc = "(" + jsdocInit + jsdocMid + jsdocEnd + ")?";

  var sedConfig = {
    privateDefinitions: {
      pattern: jsdoc + prefixMatch + "private " + varNameMatch + finalMatch,
      replacement: "",
      path: "build/plottable.d.ts"
    },
    plottableMultifile: {
      pattern: '/// *<reference path="([^."]*).ts" */>',
      replacement: 'synchronousRequire("/build/src/$1.js");',
      path: "plottable_multifile.js"
    },
    definitions: {
      pattern: '/// *<reference path=[\'"].*[\'"] */>',
      replacement: "",
      path: "build/plottable.d.ts"
    },
    testsMultifile: {
      pattern: '/// *<reference path="([^."]*).ts" */>',
      replacement: 'synchronousRequire("/build/test/$1.js");',
      path: "test/tests_multifile.js"
    },
    sublime: {
      pattern: "(.*\\.ts)",
      replacement: '/// <reference path="../$1" />',
      path: "build/sublime.d.ts"
    },
    versionNumber: {
      pattern: "@VERSION",
      replacement: "<%= pkg.version %>",
      path: "plottable.js"
    }
  };

  // e.g. ["components/foo.ts", ...]
  // the important thing is that they are sorted by hierarchy,
  // leaves first, roots last
  var tsFiles;
  // since src/reference.ts might have changed, I need to update this
  // on each recompile
  var updateTsFiles = function() {
    tsFiles = grunt.file.read("src/reference.ts")
      .split("\n")
      .filter(function(s) {
        return s !== "";
      }).map(function(s) {
        return s.match(/"(.*\.ts)"/)[1];
      });
  };
  updateTsFiles();

  var testTsFiles;
  var updateTestTsFiles = function() {
    testTsFiles = grunt.file.read("test/testReference.ts")
      .split("\n")
      .filter(function(s) {
        return s !== "";
      }).map(function(s) {
        return s.match(/"(.*\.ts)"/)[1];
      });
  };
  updateTestTsFiles();

  var umdConfig = {
    all: {
      src: "plottable.js",
      template: "unit",
      objectToExport: "Plottable"
    }
  };

  var concatConfig = {
    header: {
      src: ["license_header.txt", "plottable.js"],
      dest: "plottable.js"
    },
    plottableMultifile: {
      src: ["synchronousRequire.js", "src/reference.ts"],
      dest: "plottable_multifile.js"
    },
    testsMultifile: {
      src: ["synchronousRequire.js", "test/testReference.ts"],
      dest: "test/tests_multifile.js"
    },
    plottable: {
      src: tsFiles.map(function(s) {
            return "build/src/" + s.replace(".ts", ".js");
        }),
      dest: "plottable.js"
    },
    tests: {
      src: testTsFiles.map(function(s) {
            return "build/test/" + s.replace(".ts", ".js");
        }),
      dest: "test/tests.js"
    },
    definitions: {
      src: tsFiles.map(function(s) {
            return "build/src/" + s.replace(".ts", ".d.ts");
        }),
      dest: "build/plottable.d.ts"
    },
    svgtypewriter: {
      src: ["plottable.js", "bower_components/svg-typewriter/svgtypewriter.js"],
      dest: "plottable.js"
    }
  };

  var tslintConfig = {
    options: {
      configuration: grunt.file.readJSON("tslint.json")
    },
    all: {
      src: ["src/**/*.ts", "test/**/*.ts"]
    }
  };

  var jshintConfig = {
    files: ["Gruntfile.js", "quicktests/**/*.js"],
    options: {
      jshintrc: ".jshintrc"
    }
  };

  var jscsConfig = {
    files: ["Gruntfile.js", "quicktests/**/*.js"],
    options: {
      config: ".jscsrc"
    }
  };

  var eslintConfig = {
    target: ["Gruntfile.js", "quicktests/**/*.js"],
    options: {
      configFile: ".eslintrc"
    }
  };

  var parallelizeConfig = {
    tslint: {
      all: 4
    }
  };

  var configJSON = {
    pkg: grunt.file.readJSON("package.json"),
    bump: bumpConfig,
    umd: umdConfig,
    concat: concatConfig,
    ts: tsConfig,
    tslint: tslintConfig,
    jshint: jshintConfig,
    jscs: jscsConfig,
    eslint: eslintConfig,
    parallelize: parallelizeConfig,
    watch: {
      "options": {
        livereload: true
      },
      "rebuild": {
        "tasks": ["dev-compile"],
        "files": ["src/**/*.ts", "examples/**/*.ts"]
      },
      "tests": {
        "tasks": ["test-compile"],
        "files": ["test/**/*.ts"]
      },
      "quicktests": {
        "tasks": ["update-quicktests"],
        "files": ["quicktests/overlaying/tests/**/*.js"]
      }
    },
    "blanket_mocha": {
      all: ["test/coverage.html"],
      options: {
        threshold: 70
      }
    },
    connect: {
      server: {
        options: {
          port: 9999,
          hostname: "*",
          base: "",
          livereload: true
        }
      }
    },
    clean: {
      tscommand: ["tscommand*.tmp.txt"]
    },
    sed: sedConfig,
    gitcommit: {
      version: {
        options: {
          message: "Release version <%= pkg.version %>"
        },
        files: {
          src: FILES_TO_COMMIT
        }
      },
      built: {
        options: {
          message: "Update built files"
        },
        files: {
          src: FILES_TO_COMMIT
        }
      }
    },
    compress: {
      main: {
        options: {
          archive: "plottable.zip"
        },
        files: [
        {src: "plottable.js",     dest: "."},
        {src: "plottable.min.js", dest: "."},
        {src: "plottable.d.ts",   dest: "."},
        {src: "plottable.css",    dest: "."},
        {src: "README.md",        dest: "."},
        {src: "LICENSE",          dest: "."}]
      }
    },
    uglify: {
      main: {
        files: {"plottable.min.js": ["plottable.js"]}
      }
    },
    shell: {
      sublime: {
        command: "(echo 'src/reference.ts'; find typings -name '*.d.ts') > build/sublime.d.ts"
      }
    },
    "saucelabs-mocha": {
      all: {
        options: {
          urls: ["http://127.0.0.1:9999/test/tests.html"],
          testname: "Plottable Sauce Unit Tests",
          browsers: [{
            browserName: "firefox",
            platform: "linux"
          }, {
            browserName: "chrome",
            platform: "linux"
          }, {
            browserName: "internet explorer",
            version: "9",
            platform: "WIN7"
          }],
          build: process.env.TRAVIS_JOB_ID,
          "tunnel-identifier": process.env.TRAVIS_JOB_NUMBER
        }
      }
    }
  };

  // project configuration
  grunt.initConfig(configJSON);

  require("load-grunt-tasks")(grunt);

  // default task (this is what runs when a task isn't specified)
  grunt.registerTask("update_ts_files", updateTsFiles);
  grunt.registerTask("update_test_ts_files", updateTestTsFiles);
  grunt.registerTask("definitions_prod", function() {
    grunt.file.copy("build/plottable.d.ts", "plottable.d.ts");
  });
  grunt.registerTask("test-compile", [
    "ts:test",
    "concat:testsMultifile",
    "sed:testsMultifile",
    "concat:tests"
  ]);
  grunt.registerTask("default", "launch");

  grunt.registerTask("dev-compile", [
    "update_ts_files",
    "update_test_ts_files",
    "ts:dev",
    "concat:plottable",
    "concat:svgtypewriter",
    "concat:definitions",
    "sed:definitions",
    "sed:privateDefinitions",
    "umd:all",
    "concat:header",
    "sed:versionNumber",
    "definitions_prod",
    "test-compile",
    "concat:plottableMultifile",
    "sed:plottableMultifile",
    "clean:tscommand",
    "update-quicktests"
  ]);

  grunt.registerTask("release:patch", ["bump:patch", "dist-compile", "gitcommit:version"]);
  grunt.registerTask("release:minor", ["bump:minor", "dist-compile", "gitcommit:version"]);
  grunt.registerTask("release:major", ["bump:major", "dist-compile", "gitcommit:version"]);

  grunt.registerTask("dist-compile", [
    "dev-compile",
    "blanket_mocha",
    "parallelize:tslint",
    "ts:verifyDefinitionFiles",
    "uglify",
    "compress"
  ]);

  grunt.registerTask("commitjs", ["dist-compile", "gitcommit:built"]);
  grunt.registerTask("launch", ["connect", "dev-compile", "watch"]);
  grunt.registerTask("test-sauce", ["connect", "saucelabs-mocha"]);
  grunt.registerTask("test", [
    "dev-compile",
    "blanket_mocha",
    "parallelize:tslint",
    "jshint",
    "ts:verifyDefinitionFiles",
    "jscs",
    "eslint"
  ]);

  // Disable saucelabs for external pull requests. Check if we can see the SAUCE_USERNAME
  var travisTests = ["test"];
  if (process.env.SAUCE_USERNAME) {
    travisTests.push("test-sauce");
  }
  grunt.registerTask("test-travis", travisTests);
  grunt.registerTask("bm", ["blanket_mocha"]);

  grunt.registerTask("sublime", [
    "shell:sublime",
    "sed:sublime"
  ]);

  grunt.registerTask("update-quicktests", function() {
    var qtJSON = [];
    var rawtests = grunt.file.expand("quicktests/overlaying/tests/**/*.js");
    rawtests.forEach(function(value) {
      qtJSON.push({ path: value });
    });
    qtJSON = JSON.stringify(qtJSON);
    qtJSON = qtJSON.split(",").join(",\n") + "\n";
    grunt.file.write("quicktests/overlaying/list_of_quicktests.json", qtJSON);
  });

};
<|endoftext|>


<commit_before>var Promise = require('bluebird');

var story = require('storyboard').mainStory;
var request = require('request');
var moment = require("moment");
var redis = require('../db/redis_db');
var db = require('../db/sql_db');
var utils = require('../utils');
var plugged = require('../client');
var config = require('../load_config');
var langfile = require('../../langfile');
var songfilters = require('../songfilters');

var websocketUpdate = require('../../web/index').wsGet('advance');

var timeouts = {
    stuck: null,
    tskip: null
};

module.exports = {
    event: plugged.ADVANCE,
    handler: function (booth, now, prev) {
        booth = utils.clone(booth);
        now = utils.clone(now);
        prev = utils.clone(prev);
        if (booth.dj !== undefined) {
            Promise.all(songfilters.map(function (e) {
                return e(booth, now);
            })).catch(function (error) {
                story.debug('SongFilters', '', {attach: error});
                if (plugged.getMedia().id === now.media.id) {
                    plugged.sendChat(error.preskip);
                    if (error.do_lockskip) {
                        plugged.setCyclePromise(true).then(function () {
                            return plugged.skipDJPromise(booth.dj);
                        }).then(function () {
                            if (config.lockskip.move_pos !== undefined) plugged.moveDJ(booth.dj, config.lockskip.move_pos);
                            return Promise.resolve();
                        }).then(function () {
                            if (booth.shouldCycle !== plugged.doesWaitlistCycle()) return plugged.setCyclePromise(booth.shouldCycle);
                            else Promise.resolve();
                        }).then(function () {
                            plugged.sendChat(error.afterskip);
                            if (error.blacklist) db.blacklist.add(now.media.format, now.media.cid, error.bl_reason || undefined);
                        }).catch(function (err) {
                            story.error('Error while lockskipping.', {attach: err});
                        });
                    } else {
                        plugged.skipDJ(booth.dj);
                        setTimeout(function () {
                            plugged.sendChat(error.afterskip);
                            if (error.blacklist) db.blacklist.add(now.media.format, now.media.cid, error.bl_reason || undefined);
                        }, 4 * 1000);
                    }
                }
            });
            db.models.Song.findOrCreate({
                where: {cid: now.media.cid, format: now.media.format}, defaults: {
                    title: now.media.title,
                    author: now.media.author,
                    image: now.media.image,
                    duration: now.media.duration,
                    format: now.media.format,
                    plug_id: now.media.id,
                    cid: now.media.cid
                }
            }).spread(function (song) {
                song.updateAttributes({
                    image: now.media.image,
                    title: now.media.title,
                    author: now.media.author,
                    duration: now.media.duration
                });
                if (song.autovote !== 'n') {
                    if (song.autovote === 'w') plugged.woot();
                    else if (song.autovote === 'm')plugged.meh();
                }
                if (song.tskip !== null && song.tskip !== undefined && !config.state.eventmode) {
                    plugged.sendChat(utils.replace(langfile.tskip.default, {time: song.tskip}), song.tskip * 1000);
                    setTimeout(function () {
                        if (plugged.getMedia().id === now.media.id) {
                            plugged.sendChat(langfile.tskip.skip, 60 * 1000);
                            plugged.skipDJ(booth.dj);
                        }
                    }, song.tskip * 1000);
                }
            });
            story.info('advance', utils.userLogString(plugged.getUserByID(booth.dj)) + ': ' + utils.mediatitlelog(now.media));
        } else story.info('advance', 'Nobody is playing!');
        clearTimeout(timeouts.stuck);
        clearTimeout(timeouts.tskip);
        if (booth.dj !== undefined) {
            timeouts.stuck = setTimeout(function () {
                if (plugged.getMedia().id === now.media.id) {
                    plugged.sendChat(langfile.skip.stuck.default, 30);
                    plugged.skipDJ(booth.dj, now.historyID);
                }
            }, (now.media.duration + 5) * 1000);
        }
        if (prev.dj !== undefined) {
            redis.set('media:history:' + prev.media.format + ':' + prev.media.cid, 1).then(function () {
                redis.expire('media:history:' + prev.media.format + ':' + prev.media.cid, config.history.time * 60);
            });
            db.sequelize.transaction(function (t) {
                return db.models.Play.create({
                    time: new Date,
                    woots: prev.score.positive,
                    mehs: prev.score.negative,
                    grabs: prev.score.grabs
                }, {transaction: t}).then(function (play) {
                    //noinspection JSUnresolvedFunction
                    return play.setSong(prev.media.id, {transaction: t}).then(function () {
                        //noinspection JSUnresolvedFunction
                        return play.setUser(prev.dj.id, {transaction: t});
                    });
                });
            });
            story.info('score', utils.mediatitlelog(prev.media) + ' woots: ' + prev.score.positive + ' | grabs: ' + prev.score.grabs + ' | mehs: ' + prev.score.negative);
        }
        redis.del('meta:data:rdjskip:votes');
        websocketUpdate({
            m: function () {
                if (now.media.id !== -1) {
                    return {
                        cid: now.media.format + ':' + now.media.cid,
                        t: now.media.title,
                        a: now.media.author
                    };
                } else return null;
            }(),
            dj: function () {
                if (booth.dj !== -1 && booth.dj !== undefined) {
                    var u = plugged.getUserByID(booth.dj);
                    return {id: u.id, n: u.username};
                } else return null;

            }()
        });
    }
};<commit_msg>catch failed transactions<commit_after>var Promise = require('bluebird');

var story = require('storyboard').mainStory;
var request = require('request');
var moment = require("moment");
var redis = require('../db/redis_db');
var db = require('../db/sql_db');
var utils = require('../utils');
var plugged = require('../client');
var config = require('../load_config');
var langfile = require('../../langfile');
var songfilters = require('../songfilters');

var websocketUpdate = require('../../web/index').wsGet('advance');

var timeouts = {
    stuck: null,
    tskip: null
};

module.exports = {
    event: plugged.ADVANCE,
    handler: function (booth, now, prev) {
        booth = utils.clone(booth);
        now = utils.clone(now);
        prev = utils.clone(prev);
        if (booth.dj !== undefined) {
            Promise.all(songfilters.map(function (e) {
                return e(booth, now);
            })).catch(function (error) {
                story.debug('SongFilters', '', {attach: error});
                if (plugged.getMedia().id === now.media.id) {
                    plugged.sendChat(error.preskip);
                    if (error.do_lockskip) {
                        plugged.setCyclePromise(true).then(function () {
                            return plugged.skipDJPromise(booth.dj);
                        }).then(function () {
                            if (config.lockskip.move_pos !== undefined) plugged.moveDJ(booth.dj, config.lockskip.move_pos);
                            return Promise.resolve();
                        }).then(function () {
                            if (booth.shouldCycle !== plugged.doesWaitlistCycle()) return plugged.setCyclePromise(booth.shouldCycle);
                            else Promise.resolve();
                        }).then(function () {
                            plugged.sendChat(error.afterskip);
                            if (error.blacklist) db.blacklist.add(now.media.format, now.media.cid, error.bl_reason || undefined);
                        }).catch(function (err) {
                            story.error('Error while lockskipping.', {attach: err});
                        });
                    } else {
                        plugged.skipDJ(booth.dj);
                        setTimeout(function () {
                            plugged.sendChat(error.afterskip);
                            if (error.blacklist) db.blacklist.add(now.media.format, now.media.cid, error.bl_reason || undefined);
                        }, 4 * 1000);
                    }
                }
            });
            db.models.Song.findOrCreate({
                where: {cid: now.media.cid, format: now.media.format}, defaults: {
                    title: now.media.title,
                    author: now.media.author,
                    image: now.media.image,
                    duration: now.media.duration,
                    format: now.media.format,
                    plug_id: now.media.id,
                    cid: now.media.cid
                }
            }).spread(function (song) {
                song.updateAttributes({
                    image: now.media.image,
                    title: now.media.title,
                    author: now.media.author,
                    duration: now.media.duration
                });
                if (song.autovote !== 'n') {
                    if (song.autovote === 'w') plugged.woot();
                    else if (song.autovote === 'm')plugged.meh();
                }
                if (song.tskip !== null && song.tskip !== undefined && !config.state.eventmode) {
                    plugged.sendChat(utils.replace(langfile.tskip.default, {time: song.tskip}), song.tskip * 1000);
                    setTimeout(function () {
                        if (plugged.getMedia().id === now.media.id) {
                            plugged.sendChat(langfile.tskip.skip, 60 * 1000);
                            plugged.skipDJ(booth.dj);
                        }
                    }, song.tskip * 1000);
                }
            });
            story.info('advance', utils.userLogString(plugged.getUserByID(booth.dj)) + ': ' + utils.mediatitlelog(now.media));
        } else story.info('advance', 'Nobody is playing!');
        clearTimeout(timeouts.stuck);
        clearTimeout(timeouts.tskip);
        if (booth.dj !== undefined) {
            timeouts.stuck = setTimeout(function () {
                if (plugged.getMedia().id === now.media.id) {
                    plugged.sendChat(langfile.skip.stuck.default, 30);
                    plugged.skipDJ(booth.dj, now.historyID);
                }
            }, (now.media.duration + 5) * 1000);
        }
        if (prev.dj !== undefined) {
            redis.set('media:history:' + prev.media.format + ':' + prev.media.cid, 1).then(function () {
                redis.expire('media:history:' + prev.media.format + ':' + prev.media.cid, config.history.time * 60);
            });
            db.sequelize.transaction(function (t) {
                return db.models.Play.create({
                    time: new Date,
                    woots: prev.score.positive,
                    mehs: prev.score.negative,
                    grabs: prev.score.grabs
                }, {transaction: t}).then(function (play) {
                    //noinspection JSUnresolvedFunction
                    return play.setSong(prev.media.id, {transaction: t}).then(function () {
                        //noinspection JSUnresolvedFunction
                        return play.setUser(prev.dj.id, {transaction: t});
                    });
                });
            }).catch(function () {
                story.debug('SQL','Transaction errored while creating play. You skipped to fast...');
            });
            story.info('score', utils.mediatitlelog(prev.media) + ' woots: ' + prev.score.positive + ' | grabs: ' + prev.score.grabs + ' | mehs: ' + prev.score.negative);
        }
        redis.del('meta:data:rdjskip:votes');
        websocketUpdate({
            m: function () {
                if (now.media.id !== -1) {
                    return {
                        cid: now.media.format + ':' + now.media.cid,
                        t: now.media.title,
                        a: now.media.author
                    };
                } else return null;
            }(),
            dj: function () {
                if (booth.dj !== -1 && booth.dj !== undefined) {
                    var u = plugged.getUserByID(booth.dj);
                    return {id: u.id, n: u.username};
                } else return null;

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


<commit_before>// Copyright (c) 2011 Hewlett-Packard Development Company, L.P. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Build and fly through a 3D world using Three.js

var WebVfx = WebVfx || {};

WebVfx.ThreeWorld = function (width, height, nearPlane, farPlane, animationData, readyCallback) {
    var self = this;

    this.tracker = new WebVfx.Tracker(function () {
        readyCallback();
        delete self.tracker;
    });
    this.jsonLoader = new THREE.JSONLoader();

    var aspect = width / height;
    this.camera = new WebVfx.AnimatedCamera(aspect, nearPlane, farPlane,
                                            animationData);
    this.scene = new THREE.Scene();
    // Blender OBJ and three.js exporters rotate scene by -PI/2 in X,
    // undo that here so our camera animation data works.
    this.scene.rotation.x = Math.PI / 2;
    this.scene.updateMatrix();

    this.widescreen = aspect > (4 / 3);

    // Create and size canvas ourself, more efficient to size it up front
    var canvas = document.createElement("canvas");
    canvas.width = width;
    canvas.height = height;
    this.renderer = new THREE.WebGLRenderer({ canvas: canvas,
                                              antialias: true });
    // Need to enable this for our shader
    if (!this.renderer.context.getExtension("OES_standard_derivatives"))
        console.log("OES_standard_derivatives not supported");
    this.renderer.setViewport(0, 0, width, height);
    document.body.appendChild(canvas);

    // Treat page load as trackable
    if (document.readyState != "complete") {
        this.tracker.increment();
        window.addEventListener('load', function (event) {
            self.tracker.decrement();
        }, false);
    }
};

WebVfx.ThreeWorld.prototype = {
    // Must be called to start resource tracking
    startTracking: function () {
        this.tracker.start();
    },

    // Optional _callback_ will be passed the Mesh for additional configuring
    addJSONModel: function (url, material, callback) {
        var self = this;
        this.tracker.increment();
        this.jsonLoader.load({ model: url, callback: function (geometry) {
            var mesh = new THREE.Mesh(geometry, material);
            if (callback)
                callback(mesh);
            self.scene.addObject(mesh);
            self.tracker.decrement();
        } });
    },

    resize: function (width, height) {
        this.renderer.setSize(width, height);
        this.camera.aspect = width / height;
        this.camera.updateProjectionMatrix();
        this.widescreen = this.camera.aspect > (4 / 3);
    },

    render: function (time) {
        this.camera.setAnimationTime(time);
        this.renderer.render(this.scene, this.camera);
    }
};

///////////

WebVfx.loadImageTexture = function (url, tracker) {
    var image = new Image();
    var texture = new THREE.Texture(image);
    WebVfx.trackTextureImage(texture, tracker);
    image.src = url;
    return texture;
};

WebVfx.trackTextureImage = function (texture, tracker) {
    var image = texture.image;
    if (!(image instanceof Image) || image.complete) {
        texture.needsUpdate = true;
        return;
    }
    tracker.increment();
    image.addEventListener("load", function () {
        texture.needsUpdate = true;
        tracker.decrement();
    });
};

///////////

// _options_ includes:
// fontStyle - e.g. "30px Helvetica". If it uses a font loaded with @font-face,
//   then you must use a WebVfx.FontTracker and create the text Texture after
//   the font has loaded.
// textColor - Text color css spec.
// backgroundColor - Background color css spec.
// textAlign - "left", "right" or "center".
// textBaseline - "top", "middle" or "bottom"
WebVfx.createTextTexture = function (text, targetWidth, targetHeight, options) {
    var fontStyle = options.fontStyle;
    var textColor = options.textColor;
    var backgroundColor = options.backgroundColor;
    var textAlign = options.textAlign;
    var textBaseline = options.textBaseline;

    // Canvas context provides measureText(), but this only exposes width.
    // So apply same font style to span and measure it.
    // FYI span text looks much better than canvas text because span uses
    // subpixel antialiasing
    var span = document.createElement("span");
    span.style.visibility = "hidden";
    span.style.font = fontStyle;
    span.textContent = text;
    document.body.appendChild(span);
    var textWidth = span.offsetWidth;
    var textHeight = span.offsetHeight;
    document.body.removeChild(span);

    var scale = Math.min(targetWidth / textWidth, targetHeight / textHeight);

    var canvas = document.createElement("canvas");
    canvas.width = targetWidth;
    canvas.height = targetHeight;

    var context = canvas.getContext("2d");
    if (backgroundColor) {
        context.fillStyle = backgroundColor;
        context.fillRect(0, 0, targetWidth, targetHeight);
    }
    // Scale text to fit if too large
    var positionScale = 1;
    if (scale < 1) {
        context.scale(scale, scale);
        positionScale = 1 / scale;
    }
    context.font = fontStyle;
    context.fillStyle = textColor;

    var x = 0, y = 0;

    switch (textAlign) {
    case "right":
        x = targetWidth;
        break;
    case "center":
        x = targetWidth / 2;
        break;
    case "left":
    default:
        textAlign = "left";
        break;
    }
    context.textAlign = textAlign;

    switch (textBaseline) {
    case "middle":
        y = targetHeight / 2;
        break;
    case "bottom":
        y = targetHeight;
        break;
    case "top":
    default:
        textBaseline = "top";
        break;
    }
    context.textBaseline = textBaseline;

    context.fillText(text, x * positionScale, y * positionScale);

    var texture = new THREE.Texture(canvas);
    texture.needsUpdate = true;
    return texture;
}

///////////

WebVfx.updateVideoTexture = function (texture, name) {
    texture.image = webvfx.getImage(name).toImageData();
    texture.needsUpdate = true;
};

///////////

// Texture mesh by multiplying two textures.
// Texture regions outside of UV space can be colored.
// Parameters:
//  texture1 - THREE.Texture - uses main UV
//  texture2 - (optional) THREE.Texture - uses secondary UV
//  borderColor - (optional) THREE.Color - color of regions outside UV space.
//   Setting this also triggers antialiasing of the edges.
//  borderOpacity - float opacity of regions outside UV space (default 1.0)
WebVfx.MeshMultitextureMaterial = function (parameters) {
    var vertexShader = this.shaderLibrary['vertexShader'];
    var fragmentShader = this.shaderLibrary['fragmentShader'];
    var vertexPrefix = [];
    var fragmentPrefix = [];

    var uniforms = {
        texture1: { type: "t", value: 0, texture: parameters.texture1 }
    };
    if (parameters.texture2) {
        uniforms.texture2 = { type: "t", value: 1, texture: parameters.texture2 };
        vertexPrefix.push("#define USE_TEXTURE2");
        fragmentPrefix.push("#define USE_TEXTURE2");
    }
    if (parameters.borderColor) {
        uniforms.borderColor = { type: "c", value: parameters.borderColor };
        uniforms.borderOpacity = { type: "f", value: parameters.borderOpacity || 1.0 };
        fragmentPrefix.push("#define USE_BORDERCOLOR");
    }

    if (vertexPrefix.length > 0)
        vertexShader = vertexPrefix.join("\n") + vertexShader;
    if (fragmentPrefix.length > 0)
        fragmentShader = fragmentPrefix.join("\n") + fragmentShader;

    THREE.MeshShaderMaterial.call(this, {
        uniforms: uniforms,
        fragmentShader: fragmentShader,
        vertexShader: vertexShader
    });
};

WebVfx.MeshMultitextureMaterial.prototype = new THREE.MeshShaderMaterial();
WebVfx.MeshMultitextureMaterial.prototype.constructor = WebVfx.MeshMultitextureMaterial;

WebVfx.MeshMultitextureMaterial.prototype.shaderLibrary = {
    vertexShader: [
        "",
        "varying vec2 vUv;",
        "#ifdef USE_TEXTURE2",
        "varying vec2 vUv2;",
        "#endif",
        "void main() {",
        "    vUv = uv;",
        "#ifdef USE_TEXTURE2",
        "    vUv2 = uv2;",
        "#endif",
        "    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);",
        "}"
    ].join("\n"),
    fragmentShader: [
        "",
        "varying vec2 vUv;",
        "uniform sampler2D texture1;",

        "#ifdef USE_TEXTURE2",
        "varying vec2 vUv2;",
        "uniform sampler2D texture2;",
        "#endif",

        "#ifdef USE_BORDERCOLOR",
        "#extension GL_OES_standard_derivatives : enable",
        "uniform vec3 borderColor;",
        "uniform float borderOpacity;",

        "vec4 antialias(vec2 uv, vec2 fw, sampler2D texture, vec4 color) {",
        "    vec2 marginTL = -fw;",
        "    vec2 marginBR = 1.0 + fw;",
        //   // Completely outside the texture margins, use color
        "    if (uv.s <= marginTL.s || uv.s >= marginBR.s",
        "        || uv.t <= marginTL.t || uv.t >= marginBR.t)",
        "        return color;",
        //   // Completely inside the texture, use texture
        "    else if (uv.s >= 0.0 && uv.s <= 1.0 && uv.t >= 0.0 && uv.t <= 1.0)",
        "        return texture2D(texture, uv);",
        //   // Inside a margin - mix color and texture to antialias
        "    else {",
        //       // Amount of mix - 0.0 is all color, 1.0 is all texture
        "        float p = 0.0;",
        "        int c = 0;",
        "        if (uv.s < 0.0) {",
        "            p += smoothstep(marginTL.s, 0.0, uv.s);",
        "            c++;",
        "        }",
        "        else if (uv.s > 1.0) {",
        "            p += 1.0 - smoothstep(1.0, marginBR.s, uv.s);",
        "            c++;",
        "        }",
        "        if (uv.t < 0.0) {",
        "            p += smoothstep(marginTL.t, 0.0, uv.t);",
        "            c++;",
        "        }",
        "        else if (uv.t > 1.0) {",
        "            p += 1.0 - smoothstep(1.0, marginBR.t, uv.t);",
        "            c++;",
        "        }",
        "        return mix(color, texture2D(texture, uv), p / float(c));",
        "    }",
        "}",
        "#endif",

        "void main() {",
        "#ifdef USE_BORDERCOLOR",
        "    vec4 border = vec4(borderColor, borderOpacity);",
        "    gl_FragColor = antialias(vUv, fwidth(vUv), texture1, border);",
        "#else",
        "    gl_FragColor = texture2D(texture1, vUv);",
        "#endif",

        "#ifdef USE_TEXTURE2",
        "#ifdef USE_BORDERCOLOR",
        "    gl_FragColor = gl_FragColor * antialias(vUv2, fwidth(vUv2), texture2, border);",
        "#else",
        "    gl_FragColor = gl_FragColor * texture2D(texture2, vUv2);",
        "#endif",
        "#endif",
        "}"
    ].join("\n")
};

///////////

// Set UV coords for given layer, for a single quad
WebVfx.setQuadUvs = function (mesh, layer, u1, v1, u2, v2, u3, v3, u4, v4) {
    var uvs = [new THREE.UV(u1, v1),
               new THREE.UV(u2, v2),
               new THREE.UV(u3, v3),
               new THREE.UV(u4, v4)];
    mesh.geometry.faceVertexUvs[layer] = [uvs];
}

// Map (scale/translate) UVs from _fromLayer_ to _toLayer_
// min/max specifies new UV coordinate space range.
WebVfx.mapUvs = function (mesh, fromLayer, toLayer, minU, minV, maxU, maxV) {
    var uvs = mesh.geometry.faceVertexUvs[fromLayer];
    var length = uvs.length;

    // Find UV space we are mapping from
    var fromMinU = Number.MAX_VALUE;
    var fromMaxU = Number.MIN_VALUE;
    var fromMinV = Number.MAX_VALUE;
    var fromMaxV = Number.MIN_VALUE;
    for (var i = 0; i < length; i++) {
        var faceUv = uvs[i];
        var faceUvLength = faceUv.length;
        for (var j = 0; j < faceUvLength; j++) {
            var uv = faceUv[j];
            fromMinU = Math.min(uv.u, fromMinU);
            fromMaxU = Math.max(uv.u, fromMaxU);
            fromMinV = Math.min(uv.v, fromMinV);
            fromMaxV = Math.max(uv.v, fromMaxV);
        }
    }

    var fromDistU = fromMaxU - fromMinU;
    var fromDistV = fromMaxV - fromMinV;
    var toDistU = maxU - minU;
    var toDistV = maxV - minV;

    var mappedUvs = new Array(length);
    for (var i = 0; i < length; i++) {
        var faceUv = uvs[i];
        var faceUvLength = faceUv.length;
        var mappedFaceUv = new Array(faceUvLength);
        mappedUvs[i] = mappedFaceUv;
        for (var j = 0; j < faceUvLength; j++) {
            var uv = faceUv[j];
            var u = minU + (((uv.u - fromMinU) / fromDistU) * toDistU);
            var v = minV + (((uv.v - fromMinV) / fromDistV) * toDistV);
            mappedFaceUv[j] = new THREE.UV(u, v);
        }
    }

    mesh.geometry.faceVertexUvs[toLayer] = mappedUvs;
}

///////////

WebVfx.AnimatedCamera = function (aspect, nearPlane, farPlane, animationData) {
    var anim = new WebVfx.Animation(animationData);
    this.animation = anim;
    var fov = anim.radians2degrees(anim.verticalFOV(aspect));
    THREE.Camera.call(this, fov, aspect, nearPlane, farPlane);
    this.useTarget = false;
    // Blender XYZ order is really ZYX
    this.eulerOrder = 'ZYX';
};

WebVfx.AnimatedCamera.prototype = new THREE.Camera();
WebVfx.AnimatedCamera.prototype.constructor = WebVfx.AnimatedCamera;

WebVfx.AnimatedCamera.prototype.setAnimationTime = function (time) {
    var anim = this.animation;
    anim.evaluateTime(time);
    this.position.x = anim.locationX;
    this.position.y = anim.locationY;
    this.position.z = anim.locationZ;
    this.rotation.x = anim.rotationX;
    this.rotation.y = anim.rotationY;
    this.rotation.z = anim.rotationZ;
};

<commit_msg>Support shadows with MeshMultitextureMaterial<commit_after>// Copyright (c) 2011 Hewlett-Packard Development Company, L.P. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Build and fly through a 3D world using Three.js

var WebVfx = WebVfx || {};

WebVfx.ThreeWorld = function (width, height, nearPlane, farPlane, animationData, readyCallback) {
    var self = this;

    this.tracker = new WebVfx.Tracker(function () {
        readyCallback();
        delete self.tracker;
    });
    this.jsonLoader = new THREE.JSONLoader();

    var aspect = width / height;
    this.camera = new WebVfx.AnimatedCamera(aspect, nearPlane, farPlane,
                                            animationData);
    this.scene = new THREE.Scene();
    // Blender OBJ and three.js exporters rotate scene by -PI/2 in X,
    // undo that here so our camera animation data works.
    this.scene.rotation.x = Math.PI / 2;
    this.scene.updateMatrix();

    this.widescreen = aspect > (4 / 3);

    // Create and size canvas ourself, more efficient to size it up front
    var canvas = document.createElement("canvas");
    canvas.width = width;
    canvas.height = height;
    this.renderer = new THREE.WebGLRenderer({ canvas: canvas,
                                              antialias: true });
    // Need to enable this for our shader
    if (!this.renderer.context.getExtension("OES_standard_derivatives"))
        console.log("OES_standard_derivatives not supported");
    this.renderer.setViewport(0, 0, width, height);
    document.body.appendChild(canvas);

    // Treat page load as trackable
    if (document.readyState != "complete") {
        this.tracker.increment();
        window.addEventListener('load', function (event) {
            self.tracker.decrement();
        }, false);
    }
};

WebVfx.ThreeWorld.prototype = {
    // Must be called to start resource tracking
    startTracking: function () {
        this.tracker.start();
    },

    // Optional _callback_ will be passed the Mesh for additional configuring
    addJSONModel: function (url, material, callback) {
        var self = this;
        this.tracker.increment();
        this.jsonLoader.load({ model: url, callback: function (geometry) {
            var mesh = new THREE.Mesh(geometry, material);
            if (callback)
                callback(mesh);
            self.scene.addObject(mesh);
            self.tracker.decrement();
        } });
    },

    resize: function (width, height) {
        this.renderer.setSize(width, height);
        this.camera.aspect = width / height;
        this.camera.updateProjectionMatrix();
        this.widescreen = this.camera.aspect > (4 / 3);
    },

    render: function (time) {
        this.camera.setAnimationTime(time);
        this.renderer.render(this.scene, this.camera);
    }
};

///////////

WebVfx.loadImageTexture = function (url, tracker) {
    var image = new Image();
    var texture = new THREE.Texture(image);
    WebVfx.trackTextureImage(texture, tracker);
    image.src = url;
    return texture;
};

WebVfx.trackTextureImage = function (texture, tracker) {
    var image = texture.image;
    if (!(image instanceof Image) || image.complete) {
        texture.needsUpdate = true;
        return;
    }
    tracker.increment();
    image.addEventListener("load", function () {
        texture.needsUpdate = true;
        tracker.decrement();
    });
};

///////////

// _options_ includes:
// fontStyle - e.g. "30px Helvetica". If it uses a font loaded with @font-face,
//   then you must use a WebVfx.FontTracker and create the text Texture after
//   the font has loaded.
// textColor - Text color css spec.
// backgroundColor - Background color css spec.
// textAlign - "left", "right" or "center".
// textBaseline - "top", "middle" or "bottom"
WebVfx.createTextTexture = function (text, targetWidth, targetHeight, options) {
    var fontStyle = options.fontStyle;
    var textColor = options.textColor;
    var backgroundColor = options.backgroundColor;
    var textAlign = options.textAlign;
    var textBaseline = options.textBaseline;

    // Canvas context provides measureText(), but this only exposes width.
    // So apply same font style to span and measure it.
    // FYI span text looks much better than canvas text because span uses
    // subpixel antialiasing
    var span = document.createElement("span");
    span.style.visibility = "hidden";
    span.style.font = fontStyle;
    span.textContent = text;
    document.body.appendChild(span);
    var textWidth = span.offsetWidth;
    var textHeight = span.offsetHeight;
    document.body.removeChild(span);

    var scale = Math.min(targetWidth / textWidth, targetHeight / textHeight);

    var canvas = document.createElement("canvas");
    canvas.width = targetWidth;
    canvas.height = targetHeight;

    var context = canvas.getContext("2d");
    if (backgroundColor) {
        context.fillStyle = backgroundColor;
        context.fillRect(0, 0, targetWidth, targetHeight);
    }
    // Scale text to fit if too large
    var positionScale = 1;
    if (scale < 1) {
        context.scale(scale, scale);
        positionScale = 1 / scale;
    }
    context.font = fontStyle;
    context.fillStyle = textColor;

    var x = 0, y = 0;

    switch (textAlign) {
    case "right":
        x = targetWidth;
        break;
    case "center":
        x = targetWidth / 2;
        break;
    case "left":
    default:
        textAlign = "left";
        break;
    }
    context.textAlign = textAlign;

    switch (textBaseline) {
    case "middle":
        y = targetHeight / 2;
        break;
    case "bottom":
        y = targetHeight;
        break;
    case "top":
    default:
        textBaseline = "top";
        break;
    }
    context.textBaseline = textBaseline;

    context.fillText(text, x * positionScale, y * positionScale);

    var texture = new THREE.Texture(canvas);
    texture.needsUpdate = true;
    return texture;
}

///////////

WebVfx.updateVideoTexture = function (texture, name) {
    texture.image = webvfx.getImage(name).toImageData();
    texture.needsUpdate = true;
};

///////////

// Texture mesh by multiplying two textures.
// Texture regions outside of UV space can be colored.
// Parameters:
//  texture1 - THREE.Texture - uses main UV
//  texture2 - (optional) THREE.Texture - uses secondary UV
//  borderColor - (optional) THREE.Color - color of regions outside UV space.
//   Setting this also triggers antialiasing of the edges.
//  borderOpacity - float opacity of regions outside UV space (default 1.0)
WebVfx.MeshMultitextureMaterial = function (parameters) {
    var vertexShader = this.shaderLibrary['vertexShader'];
    var fragmentShader = this.shaderLibrary['fragmentShader'];
    var vertexPrefix = [];
    var fragmentPrefix = [];

    var uniforms = THREE.UniformsUtils.merge([THREE.UniformsLib["shadowmap"]]);
    uniforms.texture1 = { type: "t", value: 0, texture: parameters.texture1 };

    if (parameters.texture2) {
        uniforms.texture2 = { type: "t", value: 1, texture: parameters.texture2 };
        vertexPrefix.push("#define USE_TEXTURE2");
        fragmentPrefix.push("#define USE_TEXTURE2");
    }
    if (parameters.borderColor) {
        uniforms.borderColor = { type: "c", value: parameters.borderColor };
        uniforms.borderOpacity = { type: "f", value: parameters.borderOpacity || 1.0 };
        fragmentPrefix.push("#define USE_BORDERCOLOR");
    }

    if (vertexPrefix.length > 0)
        vertexShader = vertexPrefix.join("\n") + vertexShader;
    if (fragmentPrefix.length > 0)
        fragmentShader = fragmentPrefix.join("\n") + fragmentShader;

    THREE.MeshShaderMaterial.call(this, {
        uniforms: uniforms,
        fragmentShader: fragmentShader,
        vertexShader: vertexShader
    });
};

WebVfx.MeshMultitextureMaterial.prototype = new THREE.MeshShaderMaterial();
WebVfx.MeshMultitextureMaterial.prototype.constructor = WebVfx.MeshMultitextureMaterial;

WebVfx.MeshMultitextureMaterial.prototype.shaderLibrary = {
    vertexShader: [
        "",
        "varying vec2 vUv;",
        "#ifdef USE_TEXTURE2",
        "varying vec2 vUv2;",
        "#endif",
        THREE.ShaderChunk["shadowmap_pars_vertex"],
        "void main() {",
        "    vUv = uv;",
        "#ifdef USE_TEXTURE2",
        "    vUv2 = uv2;",
        "#endif",
        "    vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);",
        "    gl_Position = projectionMatrix * mvPosition;",
             THREE.ShaderChunk["shadowmap_vertex"],
        "}"
    ].join("\n"),
    fragmentShader: [
        "",
        "varying vec2 vUv;",
        "uniform sampler2D texture1;",

        "#ifdef USE_TEXTURE2",
        "varying vec2 vUv2;",
        "uniform sampler2D texture2;",
        "#endif",

        "#ifdef USE_BORDERCOLOR",
        "#extension GL_OES_standard_derivatives : enable",
        "uniform vec3 borderColor;",
        "uniform float borderOpacity;",
        "#endif",

        THREE.ShaderChunk["shadowmap_pars_fragment"],

        "#ifdef USE_BORDERCOLOR",
        "vec4 antialias(vec2 uv, vec2 fw, sampler2D texture, vec4 color) {",
        "    vec2 marginTL = -fw;",
        "    vec2 marginBR = 1.0 + fw;",
        //   // Completely outside the texture margins, use color
        "    if (uv.s <= marginTL.s || uv.s >= marginBR.s",
        "        || uv.t <= marginTL.t || uv.t >= marginBR.t)",
        "        return color;",
        //   // Completely inside the texture, use texture
        "    else if (uv.s >= 0.0 && uv.s <= 1.0 && uv.t >= 0.0 && uv.t <= 1.0)",
        "        return texture2D(texture, uv);",
        //   // Inside a margin - mix color and texture to antialias
        "    else {",
        //       // Amount of mix - 0.0 is all color, 1.0 is all texture
        "        float p = 0.0;",
        "        int c = 0;",
        "        if (uv.s < 0.0) {",
        "            p += smoothstep(marginTL.s, 0.0, uv.s);",
        "            c++;",
        "        }",
        "        else if (uv.s > 1.0) {",
        "            p += 1.0 - smoothstep(1.0, marginBR.s, uv.s);",
        "            c++;",
        "        }",
        "        if (uv.t < 0.0) {",
        "            p += smoothstep(marginTL.t, 0.0, uv.t);",
        "            c++;",
        "        }",
        "        else if (uv.t > 1.0) {",
        "            p += 1.0 - smoothstep(1.0, marginBR.t, uv.t);",
        "            c++;",
        "        }",
        "        return mix(color, texture2D(texture, uv), p / float(c));",
        "    }",
        "}",
        "#endif",

        "void main() {",
        "#ifdef USE_BORDERCOLOR",
        "    vec4 border = vec4(borderColor, borderOpacity);",
        "    gl_FragColor = antialias(vUv, fwidth(vUv), texture1, border);",
        "#else",
        "    gl_FragColor = texture2D(texture1, vUv);",
        "#endif",

        "#ifdef USE_TEXTURE2",
        "#ifdef USE_BORDERCOLOR",
        "    gl_FragColor = gl_FragColor * antialias(vUv2, fwidth(vUv2), texture2, border);",
        "#else",
        "    gl_FragColor = gl_FragColor * texture2D(texture2, vUv2);",
        "#endif",
        "#endif",

            THREE.ShaderChunk["shadowmap_fragment"],
        "}"
    ].join("\n")
};

///////////

// Set UV coords for given layer, for a single quad
WebVfx.setQuadUvs = function (mesh, layer, u1, v1, u2, v2, u3, v3, u4, v4) {
    var uvs = [new THREE.UV(u1, v1),
               new THREE.UV(u2, v2),
               new THREE.UV(u3, v3),
               new THREE.UV(u4, v4)];
    mesh.geometry.faceVertexUvs[layer] = [uvs];
}

// Map (scale/translate) UVs from _fromLayer_ to _toLayer_
// min/max specifies new UV coordinate space range.
WebVfx.mapUvs = function (mesh, fromLayer, toLayer, minU, minV, maxU, maxV) {
    var uvs = mesh.geometry.faceVertexUvs[fromLayer];
    var length = uvs.length;

    // Find UV space we are mapping from
    var fromMinU = Number.MAX_VALUE;
    var fromMaxU = Number.MIN_VALUE;
    var fromMinV = Number.MAX_VALUE;
    var fromMaxV = Number.MIN_VALUE;
    for (var i = 0; i < length; i++) {
        var faceUv = uvs[i];
        var faceUvLength = faceUv.length;
        for (var j = 0; j < faceUvLength; j++) {
            var uv = faceUv[j];
            fromMinU = Math.min(uv.u, fromMinU);
            fromMaxU = Math.max(uv.u, fromMaxU);
            fromMinV = Math.min(uv.v, fromMinV);
            fromMaxV = Math.max(uv.v, fromMaxV);
        }
    }

    var fromDistU = fromMaxU - fromMinU;
    var fromDistV = fromMaxV - fromMinV;
    var toDistU = maxU - minU;
    var toDistV = maxV - minV;

    var mappedUvs = new Array(length);
    for (var i = 0; i < length; i++) {
        var faceUv = uvs[i];
        var faceUvLength = faceUv.length;
        var mappedFaceUv = new Array(faceUvLength);
        mappedUvs[i] = mappedFaceUv;
        for (var j = 0; j < faceUvLength; j++) {
            var uv = faceUv[j];
            var u = minU + (((uv.u - fromMinU) / fromDistU) * toDistU);
            var v = minV + (((uv.v - fromMinV) / fromDistV) * toDistV);
            mappedFaceUv[j] = new THREE.UV(u, v);
        }
    }

    mesh.geometry.faceVertexUvs[toLayer] = mappedUvs;
}

///////////

WebVfx.AnimatedCamera = function (aspect, nearPlane, farPlane, animationData) {
    var anim = new WebVfx.Animation(animationData);
    this.animation = anim;
    var fov = anim.radians2degrees(anim.verticalFOV(aspect));
    THREE.Camera.call(this, fov, aspect, nearPlane, farPlane);
    this.useTarget = false;
    // Blender XYZ order is really ZYX
    this.eulerOrder = 'ZYX';
};

WebVfx.AnimatedCamera.prototype = new THREE.Camera();
WebVfx.AnimatedCamera.prototype.constructor = WebVfx.AnimatedCamera;

WebVfx.AnimatedCamera.prototype.setAnimationTime = function (time) {
    var anim = this.animation;
    anim.evaluateTime(time);
    this.position.x = anim.locationX;
    this.position.y = anim.locationY;
    this.position.z = anim.locationZ;
    this.rotation.x = anim.rotationX;
    this.rotation.y = anim.rotationY;
    this.rotation.z = anim.rotationZ;
};

<|endoftext|>


<commit_before>import flatten from 'flat';
import jsonexport from 'jsonexport';
import React, { Component } from 'react';
import { CSVLink } from 'react-csv';

class CSVExport extends Component {
	constructor(){
		super();

		this.exportFile = this.exportFile.bind(this);
	}

	convertFileType(data) {
		const options = {
			headers: this.props.columns.map((column) => (column.value)),
			rename: this.props.columns.map((column) => (column.label)),
		};

		jsonexport(data, options, (err,csv) => {
			if(err) {
				return console.log(err);
			}
			return csv;
		});
	}

	exportFile() {
		return this.reformatColumns(this.props.visibleItems);
	}

	reformatColumns(items) {
		const flatList = items.map((item) => flatten(item, { maxDepth: 2 }));

		// convert columns
		const reformattedList = flatList.map((item) => {
			let reformattedItem = {
				[item['budgetHours.column']]: item['budgetHours.value'],
				total: item['budgetHours.value'],
				feature: item.feature,
			};

			for (const property in item) {
				if(Array.isArray(item[property])) {
					reformattedItem[property] = item[property];
				}
			}

			return reformattedItem;
		});

		let concatObj = {};

		// combine on feature
		reformattedList.map((item) => {
      // Feature isn't already in the object
			if (typeof concatObj[item.feature] === 'undefined') {
				concatObj[item.feature] = item;
			} else {
        // Add to existing feature
				for (const property in item) {
					if(Array.isArray(item[property])) {
            concatObj[item.feature][property] = [
              ...concatObj[item.feature][property],
              ...item[property],
            ];
					} else if(typeof item[property] === 'number') {
            // Sum the numbers
						concatObj[item.feature][property] = concatObj[item.feature][property] + item[property] || item[property];
					}
				}
			}
		});

		// convert concatObj from properties to array elements
		let concatList = [];
		for (const element in concatObj) {
			concatList = [...concatList, concatObj[element]];
		}

		return concatList;
	}

	render() {

		return (

				<CSVLink
					data={this.exportFile()}
					headers={this.props.columns}
					filename={'Budget.csv'}
					className="btn btn-primary">
					Export to CSV
				</CSVLink>

		);
	}
}

CSVExport.defaultProps = {
	columns: [{
		key:'feature',
		value:'feature',
		label:'Page/Feature',
	},{
		key:'t&m',
		value:'t&m',
		label:'T&M',
	},{
		key:'Discovery',
		value:'Discovery',
		label:'Disc',
	},{
		key:'Design',
		value:'Design',
		label:'Design',
	},{
		key:'Dev',
		value:'Dev',
		label:'Dev',
	},{
		key:'Testing',
		value:'Testing',
		label:'Testing',
	},{
		key:'Remediation',
		value:'Remediation',
		label:'Remediation',
	},{
		key:'Deploy',
		value:'Deploy',
		label:'Deploy',
	},{
		key:'PM',
		value:'PM',
		label:'PM',
	},{
		key:'total',
		value:'total',
		label:'Total',
	},{
		key:'descriptions.budget',
		value:'descriptions.budget',
		label:'Description',
	},{
		key:'descriptions.assumptions',
		value:'descriptions.assumptions',
		label:'Assumptions',
	},{
		key:'descriptions.clientResponsibilities',
		value:'descriptions.clientResponsibilities',
		label:'Client Responsibilities',
	},{
		key:'descriptions.exclusions',
		value:'descriptions.exclusions',
		label:'Exclusions',
	},
	]
}

export default CSVExport;
<commit_msg>Simpifly item formatting<commit_after>import flatten from 'flat';
import jsonexport from 'jsonexport';
import React, { Component } from 'react';
import { CSVLink } from 'react-csv';

class CSVExport extends Component {
	constructor(){
		super();

		this.exportFile = this.exportFile.bind(this);
	}

	convertFileType(data) {
		const options = {
			headers: this.props.columns.map((column) => (column.value)),
			rename: this.props.columns.map((column) => (column.label)),
		};

		jsonexport(data, options, (err,csv) => {
			if(err) {
				return console.log(err);
			}
			return csv;
		});
	}

	exportFile() {
		return this.reformatColumns(this.props.visibleItems);
	}

	reformatColumns(items) {
		const flatList = items.map((item) => flatten(item, { maxDepth: 2 }));

		// convert columns
    const reformattedList = flatList.map((item) => ({
      ...item,
      // Put the hours in the right column
      [item['budgetHours.column']]: item['budgetHours.value'],
      total: item['budgetHours.value'],
    }));

		let concatObj = {};

		// combine on feature
		reformattedList.map((item) => {
      // Feature isn't already in the object
			if (typeof concatObj[item.feature] === 'undefined') {
				concatObj[item.feature] = item;
			} else {
        // Add to existing feature
				for (const property in item) {
					if(Array.isArray(item[property])) {
            concatObj[item.feature][property] = [
              ...concatObj[item.feature][property],
              ...item[property],
            ];
					} else if(typeof item[property] === 'number') {
            // Sum the numbers
						concatObj[item.feature][property] = concatObj[item.feature][property] + item[property] || item[property];
					}
				}
			}
		});

		// convert concatObj from properties to array elements
		let concatList = [];
		for (const element in concatObj) {
			concatList = [...concatList, concatObj[element]];
		}

		return concatList;
	}

	render() {

		return (

				<CSVLink
					data={this.exportFile()}
					headers={this.props.columns}
					filename={'Budget.csv'}
					className="btn btn-primary">
					Export to CSV
				</CSVLink>

		);
	}
}

CSVExport.defaultProps = {
	columns: [{
		key:'feature',
		value:'feature',
		label:'Page/Feature',
	},{
		key:'t&m',
		value:'t&m',
		label:'T&M',
	},{
		key:'Discovery',
		value:'Discovery',
		label:'Disc',
	},{
		key:'Design',
		value:'Design',
		label:'Design',
	},{
		key:'Dev',
		value:'Dev',
		label:'Dev',
	},{
		key:'Testing',
		value:'Testing',
		label:'Testing',
	},{
		key:'Remediation',
		value:'Remediation',
		label:'Remediation',
	},{
		key:'Deploy',
		value:'Deploy',
		label:'Deploy',
	},{
		key:'PM',
		value:'PM',
		label:'PM',
	},{
		key:'total',
		value:'total',
		label:'Total',
	},{
		key:'descriptions.budget',
		value:'descriptions.budget',
		label:'Description',
	},{
		key:'descriptions.assumptions',
		value:'descriptions.assumptions',
		label:'Assumptions',
	},{
		key:'descriptions.clientResponsibilities',
		value:'descriptions.clientResponsibilities',
		label:'Client Responsibilities',
	},{
		key:'descriptions.exclusions',
		value:'descriptions.exclusions',
		label:'Exclusions',
	},
	]
}

export default CSVExport;
<|endoftext|>