<commit_before>import core from 'coreApi';
import 'jasmine-jquery';
import FocusTests from './FocusTests';

describe('Editors', () => {
    describe('DocumentEditorView', () => {
        FocusTests.runFocusTests({
            initialize: () => {
                const model = new Backbone.Model({
                    value: [
                        {
                            id: 'document.1',
                            name: 'Document 1',
                            url: 'GetDocument/1'
                        }
                    ]
                });

                return new core.form.editors.DocumentEditor({
                    model,
                    key: 'value',
                    autocommit: true
                });
            },
            focusElement: '.js-file-button'
        });

        it('should initialize', () => {
            const model = new Backbone.Model({
                value: [
                    {
                        id: 'document.1',
                        name: 'Document 1',
                        url: 'GetDocument/1'
                    }
                ]
            });

            const view = new core.form.editors.DocumentEditor({
                model,
                key: 'value',
                autocommit: true
            });

            window.app
                .getView()
                .getRegion('contentRegion')
                .show(view);

            expect(true).toBe(true);
        });

        it('should initialize with value', () => {
            const model = new Backbone.Model({
                value: [
                    {
                        id: 'document.1',
                        name: 'Document 1',
                        url: 'GetDocument/1'
                    }
                ]
            });

            const view = new core.form.editors.DocumentEditor({
                model,
                key: 'value',
                autocommit: true
            });

            window.app
                .getView()
                .getRegion('contentRegion')
                .show(view);

            expect(view.getValue()).toEqual([
                {
                    id: 'document.1',
                    name: 'Document 1',
                    url: 'GetDocument/1'
                }
            ]);
        });

        it('should remove value on remove button press', () => {
            const model = new Backbone.Model({
                value: [
                    {
                        id: 'document.1',
                        name: 'Document 1',
                        url: 'GetDocument/1'
                    }
                ]
            });

            const view = new core.form.editors.DocumentEditor({
                model,
                key: 'value',
                autocommit: true
            });

            window.app
                .getView()
                .getRegion('contentRegion')
                .show(view);

            view.$('.document-list').trigger('mouseenter');

            document.getElementsByClassName('js-delete-button')[0].click();

            expect(view.getValue()).toEqual([]);
        });

        it('should not show remove button if deleteion not permitted', () => {
            const model = new Backbone.Model({
                value: [
                    {
                        id: 'document.1',
                        name: 'Document 1',
                        url: 'GetDocument/1'
                    }
                ]
            });

            const view = new core.form.editors.DocumentEditor({
                model,
                key: 'value',
                autocommit: true,
                allowDelete: false
            });

            window.app
                .getView()
                .getRegion('contentRegion')
                .show(view);

            view.$('.task-links__i').trigger('mouseenter');

            expect(document.getElementsByClassName('js-bubble-delete').length).toEqual(0);
        });

        it('should show revision on revion button click', done => {
            const model = new Backbone.Model({
                value: [
                    {
                        id: 'document.1',
                        name: 'Document 1',
                        url: 'GetDocument/1'
                    }
                ]
            });

            const view = new core.form.editors.DocumentEditor({
                model,
                key: 'value',
                autocommit: true,
                allowDelete: false,
                showRevision: true
            });

            window.app
                .getView()
                .getRegion('contentRegion')
                .show(view);

            view.$('.document-list').trigger('mouseenter');
            view.$('.js-revise-button-region').click();
            setTimeout(() => {
                expect(document.getElementsByClassName('js-revision-list').length).toEqual(1);
                done();
            }, 100);
        });

        it('change value after upload ', done => {
            const model = new Backbone.Model({
                value: [
                    {
                        id: 'document.1',
                        name: 'Document 1',
                        url: 'GetDocument/1'
                    }
                ]
            });

            const view = new core.form.editors.DocumentEditor({
                model,
                key: 'value',
                autocommit: true,
                allowDelete: false,
                showRevision: true
            });

            window.app
                .getView()
                .getRegion('contentRegion')
                .show(view);

            const file = new File([], 'testFile');
            view._uploadFiles([file]);
            setTimeout(() => {
                const value = view.getValue();
                expect(value).toEqual([
                    {
                        id: 'document.1',
                        name: 'Document 1',
                        url: 'GetDocument/1'
                    },
                    {
                        name: 'testFile',
                        extension: 'testFile',
                        streamId: 'testFile1',
                        url: value[1].url
                    }
                ]);
                done();
            }, 1000);
        });

        it('show add values after twice upload by default', done => {
            const model = new Backbone.Model({
                value: null
            });

            const view = new core.form.editors.DocumentEditor({
                model,
                key: 'value',
                autocommit: true,
                allowDelete: false,
                showRevision: true
            });

            window.app
                .getView()
                .getRegion('contentRegion')
                .show(view);

            const file1 = new File([], 'firstFile');
            const file2 = new File([], 'secondFile');
            view._uploadFiles([file1, file2]);
            setTimeout(() => {
                const value = view.getValue();
                expect(value).toEqual([
                    {
                        name: 'firstFile',
                        extension: 'firstFile',
                        streamId: 'firstFile1',
                        url: value[0].url
                    },
                    {
                        name: 'secondFile',
                        extension: 'secondFile',
                        streamId: 'secondFile2',
                        url: value[1].url
                    }
                ]);
                const file3 = new File([], 'thirdFile');
                view._uploadFiles([file3]);
                setTimeout(() => {
                    const newValue = view.getValue();
                    expect(view.getValue()).toEqual([
                        {
                            name: 'firstFile',
                            extension: 'firstFile',
                            streamId: 'firstFile1',
                            url: newValue[0].url
                        },
                        {
                            name: 'secondFile',
                            extension: 'secondFile',
                            streamId: 'secondFile2',
                            url: newValue[1].url
                        },
                        {
                            name: 'thirdFile',
                            extension: 'thirdFile',
                            streamId: 'thirdFile1',
                            url: newValue[2].url
                        }
                    ]);
                    done();
                }, 100);
            }, 100);
        });

        it('show should reset value after any update if multiple restricted', done => {
            const model = new Backbone.Model({
                value: null
            });

            const view = new core.form.editors.DocumentEditor({
                model,
                key: 'value',
                autocommit: true,
                allowDelete: false,
                showRevision: true,
                multiple: false
            });

            window.app
                .getView()
                .getRegion('contentRegion')
                .show(view);

            const file1 = new File([], 'firstFile');
            view._uploadFiles([file1, new File([], 'secondFile')]);
            setTimeout(() => {
                const value = view.getValue();
                expect(value).toEqual([
                    {
                        name: 'firstFile',
                        extension: 'firstFile',
                        streamId: 'firstFile1',
                        url: value[0].url
                    }
                ]);
                const file3 = new File([], 'thirdFile');
                view._uploadFiles([file3]);
                setTimeout(() => {
                    const newValue = view.getValue();
                    expect(view.getValue()).toEqual([
                        {
                            name: 'thirdFile',
                            extension: 'thirdFile',
                            streamId: 'thirdFile1',
                            url: newValue[0].url
                        }
                    ]);
                    done();
                }, 100);
            }, 100);
        });
    });
});
<commit_msg>Xit tests documents for build<commit_after>import core from 'coreApi';
import 'jasmine-jquery';
import FocusTests from './FocusTests';

describe('Editors', () => {
    describe('DocumentEditorView', () => {
        FocusTests.runFocusTests({
            initialize: () => {
                const model = new Backbone.Model({
                    value: [
                        {
                            id: 'document.1',
                            name: 'Document 1',
                            url: 'GetDocument/1'
                        }
                    ]
                });

                return new core.form.editors.DocumentEditor({
                    model,
                    key: 'value',
                    autocommit: true
                });
            },
            focusElement: '.js-file-button'
        });

        it('should initialize', () => {
            const model = new Backbone.Model({
                value: [
                    {
                        id: 'document.1',
                        name: 'Document 1',
                        url: 'GetDocument/1'
                    }
                ]
            });

            const view = new core.form.editors.DocumentEditor({
                model,
                key: 'value',
                autocommit: true
            });

            window.app
                .getView()
                .getRegion('contentRegion')
                .show(view);

            expect(true).toBe(true);
        });

        it('should initialize with value', () => {
            const model = new Backbone.Model({
                value: [
                    {
                        id: 'document.1',
                        name: 'Document 1',
                        url: 'GetDocument/1'
                    }
                ]
            });

            const view = new core.form.editors.DocumentEditor({
                model,
                key: 'value',
                autocommit: true
            });

            window.app
                .getView()
                .getRegion('contentRegion')
                .show(view);

            expect(view.getValue()).toEqual([
                {
                    id: 'document.1',
                    name: 'Document 1',
                    url: 'GetDocument/1'
                }
            ]);
        });

        xit('should remove value on remove button press', () => {
            const model = new Backbone.Model({
                value: [
                    {
                        id: 'document.1',
                        name: 'Document 1',
                        url: 'GetDocument/1'
                    }
                ]
            });

            const view = new core.form.editors.DocumentEditor({
                model,
                key: 'value',
                autocommit: true
            });

            window.app
                .getView()
                .getRegion('contentRegion')
                .show(view);

            view.$('.document-list').trigger('mouseenter');

            document.getElementsByClassName('js-delete-button')[0].click();

            expect(view.getValue()).toEqual([]);
        });

        it('should not show remove button if deleteion not permitted', () => {
            const model = new Backbone.Model({
                value: [
                    {
                        id: 'document.1',
                        name: 'Document 1',
                        url: 'GetDocument/1'
                    }
                ]
            });

            const view = new core.form.editors.DocumentEditor({
                model,
                key: 'value',
                autocommit: true,
                allowDelete: false
            });

            window.app
                .getView()
                .getRegion('contentRegion')
                .show(view);

            view.$('.task-links__i').trigger('mouseenter');

            expect(document.getElementsByClassName('js-bubble-delete').length).toEqual(0);
        });

        xit('should show revision on revion button click', done => {
            const model = new Backbone.Model({
                value: [
                    {
                        id: 'document.1',
                        name: 'Document 1',
                        url: 'GetDocument/1'
                    }
                ]
            });

            const view = new core.form.editors.DocumentEditor({
                model,
                key: 'value',
                autocommit: true,
                allowDelete: false,
                showRevision: true
            });

            window.app
                .getView()
                .getRegion('contentRegion')
                .show(view);

            view.$('.document-list').trigger('mouseenter');
            view.$('.js-revise-button-region').click();
            setTimeout(() => {
                expect(document.getElementsByClassName('js-revision-list').length).toEqual(1);
                done();
            }, 100);
        });

        it('change value after upload ', done => {
            const model = new Backbone.Model({
                value: [
                    {
                        id: 'document.1',
                        name: 'Document 1',
                        url: 'GetDocument/1'
                    }
                ]
            });

            const view = new core.form.editors.DocumentEditor({
                model,
                key: 'value',
                autocommit: true,
                allowDelete: false,
                showRevision: true
            });

            window.app
                .getView()
                .getRegion('contentRegion')
                .show(view);

            const file = new File([], 'testFile');
            view._uploadFiles([file]);
            setTimeout(() => {
                const value = view.getValue();
                expect(value).toEqual([
                    {
                        id: 'document.1',
                        name: 'Document 1',
                        url: 'GetDocument/1'
                    },
                    {
                        name: 'testFile',
                        extension: 'testFile',
                        streamId: 'testFile1',
                        url: value[1].url
                    }
                ]);
                done();
            }, 1000);
        });

        it('show add values after twice upload by default', done => {
            const model = new Backbone.Model({
                value: null
            });

            const view = new core.form.editors.DocumentEditor({
                model,
                key: 'value',
                autocommit: true,
                allowDelete: false,
                showRevision: true
            });

            window.app
                .getView()
                .getRegion('contentRegion')
                .show(view);

            const file1 = new File([], 'firstFile');
            const file2 = new File([], 'secondFile');
            view._uploadFiles([file1, file2]);
            setTimeout(() => {
                const value = view.getValue();
                expect(value).toEqual([
                    {
                        name: 'firstFile',
                        extension: 'firstFile',
                        streamId: 'firstFile1',
                        url: value[0].url
                    },
                    {
                        name: 'secondFile',
                        extension: 'secondFile',
                        streamId: 'secondFile2',
                        url: value[1].url
                    }
                ]);
                const file3 = new File([], 'thirdFile');
                view._uploadFiles([file3]);
                setTimeout(() => {
                    const newValue = view.getValue();
                    expect(view.getValue()).toEqual([
                        {
                            name: 'firstFile',
                            extension: 'firstFile',
                            streamId: 'firstFile1',
                            url: newValue[0].url
                        },
                        {
                            name: 'secondFile',
                            extension: 'secondFile',
                            streamId: 'secondFile2',
                            url: newValue[1].url
                        },
                        {
                            name: 'thirdFile',
                            extension: 'thirdFile',
                            streamId: 'thirdFile1',
                            url: newValue[2].url
                        }
                    ]);
                    done();
                }, 100);
            }, 100);
        });

        it('show should reset value after any update if multiple restricted', done => {
            const model = new Backbone.Model({
                value: null
            });

            const view = new core.form.editors.DocumentEditor({
                model,
                key: 'value',
                autocommit: true,
                allowDelete: false,
                showRevision: true,
                multiple: false
            });

            window.app
                .getView()
                .getRegion('contentRegion')
                .show(view);

            const file1 = new File([], 'firstFile');
            view._uploadFiles([file1, new File([], 'secondFile')]);
            setTimeout(() => {
                const value = view.getValue();
                expect(value).toEqual([
                    {
                        name: 'firstFile',
                        extension: 'firstFile',
                        streamId: 'firstFile1',
                        url: value[0].url
                    }
                ]);
                const file3 = new File([], 'thirdFile');
                view._uploadFiles([file3]);
                setTimeout(() => {
                    const newValue = view.getValue();
                    expect(view.getValue()).toEqual([
                        {
                            name: 'thirdFile',
                            extension: 'thirdFile',
                            streamId: 'thirdFile1',
                            url: newValue[0].url
                        }
                    ]);
                    done();
                }, 100);
            }, 100);
        });
    });
});
<|endoftext|>


<commit_before>// configuration object
var clockifyConfig = {
    whatToDo: function boing() {
        console.log("boing");
    },
    timeToWait: 1500
};

var clockify = function (theOptions) {
    var alreadyPlayed = false;

    if (theOptions === undefined || !theOptions.hasOwnProperty("whatToDo") || !theOptions.hasOwnProperty("timeToWait")) {
        console.log("Not enough information. Cannot continu.");
        return;
    }

    // repeat a function a certain number of times, with a certain interval
    function repeater(theFunction, numberOfTimes, timeToWait) {
        var i = 1;
        function t() {
            theFunction();
            if (i < numberOfTimes) {
                i++;
                setTimeout(t, timeToWait);
            }
        }
        t();
    }

    function createNewDate() {
        var now = new Date();
        var hour = now.getHours();
        var minute = now.getMinutes();

        if (hour > 12) {
            hour = hour - 12;
        } else {
            if (hour === 0) {
                hour = 12;
            }
        }
        return {
            hour: hour,
            minute: minute
        };
    }

    function playActualHour() {
        switch (createNewDate().hour) {
            case 1:
                repeater(theOptions.whatToDo, 1, theOptions.timeToWait);
                break;
            case 2:
                repeater(theOptions.whatToDo, 2, theOptions.timeToWait);
                break;
            case 3:
                repeater(theOptions.whatToDo, 3, theOptions.timeToWait);
                break;
            case 4:
                repeater(theOptions.whatToDo, 4, theOptions.timeToWait);
                break;
            case 5:
                repeater(theOptions.whatToDo, 5, theOptions.timeToWait);
                break;
            case 6:
                repeater(theOptions.whatToDo, 6, theOptions.timeToWait);
                break;
            case 7:
                repeater(theOptions.whatToDo, 7, theOptions.timeToWait);
                break;
            case 8:
                repeater(theOptions.whatToDo, 8, theOptions.timeToWait);
                break;
            case 9:
                repeater(theOptions.whatToDo, 9, theOptions.timeToWait);
                break;
            case 10:
                repeater(theOptions.whatToDo, 10, theOptions.timeToWait);
                break;
            case 11:
                repeater(theOptions.whatToDo, 11, theOptions.timeToWait);
                break;
            case 12:
                repeater(theOptions.whatToDo, 12, theOptions.timeToWait);
                break;
            default:
        }
    }

    function checkTime() {
        var actualMinute = createNewDate().minute;
        if ((actualMinute === 0) && (alreadyPlayed === false)) {
            playActualHour();
            alreadyPlayed = true;
        } else if (actualMinute !== 0) {
            alreadyPlayed = false;
        }
        setTimeout(checkTime, 10000); // every 10 seconds the system clock will be checked
    }
    checkTime();
};

clockify(clockifyConfig);<commit_msg>added explanation to config object<commit_after>// configuration object
var clockifyConfig = {
    whatToDo: function boing() { // write your own function
        console.log("boing");
    },
    timeToWait: 1500 // time between two function calls, in miliseconds
};

var clockify = function (theOptions) {
    var alreadyPlayed = false;

    if (theOptions === undefined || !theOptions.hasOwnProperty("whatToDo") || !theOptions.hasOwnProperty("timeToWait")) {
        console.log("Not enough information. Cannot continu.");
        return;
    }

    // repeat a function a certain number of times, with a certain interval
    function repeater(theFunction, numberOfTimes, timeToWait) {
        var i = 1;
        function t() {
            theFunction();
            if (i < numberOfTimes) {
                i++;
                setTimeout(t, timeToWait);
            }
        }
        t();
    }

    function createNewDate() {
        var now = new Date();
        var hour = now.getHours();
        var minute = now.getMinutes();

        if (hour > 12) {
            hour = hour - 12;
        } else {
            if (hour === 0) {
                hour = 12;
            }
        }
        return {
            hour: hour,
            minute: minute
        };
    }

    function playActualHour() {
        switch (createNewDate().hour) {
            case 1:
                repeater(theOptions.whatToDo, 1, theOptions.timeToWait);
                break;
            case 2:
                repeater(theOptions.whatToDo, 2, theOptions.timeToWait);
                break;
            case 3:
                repeater(theOptions.whatToDo, 3, theOptions.timeToWait);
                break;
            case 4:
                repeater(theOptions.whatToDo, 4, theOptions.timeToWait);
                break;
            case 5:
                repeater(theOptions.whatToDo, 5, theOptions.timeToWait);
                break;
            case 6:
                repeater(theOptions.whatToDo, 6, theOptions.timeToWait);
                break;
            case 7:
                repeater(theOptions.whatToDo, 7, theOptions.timeToWait);
                break;
            case 8:
                repeater(theOptions.whatToDo, 8, theOptions.timeToWait);
                break;
            case 9:
                repeater(theOptions.whatToDo, 9, theOptions.timeToWait);
                break;
            case 10:
                repeater(theOptions.whatToDo, 10, theOptions.timeToWait);
                break;
            case 11:
                repeater(theOptions.whatToDo, 11, theOptions.timeToWait);
                break;
            case 12:
                repeater(theOptions.whatToDo, 12, theOptions.timeToWait);
                break;
            default:
        }
    }

    function checkTime() {
        var actualMinute = createNewDate().minute;
        if ((actualMinute === 0) && (alreadyPlayed === false)) {
            playActualHour();
            alreadyPlayed = true;
        } else if (actualMinute !== 0) {
            alreadyPlayed = false;
        }
        setTimeout(checkTime, 10000); // every 10 seconds the system clock will be checked
    }
    checkTime();
};

clockify(clockifyConfig);<|endoftext|>


<commit_before>var text = ""; // Last text of sentence
var sugg = []; // suggestions for autocompletion of node names

$('#textanalyser').autocompleteTrigger({
    triggerStart: '#',
    triggerEnd: '',
    source: sugg
});

// TODO - hide this in a scope
function analyzeSentence(sentence, finalize)
{
    var ret = TextAnalyser2(sentence, finalize);
    for (var k in ret.sugg) {
        sugg.push(ret.sugg[k]);
    }
    switch (ret.state) {
    case ANALYSIS_NODE_START:
        $('.typeselection').css({top:window.innerHeight/2-115,left:window.innerWidth/2-325});
        $('.typeselection').html('

Use [TAB] key to pick a type

');
        break;
    case ANALYSIS_LINK:
        $('.typeselection').css('top', -300);
        $('.typeselection').css('left', 0);
        break;
    }
    //REINITIALISE GRAPH (DUMB BUT IT WORKS)
    graph.removeNodes("temp");
    graph.removeLinks("temp");
    for (var k in ret.nodes) {
        var n = ret.nodes[k];
        graph.addNode(n.id, n.type, n.state);
    }
    for (var k in ret.links) {
        var l = ret.links[k];
        graph.addLink(l.sourceId, l.targetId, l.name, l.state);
    }

    //UPDATE GRAPH ONCE
    graph.update();

    if (finalize) {
        $('.typeselection').css('top', -300);
        $('.typeselection').css('left', 0);
    }
}

$("#textanalyser").keypress(function(e) {
     if (graph.history !== undefined) {
         graph.history.record_keystrokes(KEYSTROKE_WHERE_TEXTANALYSIS, [e.which]);
     }
     if (e.which == 13) {
        if(!suggestionChange) {
            text = $('#textanalyser').val();
            $('#textanalyser').val("");
            analyzeSentence(text, true);
            typeStack = [];
        } else {
            suggestionChange = false;
        }
        return false;
    }

    if (e.which == 37) {//RIGHT
        $('body').scrollLeft(0);
        e.stopPropagation();
        return false;
    }
    if (e.which == 39) { //LEFT
        $('body').scrollLeft(0);
        e.stopPropagation();
        return false;
    }

});

$(document).keydown(function(e) {

    if (graph.history !== undefined) {
        graph.history.record_keystrokes(KEYSTROKE_WHERE_DOCUMENT, [e.KeyCode]);
    }
    if (e.keyCode == 9) {//TAB
        e.preventDefault();
        changeType("down", lastnode);
        return false;
    }

    if (e.keyCode == 37) {//UP
          $('html, body').scrollLeft(0);
    }
    if (e.keyCode == 39) {//DOWN
          $('html, body').scrollLeft(0);
    }

    if (e.keyCode == 38) {//UP
        suggestionChange = true;
    }
    if (e.keyCode == 40) {//DOWN
        suggestionChange = true;
    }

    if (e.keyCode == 9) {//TAB
        return false;
    }

});

function textSelect(inp, s, e) {
    e = e || s;
    if (inp.createTextRange) {
        var r = inp.createTextRange();
        r.collapse(true);
        r.moveEnd('character', e);
        r.moveStart('character', s);
        r.select();
    }else if(inp.setSelectionRange) {
        inp.focus();
        inp.setSelectionRange(s, e);
    }
}

function changeType(arg, id) {
    if(!id)id="new node";
    if (arg === 'up') {
        if (typeindex < 4) typeindex++;
        else typeindex = 0;
        graph.editType(id, null, nodetypes[typeindex]);
        $('.typeselection').html('

' + "Chosen Type: " + nodetypes[typeindex] + '

');
        graph.findCoordinates(lastnode,null);
    } else {
        if (typeindex > 0) typeindex--;
        else typeindex = 4;

        graph.editType(id, null, nodetypes[typeindex]);
        $('.typeselection').html('

' + "Chosen Type: " + nodetypes[typeindex] + '

');
        graph.findCoordinates(lastnode,null);

    }
    graph.updateGraph();
}

window.setInterval(function() {
    if ($('#textanalyser').val() != text) {

        if(text.length*8>500)$('#textanalyser').css('width',text.length*8+20);
        // text changed
        text = $('#textanalyser').val();
        analyzeSentence(text, false);
        suggestionChange=false;
    }
}, 5);

<commit_msg>textanalysis-ui: add note about 200 Hz text analysis being perhaps overzealous<commit_after>var text = ""; // Last text of sentence
var sugg = []; // suggestions for autocompletion of node names

$('#textanalyser').autocompleteTrigger({
    triggerStart: '#',
    triggerEnd: '',
    source: sugg
});

// TODO - hide this in a scope
function analyzeSentence(sentence, finalize)
{
    var ret = TextAnalyser2(sentence, finalize);
    for (var k in ret.sugg) {
        sugg.push(ret.sugg[k]);
    }
    switch (ret.state) {
    case ANALYSIS_NODE_START:
        $('.typeselection').css({top:window.innerHeight/2-115,left:window.innerWidth/2-325});
        $('.typeselection').html('

Use [TAB] key to pick a type

');
        break;
    case ANALYSIS_LINK:
        $('.typeselection').css('top', -300);
        $('.typeselection').css('left', 0);
        break;
    }
    //REINITIALISE GRAPH (DUMB BUT IT WORKS)
    graph.removeNodes("temp");
    graph.removeLinks("temp");
    for (var k in ret.nodes) {
        var n = ret.nodes[k];
        graph.addNode(n.id, n.type, n.state);
    }
    for (var k in ret.links) {
        var l = ret.links[k];
        graph.addLink(l.sourceId, l.targetId, l.name, l.state);
    }

    //UPDATE GRAPH ONCE
    graph.update();

    if (finalize) {
        $('.typeselection').css('top', -300);
        $('.typeselection').css('left', 0);
    }
}

$("#textanalyser").keypress(function(e) {
     if (graph.history !== undefined) {
         graph.history.record_keystrokes(KEYSTROKE_WHERE_TEXTANALYSIS, [e.which]);
     }
     if (e.which == 13) {
        if(!suggestionChange) {
            text = $('#textanalyser').val();
            $('#textanalyser').val("");
            analyzeSentence(text, true);
            typeStack = [];
        } else {
            suggestionChange = false;
        }
        return false;
    }

    if (e.which == 37) {//RIGHT
        $('body').scrollLeft(0);
        e.stopPropagation();
        return false;
    }
    if (e.which == 39) { //LEFT
        $('body').scrollLeft(0);
        e.stopPropagation();
        return false;
    }

});

$(document).keydown(function(e) {

    if (graph.history !== undefined) {
        graph.history.record_keystrokes(KEYSTROKE_WHERE_DOCUMENT, [e.KeyCode]);
    }
    if (e.keyCode == 9) {//TAB
        e.preventDefault();
        changeType("down", lastnode);
        return false;
    }

    if (e.keyCode == 37) {//UP
          $('html, body').scrollLeft(0);
    }
    if (e.keyCode == 39) {//DOWN
          $('html, body').scrollLeft(0);
    }

    if (e.keyCode == 38) {//UP
        suggestionChange = true;
    }
    if (e.keyCode == 40) {//DOWN
        suggestionChange = true;
    }

    if (e.keyCode == 9) {//TAB
        return false;
    }

});

function textSelect(inp, s, e) {
    e = e || s;
    if (inp.createTextRange) {
        var r = inp.createTextRange();
        r.collapse(true);
        r.moveEnd('character', e);
        r.moveStart('character', s);
        r.select();
    }else if(inp.setSelectionRange) {
        inp.focus();
        inp.setSelectionRange(s, e);
    }
}

function changeType(arg, id) {
    if(!id)id="new node";
    if (arg === 'up') {
        if (typeindex < 4) typeindex++;
        else typeindex = 0;
        graph.editType(id, null, nodetypes[typeindex]);
        $('.typeselection').html('

' + "Chosen Type: " + nodetypes[typeindex] + '

');
        graph.findCoordinates(lastnode,null);
    } else {
        if (typeindex > 0) typeindex--;
        else typeindex = 4;

        graph.editType(id, null, nodetypes[typeindex]);
        $('.typeselection').html('

' + "Chosen Type: " + nodetypes[typeindex] + '

');
        graph.findCoordinates(lastnode,null);

    }
    graph.updateGraph();
}

/* TODO: don't use interval by default but only if keys are comming to fast (but still - 5 ms??) */
window.setInterval(function() {
    if ($('#textanalyser').val() != text) {

        if(text.length*8 > 500)$('#textanalyser').css('width',text.length*8+20);
        // text changed
        text = $('#textanalyser').val();
        analyzeSentence(text, false);
        suggestionChange = false;
    }
}, 5);

<|endoftext|>


<commit_before>var gulp = require('gulp'),
  gutil = require('gulp-util'),
  clean = require('gulp-clean'),
  header = require('gulp-header'),
  rename = require('gulp-rename'),
  uglify = require('gulp-uglify'),
  stylus = require('gulp-stylus'),
  autoprefixer = require('gulp-autoprefixer'),
  csso = require('gulp-csso'),
  jade = require('gulp-jade'),
  connect = require('gulp-connect'),
  plumber = require('gulp-plumber'),
  opn = require('opn'),
  pkg = require('./package.json'),
  browserify = require('gulp-browserify'),
  through = require('through'),
  path = require('path'),
  ghpages = require('gh-pages'),
  template = require('lodash').template,
  isDemo = process.argv.indexOf('demo') > 0;

gulp.task('default', ['clean', 'compile']);
gulp.task('demo', ['compile', 'watch', 'connect']);
gulp.task('compile', ['compile:lib', 'compile:demo']);
gulp.task('compile:lib', ['stylus', 'browserify:lib']);
gulp.task('compile:demo', ['jade', 'browserify:demo']);

gulp.task('watch', function() {
  gulp.watch('lib/*', ['compile:lib', 'browserify:demo']);
  gulp.watch('demo/src/*.jade', ['jade']);
  gulp.watch('demo/src/**/*.js', ['browserify:demo']);
});

gulp.task('clean', function() {
  return gulp.src(['dist', 'lib/tmp'], { read: false })
    .pipe(clean());
});

gulp.task('stylus', function() {
  return gulp.src('lib/theme.styl')
    .pipe(isDemo ? plumber() : through())
    .pipe(stylus({
      'include css': true,
      'paths': ['./node_modules']
    }))
    .pipe(autoprefixer('last 2 versions'))
    .pipe(csso())
    .pipe(gulp.dest('lib/tmp'));
});

gulp.task('browserify', ['browserify:lib', 'browserify:demo']);

gulp.task('browserify:lib', ['stylus'], function() {
  return gulp.src('lib/<%= themeFullName %>.js')
    .pipe(isDemo ? plumber() : through())
    .pipe(browserify({ transform: ['brfs'], standalone: 'bespoke.themes.<%= themeNameCamelized %>' }))
    .pipe(header(template([
      '/*!',
      ' * <%%= name %> v<%%= version %>',
      ' *',
      ' * Copyright <%%= new Date().getFullYear() %>, <%%= author.name %>',
      ' * This content is released under the <%%= licenses[0].type %> license',
      ' * <%%= licenses[0].url %>',
      ' */\n\n'
    ].join('\n'), pkg)))
    .pipe(gulp.dest('dist'))
    .pipe(rename('<%= themeFullName %>.min.js'))
    .pipe(uglify())
    .pipe(header(template([
      '/*! <%%= name %> v<%%= version %> ',
      '© <%%= new Date().getFullYear() %> <%%= author.name %>, ',
      '<%%= licenses[0].type %> License */\n'
    ].join(''), pkg)))
    .pipe(gulp.dest('dist'));
});

gulp.task('browserify:demo', function() {
  return gulp.src('demo/src/scripts/main.js')
    .pipe(isDemo ? plumber() : through())
    .pipe(browserify({ transform: ['brfs'] }))
    .pipe(rename('build.js'))
    .pipe(gulp.dest('demo/dist/build'))
    .pipe(connect.reload());
});

gulp.task('jade', function() {
  return gulp.src('demo/src/index.jade')
    .pipe(isDemo ? plumber() : through())
    .pipe(jade({ pretty: true }))
    .pipe(gulp.dest('demo/dist'))
    .pipe(connect.reload());
});

gulp.task('connect', ['compile'], function(done) {
  connect.server({
    root: 'demo/dist',
    livereload: true
  });

  opn('http://localhost:8080', done);
});

gulp.task('deploy', ['compile:demo'], function(done) {
  ghpages.publish(path.join(__dirname, 'demo/dist'), { logger: gutil.log }, done);
});
<commit_msg>Fix clean race condition, add more clean tasks<commit_after>var gulp = require('gulp'),
  gutil = require('gulp-util'),
  clean = require('gulp-clean'),
  header = require('gulp-header'),
  rename = require('gulp-rename'),
  uglify = require('gulp-uglify'),
  stylus = require('gulp-stylus'),
  autoprefixer = require('gulp-autoprefixer'),
  csso = require('gulp-csso'),
  jade = require('gulp-jade'),
  connect = require('gulp-connect'),
  plumber = require('gulp-plumber'),
  opn = require('opn'),
  pkg = require('./package.json'),
  browserify = require('gulp-browserify'),
  through = require('through'),
  path = require('path'),
  ghpages = require('gh-pages'),
  template = require('lodash').template,
  isDemo = process.argv.indexOf('demo') > 0;

gulp.task('default', ['clean', 'compile']);
gulp.task('demo', ['compile', 'watch', 'connect']);
gulp.task('compile', ['compile:lib', 'compile:demo']);
gulp.task('compile:lib', ['stylus', 'browserify:lib']);
gulp.task('compile:demo', ['jade', 'browserify:demo']);

gulp.task('watch', function() {
  gulp.watch('lib/*', ['compile:lib', 'browserify:demo']);
  gulp.watch('demo/src/*.jade', ['jade']);
  gulp.watch('demo/src/**/*.js', ['browserify:demo']);
});

gulp.task('clean', ['clean:browserify', 'clean:stylus', 'clean:jade']);
gulp.task('clean:browserify', ['clean:browserify:lib', 'clean:browserify:demo']);

gulp.task('clean:browserify:lib', function() {
  return gulp.src(['dist'], { read: false })
    .pipe(clean());
});

gulp.task('clean:browserify:demo', function() {
  return gulp.src(['demo/dist/build'], { read: false })
    .pipe(clean());
});

gulp.task('clean:stylus', function() {
  return gulp.src(['lib/tmp'], { read: false })
    .pipe(clean());
});

gulp.task('clean:jade', function() {
  return gulp.src(['demo/dist/index.html'], { read: false })
    .pipe(clean());
});

gulp.task('stylus', ['clean:stylus'], function() {
  return gulp.src('lib/theme.styl')
    .pipe(isDemo ? plumber() : through())
    .pipe(stylus({
      'include css': true,
      'paths': ['./node_modules']
    }))
    .pipe(autoprefixer('last 2 versions'))
    .pipe(csso())
    .pipe(gulp.dest('lib/tmp'));
});

gulp.task('browserify', ['browserify:lib', 'browserify:demo']);

gulp.task('browserify:lib', ['clean:browserify:lib', 'stylus'], function() {
  return gulp.src('lib/<%= themeFullName %>.js')
    .pipe(isDemo ? plumber() : through())
    .pipe(browserify({ transform: ['brfs'], standalone: 'bespoke.themes.<%= themeNameCamelized %>' }))
    .pipe(header(template([
      '/*!',
      ' * <%%= name %> v<%%= version %>',
      ' *',
      ' * Copyright <%%= new Date().getFullYear() %>, <%%= author.name %>',
      ' * This content is released under the <%%= licenses[0].type %> license',
      ' * <%%= licenses[0].url %>',
      ' */\n\n'
    ].join('\n'), pkg)))
    .pipe(gulp.dest('dist'))
    .pipe(rename('<%= themeFullName %>.min.js'))
    .pipe(uglify())
    .pipe(header(template([
      '/*! <%%= name %> v<%%= version %> ',
      '© <%%= new Date().getFullYear() %> <%%= author.name %>, ',
      '<%%= licenses[0].type %> License */\n'
    ].join(''), pkg)))
    .pipe(gulp.dest('dist'));
});

gulp.task('browserify:demo', ['clean:browserify:demo'], function() {
  return gulp.src('demo/src/scripts/main.js')
    .pipe(isDemo ? plumber() : through())
    .pipe(browserify({ transform: ['brfs'] }))
    .pipe(rename('build.js'))
    .pipe(gulp.dest('demo/dist/build'))
    .pipe(connect.reload());
});

gulp.task('jade', ['clean:jade'], function() {
  return gulp.src('demo/src/index.jade')
    .pipe(isDemo ? plumber() : through())
    .pipe(jade({ pretty: true }))
    .pipe(gulp.dest('demo/dist'))
    .pipe(connect.reload());
});

gulp.task('connect', ['compile'], function(done) {
  connect.server({
    root: 'demo/dist',
    livereload: true
  });

  opn('http://localhost:8080', done);
});

gulp.task('deploy', ['compile:demo'], function(done) {
  ghpages.publish(path.join(__dirname, 'demo/dist'), { logger: gutil.log }, done);
});
<|endoftext|>


<commit_before>
function submitTestRequest() {
    axios.get('http://localhost:3000/cases')
      .then(function(response) {
        console.log(response);
      })
      .catch(function(error) {
        console.log(error);
      });
}

function getSpreadsheet(){
  axios.get('http://localhost:3000/export').then(function(response) {
    console.log(response);
  })
  .catch(function(error){
    console.log(error);
  })
}

// https://stackoverflow.com/questions/6974684/how-to-send-formdata-objects-with-ajax-requests-in-jquery

$("#upload").on("change", () => {
  var formData = new FormData();
  formData.append("file", ($("#upload"))[0].files[0]);
  var filename = ($("#upload"))[0].files[0].name;
  $.ajax({
    url: 'http://localhost:3000/upload',
    data: formData,
    processData: false,
    contentType: false,
    crossDomain: true, // Added
    type: 'POST',
    success: function(data){
      alert(data);
    }
  });
  // request.post({
  //   url: 'http:localhost:3000/upload',
  //   formData: formData
  // }, function (err, httpResponse, body){
  //   if (err) {
  //     return console.error('upload failed:', err);
  //   }
  //   console.log('Upload successful!  Server responded with: ', body);
  // });
});
<commit_msg>Playing around with request<commit_after>
function submitTestRequest() {
    axios.get('http://localhost:3000/cases')
      .then(function(userResponse) {
        axios.get('http://localhost:3000/users')
          .then(function(caseResponse) {
            console.log(userResponse, caseResponse, window);
          })
      })
      .catch(function(error) {
        console.log(error);
      });
}

function getSpreadsheet(){
  axios.get('http://localhost:3000/export').then(function(response) {
    console.log(response);
  })
  .catch(function(error){
    console.log(error);
  })
}

// https://stackoverflow.com/questions/6974684/how-to-send-formdata-objects-with-ajax-requests-in-jquery

$("#upload").on("change", () => {
  var formData = new FormData();
  formData.append("file", ($("#upload"))[0].files[0]);
  var filename = ($("#upload"))[0].files[0].name;
  $.ajax({
    url: 'http://localhost:3000/upload',
    data: formData,
    processData: false,
    contentType: false,
    crossDomain: true, // Added
    type: 'POST',
    success: function(data){
      alert(data);
    }
  });
  // request.post({
  //   url: 'http:localhost:3000/upload',
  //   formData: formData
  // }, function (err, httpResponse, body){
  //   if (err) {
  //     return console.error('upload failed:', err);
  //   }
  //   console.log('Upload successful!  Server responded with: ', body);
  // });
});
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * Logology V{{{VERSION}}}
 * Author: {{{AUTHOR.NAME}}} <{{{AUTHOR.EMAIL}}}> <{{{AUTHOR.SITE}}}>
 *
 * This is a very simple demonstration of using gulp + ES6; it obviously
 * doesn't do anything resembling the goal of the app yet.
 *
 *****************************************************************************/

/*globals MobileAccessibility, setImmediate*/

import "babel/polyfill";
import h from "yasmf-h";
import Emitter from "yasmf-emitter";
import GCS from "../lib/grandCentralStation";
import SoftKeyboard from "../lib/SoftKeyboard";
import L from "./localization/localization";

import Theme from "../lib/Theme";
import ThemeManager from "../lib/ThemeManager";

import NavigationViewController from "../lib/NavigationViewController.js";

import Settings from "./models/Settings";
import Dictionaries from "./models/Dictionaries";
import StarterDictionary from "./models/StarterDictionary";

/*
function simpleAlert() {
    let outerDiv = document.createElement("div"),
        innerDiv = document.createElement("div"),
        titleEl  = document.createElement("h1"),
        messageEl =  document.createElement("p"),
        buttonEl = document.createElement("button"),
        mainWindow = document.getElementById("mainWindow");
    outerDiv.setAttribute("is", "y-alert-container");
    innerDiv.setAttribute("is", "y-alert-dialog");
    titleEl.textContent = "Important!";
    messageEl.textContent = "This is an important message. Close this by tapping OK.";
    buttonEl.textContent = "OK";

    // accessibility
    innerDiv.setAttribute("role", "alertdialog");
    messageEl.setAttribute("role", "alert");

    // create the dom structure
    outerDiv.appendChild(innerDiv);
    innerDiv.appendChild(titleEl);
    innerDiv.appendChild(messageEl);
    innerDiv.appendChild(buttonEl);

    document.body.appendChild(outerDiv);
    setTimeout(function () {
      outerDiv.classList.add("visible");
      mainWindow.setAttribute("aria-hidden", true);
      buttonEl.focus();
    }, 0);

    buttonEl.addEventListener("click", function() {
        outerDiv.classList.remove("visible");
        setTimeout(function() {
          mainWindow.removeAttribute("aria-hidden");
          document.body.removeChild(outerDiv);
        }, 400);
    }, false);
}
*/

import SearchViewController from "./controllers/SearchViewController";

class App extends Emitter {
    constructor() {
        super();
        //document.addEventListener("deviceready", this.start.bind(this), false);
        document.addEventListener("DOMContentLoaded", this.start.bind(this), false);
        this.GCS = GCS;
        GCS.on("APP:startupFailure", this.onStartupFailure, this);
    }

    onStartupFailure(sender, notice, err) {
        console.log(`Startup failure ${err}`);
    }

    async start() {

//        try {

            // zoom our text for accessibility
            if (typeof MobileAccessibility !== "undefined") {
                MobileAccessibility.usePreferredTextZoom(true);
            }

            // load localization information
            let locale = await L.loadLocale();
            this.locale = locale;
            this.L = L;
            L.loadTranslations(require("./localization/root/messages"));

            // load theme
            this.theme = new Theme();
            this.themeManager = new ThemeManager();
            this.themeManager.currentTheme = this.theme;

            // load settings
            this.settings = new Settings();

            // create dictionaries list
            this.dictionaries = new Dictionaries();
            this.dictionaries.addDictionary(StarterDictionary);

            this.searchViewController = new SearchViewController({model: new StarterDictionary()});
            this.searchViewController2 = new SearchViewController({model: new StarterDictionary()});
            //this.searchViewController.renderElement = document.getElementById("mainWindow");

            this.navigationViewController = new NavigationViewController({subviews: [this.searchViewController],
                                                                          themeManager: this.themeManager,
                                                                          renderElement: document.getElementById("mainWindow")});

            // tell everyone that the app has started
            GCS.emit("APP:started");
            this.emit("started");
 /*       } catch (err) {
            GCS.emit("APP:startupFailure", err);
            this.emit("startupFailure", err);
        }*/

        //document.querySelector("[is='y-menu-glyph']").addEventListener("click", simpleAlert, false);
        this.softKeyboard = new SoftKeyboard({selectors: [".ui-scroll-container", "[is='y-scroll-container']", "y-scroll-container"]});
    }
}

let app = new App();
export default app;
<commit_msg>disable dom merging; our target event handling doesn't work with it atm<commit_after>/*****************************************************************************
 *
 * Logology V{{{VERSION}}}
 * Author: {{{AUTHOR.NAME}}} <{{{AUTHOR.EMAIL}}}> <{{{AUTHOR.SITE}}}>
 *
 * This is a very simple demonstration of using gulp + ES6; it obviously
 * doesn't do anything resembling the goal of the app yet.
 *
 *****************************************************************************/

/*globals MobileAccessibility, setImmediate*/

import "babel/polyfill";
import h from "yasmf-h";

//h.useDomMerging = true;

import Emitter from "yasmf-emitter";
import GCS from "../lib/grandCentralStation";
import SoftKeyboard from "../lib/SoftKeyboard";
import L from "./localization/localization";

import Theme from "../lib/Theme";
import ThemeManager from "../lib/ThemeManager";

import NavigationViewController from "../lib/NavigationViewController.js";

import Settings from "./models/Settings";
import Dictionaries from "./models/Dictionaries";
import StarterDictionary from "./models/StarterDictionary";

/*
function simpleAlert() {
    let outerDiv = document.createElement("div"),
        innerDiv = document.createElement("div"),
        titleEl  = document.createElement("h1"),
        messageEl =  document.createElement("p"),
        buttonEl = document.createElement("button"),
        mainWindow = document.getElementById("mainWindow");
    outerDiv.setAttribute("is", "y-alert-container");
    innerDiv.setAttribute("is", "y-alert-dialog");
    titleEl.textContent = "Important!";
    messageEl.textContent = "This is an important message. Close this by tapping OK.";
    buttonEl.textContent = "OK";

    // accessibility
    innerDiv.setAttribute("role", "alertdialog");
    messageEl.setAttribute("role", "alert");

    // create the dom structure
    outerDiv.appendChild(innerDiv);
    innerDiv.appendChild(titleEl);
    innerDiv.appendChild(messageEl);
    innerDiv.appendChild(buttonEl);

    document.body.appendChild(outerDiv);
    setTimeout(function () {
      outerDiv.classList.add("visible");
      mainWindow.setAttribute("aria-hidden", true);
      buttonEl.focus();
    }, 0);

    buttonEl.addEventListener("click", function() {
        outerDiv.classList.remove("visible");
        setTimeout(function() {
          mainWindow.removeAttribute("aria-hidden");
          document.body.removeChild(outerDiv);
        }, 400);
    }, false);
}
*/

import SearchViewController from "./controllers/SearchViewController";

class App extends Emitter {
    constructor() {
        super();
        //document.addEventListener("deviceready", this.start.bind(this), false);
        document.addEventListener("DOMContentLoaded", this.start.bind(this), false);
        this.GCS = GCS;
        GCS.on("APP:startupFailure", this.onStartupFailure, this);
    }

    onStartupFailure(sender, notice, err) {
        console.log(`Startup failure ${err}`);
    }

    async start() {

//        try {

            // zoom our text for accessibility
            if (typeof MobileAccessibility !== "undefined") {
                MobileAccessibility.usePreferredTextZoom(true);
            }

            // load localization information
            let locale = await L.loadLocale();
            this.locale = locale;
            this.L = L;
            L.loadTranslations(require("./localization/root/messages"));

            // load theme
            this.theme = new Theme();
            this.themeManager = new ThemeManager();
            this.themeManager.currentTheme = this.theme;

            // load settings
            this.settings = new Settings();

            // create dictionaries list
            this.dictionaries = new Dictionaries();
            this.dictionaries.addDictionary(StarterDictionary);

            this.searchViewController = new SearchViewController({model: new StarterDictionary()});
            this.searchViewController2 = new SearchViewController({model: new StarterDictionary()});
            //this.searchViewController.renderElement = document.getElementById("mainWindow");

            this.navigationViewController = new NavigationViewController({subviews: [this.searchViewController],
                                                                          themeManager: this.themeManager,
                                                                          renderElement: document.getElementById("mainWindow")});

            // tell everyone that the app has started
            GCS.emit("APP:started");
            this.emit("started");
 /*       } catch (err) {
            GCS.emit("APP:startupFailure", err);
            this.emit("startupFailure", err);
        }*/

        //document.querySelector("[is='y-menu-glyph']").addEventListener("click", simpleAlert, false);
        this.softKeyboard = new SoftKeyboard({selectors: [".ui-scroll-container", "[is='y-scroll-container']", "y-scroll-container"]});
    }
}

let app = new App();
export default app;
<|endoftext|>


<commit_before>import React from 'react';

import Analyzer from 'parser/core/Analyzer';
import SPELLS from 'common/SPELLS';
import SpellIcon from 'common/SpellIcon';
import SpellLink from 'common/SpellLink';
import { formatPercentage } from 'common/format';
import TalentStatisticBox, { STATISTIC_ORDER } from 'interface/others/TalentStatisticBox';
import EnemyInstances, { encodeTargetString } from 'parser/shared/modules/EnemyInstances';

const DAMAGE_BUFFER = 250;

class GlacialSpike extends Analyzer {
  static dependencies = {
    enemies: EnemyInstances,
  };

  constructor(...args) {
    super(...args);
    this.active = this.selectedCombatant.hasTalent(SPELLS.GLACIAL_SPIKE_TALENT.id);
    this.hasEbonbolt = this.selectedCombatant.hasTalent(SPELLS.EBONBOLT_TALENT.id);
    this.hasSplittingIce = this.selectedCombatant.hasTalent(SPELLS.SPLITTING_ICE_TALENT.id);
  }

  goodCasts = 0;
  totalCasts = 0;
  damageTimestamp = 0;

  on_byPlayer_damage(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.GLACIAL_SPIKE_DAMAGE.id) {
      return;
    }

    const damageTarget = encodeTargetString(event.targetID, event.targetInstance);
    const enemy = this.enemies.getEntity(event);
    if (!enemy) {
      return;
    }

    if (this.castTarget === damageTarget) {
      this.totalCasts += 1;
    }

    //It is considered a good use of Glacial Spike if either Glacial Spike lands into Winter's Chill (they used a Brain Freeze Proc with it) or the Glacial Spike cleaved and hit a second target.
    if (this.castTarget === damageTarget && enemy.hasBuff(SPELLS.WINTERS_CHILL.id)) {
      this.goodCasts += 1;
      this.damageTimestamp = event.timestamp;
    } else if (this.hasSplittingIce && this.castTarget !== damageTarget && event.timestamp - this.damageTimestamp < DAMAGE_BUFFER) {
      this.goodCasts += 1;
    }
  }

  on_byPlayer_cast(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.GLACIAL_SPIKE_TALENT.id) {
      return;
    }

    if(event.targetID) {
      this.castTarget = encodeTargetString(event.targetID, event.targetInstance);
    }
  }

  get utilPercentage() {
    return (this.goodCasts / this.totalCasts) || 0;
  }

  get badCasts() {
    return this.totalCasts - this.goodCasts;
  }

  get utilSuggestionThresholds() {
    return {
      actual: this.utilPercentage,
      isLessThan: {
        minor: 1,
        average: 0.8,
      },
      style: 'percentage',
    };
  }

  suggestions(when) {
    when(this.utilSuggestionThresholds)
      .addSuggestion((suggest, actual, recommended) => {
        return suggest(<>You misused <SpellLink id={SPELLS.GLACIAL_SPIKE_TALENT.id} /> {this.badCasts} times. In order to get the most out of Glacial Spike, you should only cast it if you have a <SpellLink id={SPELLS.BRAIN_FREEZE.id} /> proc to cast alongside it (Glacial Spike > Flurry > Ice Lance) {this.hasSplittingIce ? ' or if Glacial Spike will cleave to a second target (If you have Splitting Ice talented).' : ''} If you are consistently spending a long time fishing for a Brain Freeze Proc, {this.hasEbonbolt ? 'then hold Ebonbolt to generate a proc when you need it.' : 'then consider taking Ebonbolt and not casting it unless you need a Brain Freeze Proc for Glacial Spike.'}</>)
          .icon(SPELLS.GLACIAL_SPIKE_TALENT.icon)
          .actual(`${formatPercentage(this.utilPercentage, 1)}% utilization`)
          .recommended(`${formatPercentage(recommended, 1)}% is recommended`);
      });
  }
  statistic() {
    return (
      <TalentStatisticBox
        position={STATISTIC_ORDER.CORE(90)}
        icon={<SpellIcon id={SPELLS.GLACIAL_SPIKE_TALENT.id} />}
        value={`${formatPercentage(this.utilPercentage, 0)} %`}
        label="Glacial Spike Utilization"
        tooltip={`There are two situations where it is acceptable to use your Glacial Spike

You have a Brain Freeze Proc (Glacial Spike > Flurry > Ice Lance)

You do not have Brain Freeze, but Glacial Spike will cleave (If Splitting Ice is talented)

`}
      />
    );
  }
}

export default GlacialSpike;
<commit_msg>Rewrote glacial spike module<commit_after>import React from 'react';

import Analyzer from 'parser/core/Analyzer';
import SPELLS from 'common/SPELLS';
import SpellIcon from 'common/SpellIcon';
import SpellLink from 'common/SpellLink';
import { formatPercentage } from 'common/format';
import TalentStatisticBox, { STATISTIC_ORDER } from 'interface/others/TalentStatisticBox';
import EnemyInstances, { encodeTargetString } from 'parser/shared/modules/EnemyInstances';
import { SHATTER_DEBUFFS } from '../../constants';

class GlacialSpike extends Analyzer {
  static dependencies = {
    enemies: EnemyInstances,
  };

  lastCastEvent = null;
  lastCastDidDamage = false;
  goodCasts = 0;
  totalCasts = 0;

  constructor(...args) {
    super(...args);
    this.active = this.selectedCombatant.hasTalent(SPELLS.GLACIAL_SPIKE_TALENT.id);
    this.hasSplittingIce = this.selectedCombatant.hasTalent(SPELLS.SPLITTING_ICE_TALENT.id);
  }

  on_byPlayer_damage(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.GLACIAL_SPIKE_DAMAGE.id) {
      return;
    }

    if (this.lastCastEvent === null) {
      return;
    }

    this.lastCastDidDamage = true;

    // Check if second target was hit via Splitting Ice
    const castTarget = encodeTargetString(this.lastCastEvent.targetID, this.lastCastEvent.targetInstance);
    const damageTarget = encodeTargetString(event.targetID, event.targetInstance);
    if (castTarget !== damageTarget) {
      this.goodCasts += 1;
      this.lastCastEvent = null;
      return;
    }

    // Check if the target had a shatter effect on them
    const enemy = this.enemies.getEntity(event);
    if (enemy && SHATTER_DEBUFFS.some(effect => enemy.hasBuff(effect, event.timestamp))) {
      this.goodCasts += 1;
      this.lastCastEvent = null;
    }
  }

  on_byPlayer_cast(event) {
    const spellId = event.ability.guid;
    if (spellId !== SPELLS.GLACIAL_SPIKE_TALENT.id) {
      return;
    }
    this.invalidateCast();
    this.totalCasts += 1;
    this.lastCastEvent = event;
    this.lastCastDidDamage = false;
  }

  on_finished() {
    this.invalidateCast();
  }

  invalidateCast() {
    if (this.lastCastEvent === null) {
      // Cast was good!
      return;
    }

    this.lastCastEvent.meta = this.lastCastEvent.meta || {};
    this.lastCastEvent.meta.isInefficientCast = true;
    if (this.lastCastDidDamage) {
      this.lastCastEvent.meta.inefficientCastReason = `You cast Glacial Spike without shattering${this.hasSplittingIce ? ' or cleaving' : ''} it. You should wait until you are able to use a Brain Freeze proc${this.hasSplittingIce ? ' or for a second target to be in cleave range' : ''} to maximize its damage.`;
    } else {
      this.lastCastEvent.meta.inefficientCastReason = 'The target died before Glacial Spike hit it. You should avoid this by casting faster spells on very low-health targets, it is important to not waste potential Glacial Spike damage.';

    }
    this.lastCastEvent = null;
  }

  get utilPercentage() {
    return (this.goodCasts / this.totalCasts) || 0;
  }

  get badCasts() {
    return this.totalCasts - this.goodCasts;
  }

  get utilSuggestionThresholds() {
    return {
      actual: this.utilPercentage,
      isLessThan: {
        minor: 1.0,
        average: 0.85,
        major: 0.7,
      },
      style: 'percentage',
    };
  }

  suggestions(when) {
    when(this.utilSuggestionThresholds)
      .addSuggestion((suggest, actual, recommended) => {
        return suggest(
          <>
            You cast <SpellLink id={SPELLS.GLACIAL_SPIKE_TALENT.id} /> inefficiently {this.badCasts} times. Because it is such a potent ability, it is important to maximize its damage by only casting it when at least one of the following is true:

You have a <SpellLink id={SPELLS.BRAIN_FREEZE.id} /> proc to <dfn data-tip="Glacial Spike > (empowered) Flurry > Ice Lance
Because of Flurry's extremely fast travel time, using a Brain Freeze proc immediately following a slower spell like Glacial Spike will apply Winter's Chill to the target before the slower spell hits.">use on it</dfn>.

The <SpellLink id={SPELLS.GLACIAL_SPIKE_TALENT.id} /> will cleave to a second target via <SpellLink id={SPELLS.SPLITTING_ICE_TALENT.id} /> (if talented).

          </>)
          .icon(SPELLS.GLACIAL_SPIKE_TALENT.icon)
          .actual(`${formatPercentage(this.utilPercentage, 1)}% utilization`)
          .recommended(`${formatPercentage(recommended, 1)}% is recommended`);
      });
  }

  statistic() {
    return (
      <TalentStatisticBox
        position={STATISTIC_ORDER.CORE(90)}
        icon={<SpellIcon id={SPELLS.GLACIAL_SPIKE_TALENT.id} />}
        value={`${formatPercentage(this.utilPercentage, 0)} %`}
        label="Glacial Spike efficiency"
        tooltip={`You cast Glacial Spike ${this.totalCasts} times, ${this.goodCasts} casts of which met at least one of the requirements:

It was shattered via Brain Freeze (or some other freeze effect).

It hit a second target via Splitting Ice.

`}
      />
    );
  }
}

export default GlacialSpike;
<|endoftext|>


<commit_before>(function() {
  "use strict";

  // See https://angular-translate.github.io/docs/#/guide
  angular.module('dimApp')
    .config(['$translateProvider', function($translateProvider) {
      $translateProvider.useSanitizeValueStrategy('escape');

      $translateProvider
        .translations('en', {
          Level: "Level",
          Weapons: "Weapons",
          Armor: "Armor",
          Equip: "Equip",
          Vault: "Vault",
          Vanguard: "Vanguard"
        })
        .translations('it', {
          Level: "Livello",
          Weapons: "Armi",
          Armor: "Armatura",
          Equip: "Equipaggia",
          Vault: "Depositi",
          Vanguard: "Avanguardia"
        })
        .translations('de', {
          Weapons: "Waffen",
          Armor: "Rüstung",
          Equip: "Ausrüsten",
          Vault: "Tresor",
          Vanguard: "Vorhut"
        })
        .translations('fr', {
          Level: "Niveau",
          Weapons: "Armes",
          Armor: "Armure",
          Equip: "Équiper",
          Vault: "Coffres",
          Vanguard: "Avant-garde"
        })
        .translations('es', {
          Level: "Nivel",
          Weapons: "Armas",
          Armor: "Armadura",
          Equip: "Equipar",
          Vault: "Depósito",
          Vanguard: "Vanguardia"
        })
        .translations('ja', {
          Level: "レベル",
          Weapons: "武器",
          Armor: "装甲",
          Equip: "装備し",
          Vault: "保管",
          Vanguard: "前衛"
        })
        .translations('pt-br', {
          Level: "Nível",
          Weapons: "Armas",
          Armor: "Armadura",
          Equip: "Equipar",
          Vault: "Cofres",
          Vanguard: "Vanguarda"
        })
        .fallbackLanguage('en');
    }]);
})();
<commit_msg>Added translations for "General" and "Postmaster"<commit_after>(function() {
  "use strict";

  // See https://angular-translate.github.io/docs/#/guide
  angular.module('dimApp')
    .config(['$translateProvider', function($translateProvider) {
      $translateProvider.useSanitizeValueStrategy('escape');

      $translateProvider
        .translations('en', {
          Level: "Level",
          Weapons: "Weapons",
          Armor: "Armor",
          General: "General",
          Postmaster: "Postmaster",
          Equip: "Equip",
          Vault: "Vault",
          Vanguard: "Vanguard"
        })
        .translations('it', {
          Level: "Livello",
          Weapons: "Armi",
          Armor: "Armatura",
          General: "Generale",
          Postmaster: "Amministratrice",
          Equip: "Equipaggia",
          Vault: "Depositi",
          Vanguard: "Avanguardia"
        })
        .translations('de', {
          Weapons: "Waffen",
          Armor: "Rüstung",
          General: "Allgemein",
          Postmaster: "Poststelle",
          Equip: "Ausrüsten",
          Vault: "Tresor",
          Vanguard: "Vorhut"
        })
        .translations('fr', {
          Level: "Niveau",
          Weapons: "Armes",
          Armor: "Armure",
          General: "Général",
          Postmaster: "Commis des postes",
          Equip: "Équiper",
          Vault: "Coffres",
          Vanguard: "Avant-garde"
        })
        .translations('es', {
          Level: "Nivel",
          Weapons: "Armas",
          Armor: "Armadura",
          Postmaster: "Administración",
          Equip: "Equipar",
          Vault: "Depósito",
          Vanguard: "Vanguardia"
        })
        .translations('ja', {
          Level: "レベル",
          Weapons: "武器",
          Armor: "装甲",
          General: "一般的な",
          Postmaster: "郵便局",
          Equip: "装備し",
          Vault: "保管",
          Vanguard: "前衛"
        })
        .translations('pt-br', {
          Level: "Nível",
          Weapons: "Armas",
          Armor: "Armadura",
          Equip: "Equipar",
          General: "Geral",
          Postmaster: "Chefe do Correio",
          Vault: "Cofres",
          Vanguard: "Vanguarda"
        })
        .fallbackLanguage('en');
    }]);
})();
<|endoftext|>


<commit_before>import _ from 'lodash';

import React from 'react';
import { Router, Route, Link } from 'react-router';
import Griddle from 'griddle-react';
import Loader from 'react-loader';
import { octokat, octokatHelper } from '../factory';
import * as helper from '../helper';
import Auth from '../auth';
import { dispatcher } from '../dispatcher';

import {
  Alert,
  Button,
  CollapsibleNav,
  Input,
  MenuItem,
  Modal,
  Nav,
  Navbar,
  NavBrand,
  NavDropdown,
  NavItem
} from 'react-bootstrap';

class AppRoute extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      error: null,
      user: null,
      authed: false,
      githubAccessToken: null,
      rateLimit: {},
      reset: new Date(),
      repos: [
        'oauth-io/oauth-js',
        'isaacs/github'
      ],
      showingAuthModal: false
    };

    dispatcher.register(payload => {
      if(payload.actionType === dispatcher.actionTypes.ERROR) {
        var error = payload.data;
        this.setState({error});
      }
    });
  }

  componentDidMount() {
    this.checkAuth();

    var checkRateLimit = () => {
      if (!octokat()) {
        setTimeout(checkRateLimit, 2000);
        return;
      }
      octokat().rateLimit.fetch().then(
        (data) => {
          var rateLimit = data.resources.core;
          var reset = data.resources.core.reset;
          var date = new Date(reset*1000);
          var state = {rateLimit, reset: date};
          this.setState(state);
          setTimeout(checkRateLimit, 2000);
        },
        () => {
          console.error(arguments);
        }
      );
    };
    checkRateLimit();
  }

  onClickSignIn() {
    this.showAuthModal();
  }

  onClickAuth() {
    this.showAuthModal();
  }

  showAuthModal() {
    this.setState({showingAuthModal: true});
  }

  signIn() {
    Auth.signIn().then(this.onSignedIn.bind(this));
  }

  onClickSignOut() {
    console.log('onClickSignOut');
    Auth.signOut().
      then(d => {
        this.setState({authed: false, user: null})
      });
  }

  checkAuth(options) {
    Auth.check(options).
      then(d => {
        console.log('authed', d);
        this.setState({githubAccessToken: d.githubAccessToken})
        this.onSignedIn();
      });
  }

  onSignedIn() {
    this.setState({authed: true});

    octokat().user.fetch().then(user => {
      console.log(user);
      this.setState({user});
    });
  }

  signInFromAlert() {
    this.dismissAlert();
    this.signIn();
  }

  dismissAlert() {
    this.setState({error: null});
  }

  closeAuthModal() {
    this.setState({showingAuthModal: false});
  }

  onChangeGitHubAccessToken(e) {
    var githubAccessToken = e.target.value;
    this.setState({githubAccessToken});
    Auth.setToken(githubAccessToken).
      then(d => {
        this.onSignedIn();
      });
  }

  render() {
    var children = this.props.children;

    if (! children) {
      children = (

          {this.state.repos.map(r => {
            return (

                <Link to={'/' + r}>{r}</Link>

            );
          })}

      );
    }

    var errorCmp;
    var error = this.state.error;
    if (this.state.error) {
      var message = error.message || error;
      errorCmp =
        <Alert bsStyle="danger" onDismiss={this.dismissAlert.bind(this)}>

Oh snap! You got an error!

{message}

            <Button onClick={this.onClickSignIn.bind(this)} bsStyle="success">Sign In</Button>
             or
            <Button onClick={this.dismissAlert.bind(this)}>Hide Alert</Button>

        </Alert>;
    }

    var authModalSignInCmp;
    if (! this.state.user) {
      authModalSignInCmp = (
        <Button
          bsStyle="success"
          onClick={this.signIn.bind(this)}
        >
          Sign In to GitHub via OAuth.io
        </Button>
      );
    }
    else {
      authModalSignInCmp = (

              @{this.state.user.login}

            <Button
              bsStyle="success"
              onClick={this.onClickSignOut.bind(this)}
            >
               Sign Out
            </Button>

      );
    }

    var authBarCmp;
    if (! this.state.user) {
      /*
       * https://github.com/react-bootstrap/react-bootstrap/issues/1404
       */
      authBarCmp = (
        <button type="button"
          className="btn btn-success navbar-btn navbar-right"
          onClick={this.onClickSignIn.bind(this)}
        >
          Sign In
        </button>
      );
    }
    else {
      var avatar = (

      );
      authBarCmp = (

          <NavDropdown eventKey={2}
            title={avatar}
            id="ghir-navbar-user-dropdown"
          >
            <MenuItem eventKey={5}
              onSelect={this.onClickAuth.bind(this)}
            >
               Authentication
            </MenuItem>
            <MenuItem eventKey={5}
              onSelect={this.onClickSignOut.bind(this)}
            >
               Sign Out
            </MenuItem>
          </NavDropdown>

      );
    }

    return (

        <Navbar toggleNavKey={0}>
          <NavBrand>
            <Link to="/">GitHub Issue Rank</Link>
          </NavBrand>
          <CollapsibleNav eventKey={0}>

              <NavDropdown eventKey={3}
                title={}
                id="ghir-navbar-more-dropdown"
              >
                <MenuItem eventKey={1}>
                   Settings
                </MenuItem>
                <MenuItem divider />
                <MenuItem eventKey={4}
                  href="https://github.com/AndersDJohnson/github-issue-rank"
                  target="_blank"
                >
                   Source Code
                </MenuItem>
              </NavDropdown>

            {authBarCmp}

          </CollapsibleNav>
        </Navbar>

        <Modal show={this.state.showingAuthModal} onHide={this.closeAuthModal.bind(this)}>
          <Modal.Header closeButton>
            <Modal.Title>Authentication</Modal.Title>
          </Modal.Header>
          <Modal.Body>

            {authModalSignInCmp}

Or provide an access token:

            <Input
              type="text"
              value={this.state.githubAccessToken}
              onChange={this.onChangeGitHubAccessToken.bind(this)}
            />

          </Modal.Body>
          <Modal.Footer>
            <Button
              onClick={this.closeAuthModal.bind(this)}
            >
              Close
            </Button>
          </Modal.Footer>
        </Modal>

        {errorCmp}

          <progress id="gh-api-limit"
            title="API Limit"
            value={this.state.rateLimit.remaining}
            max={this.state.rateLimit.limit} />

            API Limit {this.state.rateLimit.remaining} / {this.state.rateLimit.limit}
             (resets {this.state.reset.toString()})

        {children}

    )
  }
};

class NoRoute extends React.Component {
  componentDidMount() {
    console.log(this.props.params);
  }

  render() {
    return (

404

    )
  }
};

class LinkComponent extends React.Component {
  render() {
    var data = this.data();
    var {owner, repo, number} = this.props.rowData;
    var href = '/' + owner + '/' + repo + '/' + number;
    return <Link to={href} target="_blank">{data}</Link>;
  }
  data() {
    return this.props.data;
  }
};

class IssueNumberComponent extends LinkComponent {
  data() {
    var data = this.props.data;
    return data ? '#' + data : '';
  }
};

class RepoRoute extends React.Component {
  constructor(props) {
    super(props);

    var columnMetadata = [
      {
        columnName: 'number',
        displayName: '#',
        customComponent: IssueNumberComponent,
        cssClassName: 'griddle-column-number'
      },
      {
        columnName: 'title',
        displayName: 'Title',
        customComponent: LinkComponent,
        cssClassName: 'griddle-column-title'
      },
      {
        columnName: 'voteCount',
        displayName: '# Votes',
        customComponent: LinkComponent,
        cssClassName: 'griddle-column-voteCount'
      },
      {
        columnName: 'owner',
        visible: false
      },
      {
        columnName: 'repo',
        visible: false
      },
      {
        columnName: 'htmlUrl',
        visible: false
      }
    ];

    columnMetadata = _.each(columnMetadata, (md, i) => { md.order = i; })

    var columns =_.chain(columnMetadata)
      .sortBy('order')
      .filter((md) => {
        return md.visible == null ? true : false;
      })
      .pluck('columnName')
      .value();

    this.state = {
      owner: null,
      repo: null,
      rows: [],
      loaded: false,
      anyLoaded: false,
      columnMetadata,
      columns,
      progress: {
        value:0,
        max: 0
      }
    };
  }

  componentDidUpdate() {
    this.unmounting = false;
    this.showRepo();
  }

  componentDidMount() {
    this.unmounting = false;
    this.showRepo();
  }

  componentWillUnmount () {
    // allows us to ignore an inflight request in scenario 4
    this.unmounting = true;
    this.owner = null;
    this.repo = null;
  }

  sameState(owner, repo) {
    return (! this.unmounting) && (owner && (owner === this.state.owner)) && (repo && (repo === this.state.repo));
  }

  showRepo() {
    var {owner, repo} = this.props.params;

    if (this.sameState(owner, repo)) return;

    this.setState({
      loaded: false,
      owner: owner,
      repo: repo,
      rows: []
    });

    Auth.wait().then(() => {
      helper.showRepo(owner, repo,
        (err, rows, cancel, progress) => {
          if (err) {
            return dispatcher.error(err);
          }
          if ( ! this.sameState(owner, repo)) return cancel();
          this.showRows(err, rows);
          this.setState({
            anyLoaded: true,
            progress
          });
        },
        (err, rows, cancel, progress) => {
          // console.log('progress', progress);
          if (err) {
            this.setState({loaded: true, anyLoaded: true})
            return dispatcher.error(err);
          }
          if ( ! this.sameState(owner, repo)) return cancel();
          this.showRows(err, rows);
          this.setState({
            loaded: true,
            progress
          });
        }
      );
    });

  }

  showRows(err, rows) {
    if (! this.unmounting) {
      this.setState({
        rows
      });
    }
  }

  render() {
    var {owner, repo} = this.props.params;

    return (

          <Link to={'/' + owner + '/' + repo}>
            {owner}/{repo}
          </Link>

        <progress
          value={this.state.progress.value}
          max={this.state.progress.max}
        ></progress>

        <Loader loaded={this.state.loaded}></Loader>

        <Loader loaded={this.state.anyLoaded}>

# issues: {this.state.rows.length}

          <Griddle
            results={this.state.rows}
            columnMetadata={this.state.columnMetadata}
            columns={this.state.columns}
            resultsPerPage={10}
            showSettings={true}
            showFilter={true}
          />
        </Loader>

    )
  }
};

class IssueRoute extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      owner: null,
      repo: null,
      number: null,
      issue: {},
      comments: [],
      commentsWithVotes: [],
      loaded: false
    };
  }

  componentDidMount() {
    this.unmounting = false;
    this.showComments();
  }

  showComments() {
    var {owner, repo, number} = this.props.params;

    Auth.wait().then(() => {
      octokat()
        .repos(owner, repo)
        .issues(number)
        .fetch()
        .then(issue => {
          // console.log('issue', issue);
          this.setState({issue});
        }, (err) => {
          if (err) throw err;
        });

      octokatHelper().getComments(
        owner, repo, number,
        (err, comments, cancel) => {
          if (err) {
            return dispatcher.error(err);
          }

          // console.log('each', err, comments, cancel);
          comments = helper.mapCommentsHaveVotes(comments);
          this.setState({comments});
          var commentsWithVotes = comments.filter(c => {
            return c.hasVote;
          });
          this.setState({commentsWithVotes});
        },
        (err, comments) => {
          if (err) {
            return dispatcher.error(err);
          }
          // console.log('done', comments);
        }
      );
    });
  }

  render() {
    var {owner, repo, number} = this.props.params;
    return (

          <Link to={'/' + owner + '/' + repo}>
            {owner}/{repo}
          </Link>

          <Link to={'/' + owner + '/' + repo + '/' + number}>
            #{number}
          </Link>

          {this.state.issue.title}

          {this.state.commentsWithVotes.map(c => {
            return (

            );
          })}

    );
  }
};

export class RouterComponent extends React.Component {
  render() {
    return (
      <Router>
        <Route path="/" component={AppRoute}>
          <Route path=":owner/:repo" component={RepoRoute}/>
          <Route path=":owner/:repo/:number" component={IssueRoute}/>
          <Route path="*" component={NoRoute}/>
        </Route>
      </Router>
    );
  }
};
<commit_msg>Remove console.log.<commit_after>import _ from 'lodash';

import React from 'react';
import { Router, Route, Link } from 'react-router';
import Griddle from 'griddle-react';
import Loader from 'react-loader';
import { octokat, octokatHelper } from '../factory';
import * as helper from '../helper';
import Auth from '../auth';
import { dispatcher } from '../dispatcher';

import {
  Alert,
  Button,
  CollapsibleNav,
  Input,
  MenuItem,
  Modal,
  Nav,
  Navbar,
  NavBrand,
  NavDropdown,
  NavItem
} from 'react-bootstrap';

class AppRoute extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      error: null,
      user: null,
      authed: false,
      githubAccessToken: null,
      rateLimit: {},
      reset: new Date(),
      repos: [
        'oauth-io/oauth-js',
        'isaacs/github'
      ],
      showingAuthModal: false
    };

    dispatcher.register(payload => {
      if(payload.actionType === dispatcher.actionTypes.ERROR) {
        var error = payload.data;
        this.setState({error});
      }
    });
  }

  componentDidMount() {
    this.checkAuth();

    var checkRateLimit = () => {
      if (!octokat()) {
        setTimeout(checkRateLimit, 2000);
        return;
      }
      octokat().rateLimit.fetch().then(
        (data) => {
          var rateLimit = data.resources.core;
          var reset = data.resources.core.reset;
          var date = new Date(reset*1000);
          var state = {rateLimit, reset: date};
          this.setState(state);
          setTimeout(checkRateLimit, 2000);
        },
        () => {
          console.error(arguments);
        }
      );
    };
    checkRateLimit();
  }

  onClickSignIn() {
    this.showAuthModal();
  }

  onClickAuth() {
    this.showAuthModal();
  }

  showAuthModal() {
    this.setState({showingAuthModal: true});
  }

  signIn() {
    Auth.signIn().then(this.onSignedIn.bind(this));
  }

  onClickSignOut() {
    console.log('onClickSignOut');
    Auth.signOut().
      then(d => {
        this.setState({authed: false, user: null})
      });
  }

  checkAuth(options) {
    Auth.check(options).
      then(d => {
        console.log('authed', d);
        this.setState({githubAccessToken: d.githubAccessToken})
        this.onSignedIn();
      });
  }

  onSignedIn() {
    this.setState({authed: true});

    octokat().user.fetch().then(user => {
      this.setState({user});
    });
  }

  signInFromAlert() {
    this.dismissAlert();
    this.signIn();
  }

  dismissAlert() {
    this.setState({error: null});
  }

  closeAuthModal() {
    this.setState({showingAuthModal: false});
  }

  onChangeGitHubAccessToken(e) {
    var githubAccessToken = e.target.value;
    this.setState({githubAccessToken});
    Auth.setToken(githubAccessToken).
      then(d => {
        this.onSignedIn();
      });
  }

  render() {
    var children = this.props.children;

    if (! children) {
      children = (

          {this.state.repos.map(r => {
            return (

                <Link to={'/' + r}>{r}</Link>

            );
          })}

      );
    }

    var errorCmp;
    var error = this.state.error;
    if (this.state.error) {
      var message = error.message || error;
      errorCmp =
        <Alert bsStyle="danger" onDismiss={this.dismissAlert.bind(this)}>

Oh snap! You got an error!

{message}

            <Button onClick={this.onClickSignIn.bind(this)} bsStyle="success">Sign In</Button>
             or
            <Button onClick={this.dismissAlert.bind(this)}>Hide Alert</Button>

        </Alert>;
    }

    var authModalSignInCmp;
    if (! this.state.user) {
      authModalSignInCmp = (
        <Button
          bsStyle="success"
          onClick={this.signIn.bind(this)}
        >
          Sign In to GitHub via OAuth.io
        </Button>
      );
    }
    else {
      authModalSignInCmp = (

              @{this.state.user.login}

            <Button
              bsStyle="success"
              onClick={this.onClickSignOut.bind(this)}
            >
               Sign Out
            </Button>

      );
    }

    var authBarCmp;
    if (! this.state.user) {
      /*
       * https://github.com/react-bootstrap/react-bootstrap/issues/1404
       */
      authBarCmp = (
        <button type="button"
          className="btn btn-success navbar-btn navbar-right"
          onClick={this.onClickSignIn.bind(this)}
        >
          Sign In
        </button>
      );
    }
    else {
      var avatar = (

      );
      authBarCmp = (

          <NavDropdown eventKey={2}
            title={avatar}
            id="ghir-navbar-user-dropdown"
          >
            <MenuItem eventKey={5}
              onSelect={this.onClickAuth.bind(this)}
            >
               Authentication
            </MenuItem>
            <MenuItem eventKey={5}
              onSelect={this.onClickSignOut.bind(this)}
            >
               Sign Out
            </MenuItem>
          </NavDropdown>

      );
    }

    return (

        <Navbar toggleNavKey={0}>
          <NavBrand>
            <Link to="/">GitHub Issue Rank</Link>
          </NavBrand>
          <CollapsibleNav eventKey={0}>

              <NavDropdown eventKey={3}
                title={}
                id="ghir-navbar-more-dropdown"
              >
                <MenuItem eventKey={1}>
                   Settings
                </MenuItem>
                <MenuItem divider />
                <MenuItem eventKey={4}
                  href="https://github.com/AndersDJohnson/github-issue-rank"
                  target="_blank"
                >
                   Source Code
                </MenuItem>
              </NavDropdown>

            {authBarCmp}

          </CollapsibleNav>
        </Navbar>

        <Modal show={this.state.showingAuthModal} onHide={this.closeAuthModal.bind(this)}>
          <Modal.Header closeButton>
            <Modal.Title>Authentication</Modal.Title>
          </Modal.Header>
          <Modal.Body>

            {authModalSignInCmp}

Or provide an access token:

            <Input
              type="text"
              value={this.state.githubAccessToken}
              onChange={this.onChangeGitHubAccessToken.bind(this)}
            />

          </Modal.Body>
          <Modal.Footer>
            <Button
              onClick={this.closeAuthModal.bind(this)}
            >
              Close
            </Button>
          </Modal.Footer>
        </Modal>

        {errorCmp}

          <progress id="gh-api-limit"
            title="API Limit"
            value={this.state.rateLimit.remaining}
            max={this.state.rateLimit.limit} />

            API Limit {this.state.rateLimit.remaining} / {this.state.rateLimit.limit}
             (resets {this.state.reset.toString()})

        {children}

    )
  }
};

class NoRoute extends React.Component {
  componentDidMount() {
    console.log(this.props.params);
  }

  render() {
    return (

404

    )
  }
};

class LinkComponent extends React.Component {
  render() {
    var data = this.data();
    var {owner, repo, number} = this.props.rowData;
    var href = '/' + owner + '/' + repo + '/' + number;
    return <Link to={href} target="_blank">{data}</Link>;
  }
  data() {
    return this.props.data;
  }
};

class IssueNumberComponent extends LinkComponent {
  data() {
    var data = this.props.data;
    return data ? '#' + data : '';
  }
};

class RepoRoute extends React.Component {
  constructor(props) {
    super(props);

    var columnMetadata = [
      {
        columnName: 'number',
        displayName: '#',
        customComponent: IssueNumberComponent,
        cssClassName: 'griddle-column-number'
      },
      {
        columnName: 'title',
        displayName: 'Title',
        customComponent: LinkComponent,
        cssClassName: 'griddle-column-title'
      },
      {
        columnName: 'voteCount',
        displayName: '# Votes',
        customComponent: LinkComponent,
        cssClassName: 'griddle-column-voteCount'
      },
      {
        columnName: 'owner',
        visible: false
      },
      {
        columnName: 'repo',
        visible: false
      },
      {
        columnName: 'htmlUrl',
        visible: false
      }
    ];

    columnMetadata = _.each(columnMetadata, (md, i) => { md.order = i; })

    var columns =_.chain(columnMetadata)
      .sortBy('order')
      .filter((md) => {
        return md.visible == null ? true : false;
      })
      .pluck('columnName')
      .value();

    this.state = {
      owner: null,
      repo: null,
      rows: [],
      loaded: false,
      anyLoaded: false,
      columnMetadata,
      columns,
      progress: {
        value:0,
        max: 0
      }
    };
  }

  componentDidUpdate() {
    this.unmounting = false;
    this.showRepo();
  }

  componentDidMount() {
    this.unmounting = false;
    this.showRepo();
  }

  componentWillUnmount () {
    // allows us to ignore an inflight request in scenario 4
    this.unmounting = true;
    this.owner = null;
    this.repo = null;
  }

  sameState(owner, repo) {
    return (! this.unmounting) && (owner && (owner === this.state.owner)) && (repo && (repo === this.state.repo));
  }

  showRepo() {
    var {owner, repo} = this.props.params;

    if (this.sameState(owner, repo)) return;

    this.setState({
      loaded: false,
      owner: owner,
      repo: repo,
      rows: []
    });

    Auth.wait().then(() => {
      helper.showRepo(owner, repo,
        (err, rows, cancel, progress) => {
          if (err) {
            return dispatcher.error(err);
          }
          if ( ! this.sameState(owner, repo)) return cancel();
          this.showRows(err, rows);
          this.setState({
            anyLoaded: true,
            progress
          });
        },
        (err, rows, cancel, progress) => {
          // console.log('progress', progress);
          if (err) {
            this.setState({loaded: true, anyLoaded: true})
            return dispatcher.error(err);
          }
          if ( ! this.sameState(owner, repo)) return cancel();
          this.showRows(err, rows);
          this.setState({
            loaded: true,
            progress
          });
        }
      );
    });

  }

  showRows(err, rows) {
    if (! this.unmounting) {
      this.setState({
        rows
      });
    }
  }

  render() {
    var {owner, repo} = this.props.params;

    return (

          <Link to={'/' + owner + '/' + repo}>
            {owner}/{repo}
          </Link>

        <progress
          value={this.state.progress.value}
          max={this.state.progress.max}
        ></progress>

        <Loader loaded={this.state.loaded}></Loader>

        <Loader loaded={this.state.anyLoaded}>

# issues: {this.state.rows.length}

          <Griddle
            results={this.state.rows}
            columnMetadata={this.state.columnMetadata}
            columns={this.state.columns}
            resultsPerPage={10}
            showSettings={true}
            showFilter={true}
          />
        </Loader>

    )
  }
};

class IssueRoute extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      owner: null,
      repo: null,
      number: null,
      issue: {},
      comments: [],
      commentsWithVotes: [],
      loaded: false
    };
  }

  componentDidMount() {
    this.unmounting = false;
    this.showComments();
  }

  showComments() {
    var {owner, repo, number} = this.props.params;

    Auth.wait().then(() => {
      octokat()
        .repos(owner, repo)
        .issues(number)
        .fetch()
        .then(issue => {
          // console.log('issue', issue);
          this.setState({issue});
        }, (err) => {
          if (err) throw err;
        });

      octokatHelper().getComments(
        owner, repo, number,
        (err, comments, cancel) => {
          if (err) {
            return dispatcher.error(err);
          }

          // console.log('each', err, comments, cancel);
          comments = helper.mapCommentsHaveVotes(comments);
          this.setState({comments});
          var commentsWithVotes = comments.filter(c => {
            return c.hasVote;
          });
          this.setState({commentsWithVotes});
        },
        (err, comments) => {
          if (err) {
            return dispatcher.error(err);
          }
          // console.log('done', comments);
        }
      );
    });
  }

  render() {
    var {owner, repo, number} = this.props.params;
    return (

          <Link to={'/' + owner + '/' + repo}>
            {owner}/{repo}
          </Link>

          <Link to={'/' + owner + '/' + repo + '/' + number}>
            #{number}
          </Link>

          {this.state.issue.title}

          {this.state.commentsWithVotes.map(c => {
            return (

            );
          })}

    );
  }
};

export class RouterComponent extends React.Component {
  render() {
    return (
      <Router>
        <Route path="/" component={AppRoute}>
          <Route path=":owner/:repo" component={RepoRoute}/>
          <Route path=":owner/:repo/:number" component={IssueRoute}/>
          <Route path="*" component={NoRoute}/>
        </Route>
      </Router>
    );
  }
};
<|endoftext|>


<commit_before>var ServiceTableHeaderLabels = {
  cpus: "CPU",
  disk: "Disk",
  gpus: "GPU",
  mem: "Mem",
  name: "Name",
  status: "Status",
  version: "Version",
  instances: "Instances",
  regions: "Region"
};

module.exports = ServiceTableHeaderLabels;
<commit_msg>feat(ServiceTableHeaderLabels): mark for translation<commit_after>import { i18nMark } from "@lingui/react";

const ServiceTableHeaderLabels = {
  cpus: i18nMark("CPU"),
  disk: i18nMark("Disk"),
  gpus: i18nMark("GPU"),
  mem: i18nMark("Mem"),
  name: i18nMark("Name"),
  status: i18nMark("Status"),
  version: i18nMark("Version"),
  instances: i18nMark("Instances"),
  regions: i18nMark("Region")
};

module.exports = ServiceTableHeaderLabels;
<|endoftext|>