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

function renderDataTable( /* Array of Data Objects */ components )
{
    // number of actions plus 3 -- id, name and state
    var columns = components.numActions + 3;

    header( columns );

    if (components.error)
    {
        error( columns, components.error );
    }
    else
    {
        data ( components.data );
    }

    footer( columns );
}

function header( /* int */ columns )
{
    document.write( "
" );

    document.write( "
" );
    document.write( " 	" );
    document.write( "
" );

    document.write( "
" );
    document.write( "Name	" );
    document.write( "Details	" );
    document.write( "Version	" );
    document.write( "Actions	" );
    document.write( "
" );

}

function error( /* int */ columns, /* String */ message )
{
    document.write( "
" );
    document.write( " 	" );
    document.write( "" + message + "	" );
    document.write( "
" );
}

function data( /* Array of Object */ dataArray )
{
    // render components
    if (dataArray.length == 1)
    {
        entry( dataArray[0], true );
    }
    else {
        for ( var idx in dataArray )
        {
            entry( dataArray[idx] );
        }
    }
}

function footer( /* int */ columns )
{
    document.write( "
" );
    document.write( " 	" );
    document.write( "
" );

    document.write( "
" );
}

function entry( /* Object */ dataEntry, /* boolean */ singleEntry )
{
    var trElement = tr( null, { id: "entry" + dataEntry.id } );
    entryInternal( trElement,  dataEntry, singleEntry );
    document.write( serialize( trElement ) );

    // dataEntry detailed properties
    trElement = tr( null, { id: "entry" + dataEntry.id + "_details" } );
    if (dataEntry.props)
    {
        getDataEntryDetails( trElement, dataEntry.props );
    }
    document.write( serialize( trElement ) );
}

function entryInternal( /* Element */ parent, /* Object */ dataEntry, /* boolean */ singleEntry )
{

    var id = dataEntry.id;
    var name = dataEntry.name;
    var state = dataEntry.state;
    var icon = singleEntry ? "left" : (dataEntry.props ? "down" : "right");
    var event = singleEntry ? "history.back()" : "showDataEntryDetails(" + id + ")";

    parent.appendChild( td( "content right", null, [ text( id ) ] ) );

    parent.appendChild( td( "content", null, [
            createElement( "img", null, {
                src: appRoot + "/res/imgs/" + icon + ".gif",
                onClick: event,
                id: "entry" + id + "_inline"
            } ),
            text( "\u00a0" ),
            createElement( "a", null, {
                href: pluginRoot + "/" + id
            }, [ text( name ) ]
            )]
        )
    );

    parent.appendChild( td( "content center", null, [ text( state ) ] ) );

    for ( var aidx in dataEntry.actions )
    {
        var action = dataEntry.actions[aidx];
        parent.appendChild( actionButton( action.enabled, id, action.link, action.name ) );
    }
}

/* Element */ function actionButton( /* boolean */ enabled, /* long */ id, /* String */ op, /* String */ opLabel )
{
    var buttonTd = td( "content", { align: "right" } );
    if ( op )
    {
        var input = createElement( "input", "submit", {
                type: 'button',
                value: opLabel,
                onClick: 'changeDataEntryState("' + id + '", "' + op + '");'
            });
        if (!enabled)
        {
            input.setAttribute( "disabled", true );
        }
        buttonTd.appendChild( input );
    }
    else
    {
        addText( buttonTd, "\u00a0" );
    }

    return buttonTd;
}

function getDataEntryDetails( /* Element */ parent, /* Array of Object */ details )
{
    parent.appendChild( addText( td( "content"), "\u00a0" ) );

    var tdEl = td( "content", { colspan: 4 } );
    parent.appendChild( tdEl );

    var tableEl = createElement( "table", null, { border: 0 } );
    tdEl.appendChild( tableEl );

    var tbody = createElement( "tbody" );
    tableEl.appendChild( tbody );
    for (var idx in details)
    {
        var prop = details[idx];

        var trEl = tr();
        trEl.appendChild( addText( td( "aligntop", { noWrap: true } ), prop.key ) );

        var proptd = td( "aligntop" );
        trEl.appendChild( proptd );

        if (prop.value )
        {
            var values = new String( prop.value ).split( "
" );
            for (var i=0; i < values.length; i++)
            {
                if (i > 0) { proptd.appendChild( createElement( "br" ) ); }
                addText( proptd, values[i] );
            }
        }
        else
        {
            addText( proptd, "\u00a0" );
        }

        tbody.appendChild( trEl );
    }
 }

function showDetails(bundleId)
{
    var span = document.getElementById('bundle' + bundleId + '_details');
}

function showDataEntryDetails( id )
{
    var span = document.getElementById( 'entry' + id + '_details' );
    if (span)
    {
        if (span.firstChild)
        {
            clearChildren( span );
            newLinkValue( id, appRoot + "/res/imgs/right.gif" );
        }
        else
        {
            sendRequest( 'POST', pluginRoot + '/' + id, displayDataEntryDetails );
            newLinkValue( id, appRoot + "/res/imgs/down.gif" );
        }
    }
}

function newLinkValue( /* long */ id, /* String */ newLinkValue )
{

    var link = document.getElementById( "entry" + id + "_inline" );
    if (link)
    {
        link.src = newLinkValue;
    }
}

function displayDataEntryDetails( obj )
{
    var span = document.getElementById('entry' + obj.id + '_details');
    if (span)
    {
        clearChildren( span );
        getDataEntryDetails( span, obj.props );
    }

}

function changeDataEntryState(/* long */ id, /* String */ action)
{
    var parm = pluginRoot + "/" + id + "?action=" + action;
    sendRequest('POST', parm, dataEntryStateChanged);
}

function dataEntryStateChanged(obj)
{
    if (obj.reload)
    {
        document.location = document.location;
    }
    else
    {
        var id = obj.id;
        if (obj.state)
        {
            // has status, so draw the line
            if (obj.props)
            {
                var span = document.getElementById('entry' + id + '_details');
                if (span && span.firstChild)
                {
                    clearChildren( span );
                    getDataEntryDetails( span, obj.props );
                }
                else
                {
                    obj.props = false;
                }
            }

            var span = document.getElementById('entry' + id);
            if (span)
            {
                clearChildren( span );
                entryInternal( span, obj );
            }
        }
        else
        {
            // no status, dataEntry has been removed/uninstalled
            var span = document.getElementById('entry' + id);
            if (span)
            {
                span.parentNode.removeChild(span);
            }
            var span = document.getElementById('entry' + id + '_details');
            if (span)
            {
                span.parentNode.removeChild(span);
            }
        }
    }
}

function renderPackage( /* Array of Data Objects */ bundleData )
{

    // number of actions plus 3 -- id, name and state
    var columns = 4;

    header( columns );

    installForm(  );

    if (bundleData.error)
    {
        error( columns, bundleData.error );
    }
    else
    {
        data ( bundleData.data );
    }

    installForm(  );

    footer( columns );
}

function installForm( )
{
    document.write( "<form method='post' enctype='multipart/form-data'>" );
    document.write( "
" );
    document.write( " 	" );
    document.write( "" );
    document.write( "<input type='hidden' name='action' value='deploydp' />" );
    document.write( "<input class='input' type='file' name='pckfile' size='50'>" );
    document.write( "	" );
    document.write( "" );
    document.write( "<input class='submit' style='width:auto' type='submit' value='Install or Update'>" );
    document.write( "	" );
    document.write( "
" );
    document.write( "</form>" );
}
<commit_msg>Remove unused function.<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

function header( /* int */ columns )
{
    document.write( "
" );

    document.write( "
" );
    document.write( " 	" );
    document.write( "
" );

    document.write( "
" );
    document.write( "Name	" );
    document.write( "Details	" );
    document.write( "Version	" );
    document.write( "Actions	" );
    document.write( "
" );

}

function error( /* int */ columns, /* String */ message )
{
    document.write( "
" );
    document.write( " 	" );
    document.write( "" + message + "	" );
    document.write( "
" );
}

function data( /* Array of Object */ dataArray )
{
    // render components
    if (dataArray.length == 1)
    {
        entry( dataArray[0], true );
    }
    else {
        for ( var idx in dataArray )
        {
            entry( dataArray[idx] );
        }
    }
}

function footer( /* int */ columns )
{
    document.write( "
" );
    document.write( " 	" );
    document.write( "
" );

    document.write( "
" );
}

function entry( /* Object */ dataEntry, /* boolean */ singleEntry )
{
    var trElement = tr( null, { id: "entry" + dataEntry.id } );
    entryInternal( trElement,  dataEntry, singleEntry );
    document.write( serialize( trElement ) );

    // dataEntry detailed properties
    trElement = tr( null, { id: "entry" + dataEntry.id + "_details" } );
    if (dataEntry.props)
    {
        getDataEntryDetails( trElement, dataEntry.props );
    }
    document.write( serialize( trElement ) );
}

function entryInternal( /* Element */ parent, /* Object */ dataEntry, /* boolean */ singleEntry )
{

    var id = dataEntry.id;
    var name = dataEntry.name;
    var state = dataEntry.state;
    var icon = singleEntry ? "left" : (dataEntry.props ? "down" : "right");
    var event = singleEntry ? "history.back()" : "showDataEntryDetails(" + id + ")";

    parent.appendChild( td( "content right", null, [ text( id ) ] ) );

    parent.appendChild( td( "content", null, [
            createElement( "img", null, {
                src: appRoot + "/res/imgs/" + icon + ".gif",
                onClick: event,
                id: "entry" + id + "_inline"
            } ),
            text( "\u00a0" ),
            createElement( "a", null, {
                href: pluginRoot + "/" + id
            }, [ text( name ) ]
            )]
        )
    );

    parent.appendChild( td( "content center", null, [ text( state ) ] ) );

    for ( var aidx in dataEntry.actions )
    {
        var action = dataEntry.actions[aidx];
        parent.appendChild( actionButton( action.enabled, id, action.link, action.name ) );
    }
}

/* Element */ function actionButton( /* boolean */ enabled, /* long */ id, /* String */ op, /* String */ opLabel )
{
    var buttonTd = td( "content", { align: "right" } );
    if ( op )
    {
        var input = createElement( "input", "submit", {
                type: 'button',
                value: opLabel,
                onClick: 'changeDataEntryState("' + id + '", "' + op + '");'
            });
        if (!enabled)
        {
            input.setAttribute( "disabled", true );
        }
        buttonTd.appendChild( input );
    }
    else
    {
        addText( buttonTd, "\u00a0" );
    }

    return buttonTd;
}

function getDataEntryDetails( /* Element */ parent, /* Array of Object */ details )
{
    parent.appendChild( addText( td( "content"), "\u00a0" ) );

    var tdEl = td( "content", { colspan: 4 } );
    parent.appendChild( tdEl );

    var tableEl = createElement( "table", null, { border: 0 } );
    tdEl.appendChild( tableEl );

    var tbody = createElement( "tbody" );
    tableEl.appendChild( tbody );
    for (var idx in details)
    {
        var prop = details[idx];

        var trEl = tr();
        trEl.appendChild( addText( td( "aligntop", { noWrap: true } ), prop.key ) );

        var proptd = td( "aligntop" );
        trEl.appendChild( proptd );

        if (prop.value )
        {
            var values = new String( prop.value ).split( "
" );
            for (var i=0; i < values.length; i++)
            {
                if (i > 0) { proptd.appendChild( createElement( "br" ) ); }
                addText( proptd, values[i] );
            }
        }
        else
        {
            addText( proptd, "\u00a0" );
        }

        tbody.appendChild( trEl );
    }
 }

function showDetails(bundleId)
{
    var span = document.getElementById('bundle' + bundleId + '_details');
}

function showDataEntryDetails( id )
{
    var span = document.getElementById( 'entry' + id + '_details' );
    if (span)
    {
        if (span.firstChild)
        {
            clearChildren( span );
            newLinkValue( id, appRoot + "/res/imgs/right.gif" );
        }
        else
        {
            sendRequest( 'POST', pluginRoot + '/' + id, displayDataEntryDetails );
            newLinkValue( id, appRoot + "/res/imgs/down.gif" );
        }
    }
}

function newLinkValue( /* long */ id, /* String */ newLinkValue )
{

    var link = document.getElementById( "entry" + id + "_inline" );
    if (link)
    {
        link.src = newLinkValue;
    }
}

function displayDataEntryDetails( obj )
{
    var span = document.getElementById('entry' + obj.id + '_details');
    if (span)
    {
        clearChildren( span );
        getDataEntryDetails( span, obj.props );
    }

}

function changeDataEntryState(/* long */ id, /* String */ action)
{
    var parm = pluginRoot + "/" + id + "?action=" + action;
    sendRequest('POST', parm, dataEntryStateChanged);
}

function dataEntryStateChanged(obj)
{
    if (obj.reload)
    {
        document.location = document.location;
    }
    else
    {
        var id = obj.id;
        if (obj.state)
        {
            // has status, so draw the line
            if (obj.props)
            {
                var span = document.getElementById('entry' + id + '_details');
                if (span && span.firstChild)
                {
                    clearChildren( span );
                    getDataEntryDetails( span, obj.props );
                }
                else
                {
                    obj.props = false;
                }
            }

            var span = document.getElementById('entry' + id);
            if (span)
            {
                clearChildren( span );
                entryInternal( span, obj );
            }
        }
        else
        {
            // no status, dataEntry has been removed/uninstalled
            var span = document.getElementById('entry' + id);
            if (span)
            {
                span.parentNode.removeChild(span);
            }
            var span = document.getElementById('entry' + id + '_details');
            if (span)
            {
                span.parentNode.removeChild(span);
            }
        }
    }
}

function renderPackage( /* Array of Data Objects */ bundleData )
{

    // number of actions plus 3 -- id, name and state
    var columns = 4;

    header( columns );

    installForm(  );

    if (bundleData.error)
    {
        error( columns, bundleData.error );
    }
    else
    {
        data ( bundleData.data );
    }

    installForm(  );

    footer( columns );
}

function installForm( )
{
    document.write( "<form method='post' enctype='multipart/form-data'>" );
    document.write( "
" );
    document.write( " 	" );
    document.write( "" );
    document.write( "<input type='hidden' name='action' value='deploydp' />" );
    document.write( "<input class='input' type='file' name='pckfile' size='50'>" );
    document.write( "	" );
    document.write( "" );
    document.write( "<input class='submit' style='width:auto' type='submit' value='Install or Update'>" );
    document.write( "	" );
    document.write( "
" );
    document.write( "</form>" );
}
<|endoftext|>


<commit_before>"use strict";
import {EventEmitter} from "events"
/**
 * VideoPrefetcher prefetch video.src and replace video.src to completed object url.
 */
export default class VideoPrefetcher extends EventEmitter {
    static get eventTypes() {
        return {
            "load": "load",
            "progress": "progress",
            "abort": "abort",
            "error": "error"
        }
    }

    constructor(video) {
        super();
        if (!video) {
            throw new Error('pass video element as 1st arguments.\n e.g.) new VideoPrefetcher(videoElement);')
        }
        this.video = video;
        this.request = null;
        this.originalSrc = null;
    }

    start() {
        this.originalSrc = this.video.currentSrc;
        this.request = new XMLHttpRequest();
        this.request.open("GET", this.video.currentSrc);
        this.request.responseType = 'arraybuffer';
        this.request.addEventListener("progress", (event) => {
            this.emit(VideoPrefetcher.eventTypes.progress, event);
        });
        var onLoad = (event)=> {
            if (this.request.status !== 200) {
                this.emit(VideoPrefetcher.eventTypes.error, new Error("Unexpected status code " + this.request.status + " for " + this.originalSrc));
                return;
            }
            var blob = new Blob([event.target.response], {
                type: this.video.currentType
            });
            this.video.src = window.URL.createObjectURL(blob);
            this.video.setAttribute("controls", "");
            this.emit(VideoPrefetcher.eventTypes.load, event);
            this.request.removeEventListener("progress", (event) => {
                this.emit(VideoPrefetcher.eventTypes.progress, event);
            });
            this.request.removeEventListener("load", onLoad);
        };
        this.request.addEventListener("load", onLoad);
        this.request.onerror = () => {
            this.emit(VideoPrefetcher.eventTypes.error, new Error("Unexpected status code " + this.request.status + " for " + this.originalSrc));
        };
        this.request.send();
        this.video.removeAttribute("controls");
    }

    onProgress(callback) {
        this.on(VideoPrefetcher.eventTypes.progress, callback);
    }

    onLoad(callback) {
        this.on(VideoPrefetcher.eventTypes.load, callback);
    }

    onError(callback) {
        this.on(VideoPrefetcher.eventTypes.error, callback);
    }

    stop() {
        this.video.setAttribute("controls", "");
        this.request.removeEventListener("progress", () => {
            this.removeAllListeners(VideoPrefetcher.eventTypes.progress);
        });
        this.request.removeEventListener("load", ()=> {
            this.removeAllListeners(VideoPrefetcher.eventTypes.load);
        });
        this.emit(VideoPrefetcher.eventTypes.abort);
        this.request.abort();
    }
}<commit_msg>chore(prefetcher): add status 0 handling<commit_after>"use strict";
import {EventEmitter} from "events"
/**
 * VideoPrefetcher prefetch video.src and replace video.src to completed object url.
 */
export default class VideoPrefetcher extends EventEmitter {
    static get eventTypes() {
        return {
            "load": "load",
            "progress": "progress",
            "abort": "abort",
            "error": "error"
        }
    }

    constructor(video) {
        super();
        if (!video) {
            throw new Error('pass video element as 1st arguments.\n e.g.) new VideoPrefetcher(videoElement);')
        }
        this.video = video;
        this.request = null;
        this.originalSrc = null;
    }

    start() {
        this.originalSrc = this.video.currentSrc;
        this.request = new XMLHttpRequest();
        this.request.open("GET", this.video.currentSrc);
        this.request.responseType = 'arraybuffer';
        this.request.addEventListener("progress", (event) => {
            this.emit(VideoPrefetcher.eventTypes.progress, event);
        });
        var onLoad = (event)=> {
            if (this.request.status !== 0 || this.request.status !== 200) {
                this.emit(VideoPrefetcher.eventTypes.error, new Error("Unexpected status code " + this.request.status + " for " + this.originalSrc));
                return;
            }
            var blob = new Blob([event.target.response], {
                type: this.video.currentType
            });
            this.video.src = window.URL.createObjectURL(blob);
            this.video.setAttribute("controls", "");
            this.emit(VideoPrefetcher.eventTypes.load, event);
            this.request.removeEventListener("progress", (event) => {
                this.emit(VideoPrefetcher.eventTypes.progress, event);
            });
            this.request.removeEventListener("load", onLoad);
        };
        this.request.addEventListener("load", onLoad);
        this.request.onerror = () => {
            this.emit(VideoPrefetcher.eventTypes.error, new Error("Unexpected status code " + this.request.status + " for " + this.originalSrc));
        };
        this.request.send();
        this.video.removeAttribute("controls");
    }

    onProgress(callback) {
        this.on(VideoPrefetcher.eventTypes.progress, callback);
    }

    onLoad(callback) {
        this.on(VideoPrefetcher.eventTypes.load, callback);
    }

    onError(callback) {
        this.on(VideoPrefetcher.eventTypes.error, callback);
    }

    stop() {
        this.video.setAttribute("controls", "");
        this.request.removeEventListener("progress", () => {
            this.removeAllListeners(VideoPrefetcher.eventTypes.progress);
        });
        this.request.removeEventListener("load", ()=> {
            this.removeAllListeners(VideoPrefetcher.eventTypes.load);
        });
        this.emit(VideoPrefetcher.eventTypes.abort);
        this.request.abort();
    }
}<|endoftext|>


<commit_before>/**
 * Module Name: Github
 * Description: Retrieves interesting Github information
 */
var request = require('request'),
    exec = require('child_process').exec;

var github = function(dbot) {
    this.api = {
        "githubStatus": function(callback){
            var reqUrl = "https://status.github.com/api/last-message.json";
            request({"url": reqUrl, "headers": {"UserAgent": dbot.config.github.useragent}}, function(error, response, body) {
                callback(JSON.parse(body));
            });
        }
    };

    var commands = {
        '~repocount': function(event) {
            var reqUrl = "https://api.github.com/users/" + event.params[1] + "/repos";
            request({"url": reqUrl, "headers": {"UserAgent": dbot.config.github.useragent}}, function(error, response, body) {
                if(response.statusCode == "200") {
                    var result = JSON.parse(body);
                    event.reply(dbot.t("repocount",{"user": event.params[1], "count": result.length}));
                } else {
                    event.reply(dbot.t("usernotfound"));
               }
           });
        },
        '~repo': function(event) {
            var repo = event.params[1];
            if (typeof repo == 'undefined') {
                repo = dbot.config.github.defaultrepo;
            }

            var reqUrl = "https://api.github.com/";
            reqUrl += "repos/" + repo;
            request({"url": reqUrl, "headers": {"UserAgent": dbot.config.github.useragent}}, function(error, response, body) {

                var data = JSON.parse(body);
                if (data["fork"] == true) {
                   event.reply(dbot.t("forkedrepo",data));
                } else {
                    event.reply(dbot.t("unforkedrepo",data));
                }
                // TODO: move this shizz into an api call
                var longurl = "http://github.com/" + repo;
                request({method: 'POST', uri: 'http://git.io', form:{url: longurl}}, function(error, response, body){
                    event.reply(dbot.t('location')+" "+response.headers["location"]);
                });
            });
        },
        '~gstatus': function(event) {
            data = this.api.githubStatus(function(data){
                    console.log(data);
                    event.reply(dbot.t("status"+data["status"]));
                    event.reply(data["body"]);
                }.bind(this)
            );
        },
        '~milestone': function(event) {
            var repo = dbot.config.github.defaultrepo;
            var name = event.params[1];
            if (event.params[2]){
                repo = name;
                name = event.params[2];
            }
            var reqUrl = "https://api.github.com/repos/";
            reqUrl += repo + "/milestones";

            request({"url": reqUrl, "headers":{"UserAgent": dbot.config.github.useragent}}, function(error, response, body) {
                var data = JSON.parse(body);
                for (var section in data) {
                    var milestone = data[section];
                    if (milestone["title"] == name){
                        var str = "Milestone " + milestone["title"];
                        var progress = milestone["closed_issues"] / (milestone["open_issues"] + milestone["closed_issues"]);
                        progress = Math.round(progress*100);
                        var bar = "[";
                        for (var i = 10; i < 100; i += 10) {
                            if  ((progress/i) > 1) {
                                bar += "█";
                            } else {
                                bar += " ";
                            }
                        }
                        bar += "]";
                        str += " is " + bar + progress + "% complete";

                        var longurl = "http://github.com/" + repo + "/issues?milestone=" + milestone["number"];
                        request({method: 'POST', uri: 'http://git.io', form:{url: longurl}}, function(error, response, body){
                            event.reply(response.headers["location"]);
                        });
                        event.reply(str);
                        break;
                    }
                }
           });
        },
        '~repocount': function(event) {
        // TODO: add handling for non existent user
            var reqUrl = "https://api.github.com/users/" + event.params[1] + "/repos";
            request({"url": reqUrl,"headers": { "UserAgent": dbot.config.github.useragent}}, function(error, response, body) {
            var result = JSON.parse(body);
			event.reply(event.params[1] + " has " + result.length + " public repositories.");
            });
        },
        '~grate': function(event) {
            request({"url":"https://api.github.com/rate_limit", "headers":{"UserAgent": dbot.config.github.useragent}}, function(error, response, body) {
                event.reply(dbot.config.github.useragent);
                var data = JSON.parse(body);
                if (data.message){
                    event.reply(data.message);
                } else {
                    event.reply("I am at " + data.rate.remaining + " / " + data.rate.limit);
                }
            });
        },
        '~issue': function(event) {
            var repo;
            var issue;
            if (isNaN(event.params[1]) && event.params[1]){ // if ~issue foo/bar
                repo = event.params[1];
                issue = event.params[2];
            } else {
                repo = dbot.config.github.defaultrepo;
                issue = event.params[1];
            }

            if (!issue) { // issue is undefined
                issue = "";
            } else {
                issue = "/" + issue; // got to be a better way
            }

            var reqUrl = "https://api.github.com/repos/" + repo + "/issues" + issue + "?sort=" + dbot.config.github.sortorder;
            request.get({"url": reqUrl, "headers": { "User-Agent": dbot.config.github.useragent}}, function(error,response, body) {
                if (response.statusCode == "200") {
                    var data = JSON.parse(body);
                    console.log(data);
                    if (issue == ""){
                        data = data[0];
                        console.log(data);
                    }
                    if (data["pull_request"]["html_url"] != null){
                        console.log(data["pull_request"]["html_url"]);
                        data["pull_request"] = " with code";
                    } else {
                        data["pull_request"] = "";
                    }
                    if (data["state"]=="open") {
                        data["state"] = "\u000303" + data["state"];
                    } else {
                        data["state"] = "\u000304" + data["state"];
                    }
                    var labels = "";
                    for (var i=0; i < data["labels"].length; i++) { // for-in doesn't like me
                        var color = "\u0003" + (parseInt(data["labels"][i]["color"],16) % 15);
                        labels += " " + color + data["labels"][i]["name"];
                    }
                    data["label"] = labels;
                    event.reply(dbot.t("issue",data));
                    event.reply(data["html_url"]);
                } else {
                    event.reply(dbot.t("issuenotfound"));
                }
            });
       },
       '~commits': function(event) {
            exec("git rev-list --all | wc -l", function(error, stdout, stderr) {
                stdout = stdout.trim();
                request({"url":"http://numbersapi.com/" + stdout + "?fragment&default=XXX"}, function(error, response, body){
                    if (body != "XXX"){
                        event.reply(dbot.t("commitcountfun",{"fact": body, "count": stdout}));
                    } else {
                        // nothing fun about the number, let's try the year
                        request({"url":"http://numbersapi.com/" + stdout + "/year?fragment&default=XXX"}, function(error, response, body){
                            if (body != "XXX"){
                                event.reply(dbot.t("commitcountyear",{"fact": body, "count": stdout}));
                            } else {
                                event.reply(dbot.t("commitcountboring",{"count": stdout}));
                            }
                        });
                    }
               });
            });
        }
    };
    this.commands = commands;

    this.on = 'PRIVMSG';
};

exports.fetch = function(dbot) {
    return new github(dbot);
};
<commit_msg>Fix User-Agent<commit_after>/**
 * Module Name: Github
 * Description: Retrieves interesting Github information
 */
var request = require('request'),
    exec = require('child_process').exec;

var github = function(dbot) {
    this.api = {
        "githubStatus": function(callback){
            var reqUrl = "https://status.github.com/api/last-message.json";
            request({"url": reqUrl, "headers": {"User-Agent": dbot.config.github.useragent}}, function(error, response, body) {
                callback(JSON.parse(body));
            });
        }
    };

    var commands = {
        '~repocount': function(event) {
            var reqUrl = "https://api.github.com/users/" + event.params[1] + "/repos";
            request({"url": reqUrl, "headers": {"User-Agent": dbot.config.github.useragent}}, function(error, response, body) {
                if(response.statusCode == "200") {
                    var result = JSON.parse(body);
                    event.reply(dbot.t("repocount",{"user": event.params[1], "count": result.length}));
                } else {
                    event.reply(dbot.t("usernotfound"));
               }
           });
        },
        '~repo': function(event) {
            var repo = event.params[1];
            if (typeof repo == 'undefined') {
                repo = dbot.config.github.defaultrepo;
            }

            var reqUrl = "https://api.github.com/";
            reqUrl += "repos/" + repo;
            request({"url": reqUrl, "headers": {"User-Agent": dbot.config.github.useragent}}, function(error, response, body) {

                var data = JSON.parse(body);
                if (data["fork"]) {
                   event.reply(dbot.t("forkedrepo",data));
                } else {
                    event.reply(dbot.t("unforkedrepo",data));
                }
                // TODO: move this shizz into an api call
                var longurl = "http://github.com/" + repo;
                request({method: 'POST', uri: 'http://git.io', form:{url: longurl}}, function(error, response, body){
                    event.reply(dbot.t('location')+" "+response.headers["location"]);
                });
            });
        },
        '~gstatus': function(event) {
            data = this.api.githubStatus(function(data){
                console.log(data);
                event.reply(dbot.t("status"+data["status"]));
                event.reply(data["body"]);
            }.bind(this));
        },
        '~milestone': function(event) {
            var repo = dbot.config.github.defaultrepo;
            var name = event.params[1];
            if (event.params[2]){
                repo = name;
                name = event.params[2];
            }
            var reqUrl = "https://api.github.com/repos/";
            reqUrl += repo + "/milestones";

            request({"url": reqUrl, "headers":{"User-Agent": dbot.config.github.useragent}}, function(error, response, body) {
                var data = JSON.parse(body);
                for (var section in data) {
                    var milestone = data[section];
                    if (milestone["title"] == name){
                        var str = "Milestone " + milestone["title"];
                        var progress = milestone["closed_issues"] / (milestone["open_issues"] + milestone["closed_issues"]);
                        progress = Math.round(progress*100);
                        var bar = "[";
                        for (var i = 10; i < 100; i += 10) {
                            if  ((progress/i) > 1) {
                                bar += "█";
                            } else {
                                bar += " ";
                            }
                        }
                        bar += "]";
                        str += " is " + bar + progress + "% complete";

                        var longurl = "http://github.com/" + repo + "/issues?milestone=" + milestone["number"];
                        request({method: 'POST', uri: 'http://git.io', form:{url: longurl}}, function(error, response, body){
                            event.reply(response.headers["location"]);
                        });
                        event.reply(str);
                        break;
                    }
                }
           });
        },
        '~repocount': function(event) {
        // TODO: add handling for non existent user
            var reqUrl = "https://api.github.com/users/" + event.params[1] + "/repos";
            request({"url": reqUrl,"headers": { "User-Agent": dbot.config.github.useragent}}, function(error, response, body) {
            var result = JSON.parse(body);
			event.reply(event.params[1] + " has " + result.length + " public repositories.");
            });
        },
        '~grate': function(event) {
            request.get({"url":"https://api.github.com/rate_limit", "headers":{"User-Agent": dbot.config.github.useragent}}, function(error, response, body) {
                var data = JSON.parse(body);
                if (data.message){
                    event.reply(data.message);
                } else {
                    event.reply(data.rate.remaining + " requests of " + data.rate.limit + " remaining.");
                }
            });
        },
        '~issue': function(event) {
            var repo;
            var issue;
            if (isNaN(event.params[1]) && event.params[1]){ // if ~issue foo/bar
                repo = event.params[1];
                issue = event.params[2];
            } else {
                repo = dbot.config.github.defaultrepo;
                issue = event.params[1];
            }

            if (!issue) { // issue is undefined
                issue = "";
            } else {
                issue = "/" + issue; // got to be a better way
            }

            var reqUrl = "https://api.github.com/repos/" + repo + "/issues" + issue + "?sort=" + dbot.config.github.sortorder;
            request.get({"url": reqUrl, headers: { "User-Agent": dbot.config.github.useragent}}, function(error,response, body) {
                if (response.statusCode == "200") {
                    var data = JSON.parse(body);
                    console.log(data);
                    if (!issue){
                        data = data[0];
                        console.log(data);
                    }
                    if (data["pull_request"]["html_url"]){
                        console.log(data["pull_request"]["html_url"]);
                        data["pull_request"] = " with code";
                    } else {
                        data["pull_request"] = "";
                    }
                    if (data["state"]=="open") {
                        data["state"] = "\u000303" + data["state"];
                    } else {
                        data["state"] = "\u000304" + data["state"];
                    }
                    var labels = "";
                    for (var i=0; i < data["labels"].length; i++) { // for-in doesn't like me
                        var color = "\u0003" + (parseInt(data["labels"][i]["color"],16) % 15);
                        labels += " " + color + data["labels"][i]["name"];
                    }
                    data["label"] = labels;
                    event.reply(dbot.t("issue",data));
                    event.reply(data["html_url"]);
                } else {
                    event.reply(dbot.t("issuenotfound"));
                }
            });
       },
       '~commits': function(event) {
            exec("git rev-list --all | wc -l", function(error, stdout, stderr) {
                stdout = stdout.trim();
                request({"url":"http://numbersapi.com/" + stdout + "?fragment&default=XXX"}, function(error, response, body){
                    if (body != "XXX"){
                        event.reply(dbot.t("commitcountfun",{"fact": body, "count": stdout}));
                    } else {
                        // nothing fun about the number, let's try the year
                        request({"url":"http://numbersapi.com/" + stdout + "/year?fragment&default=XXX"}, function(error, response, body){
                            if (body != "XXX"){
                                event.reply(dbot.t("commitcountyear",{"fact": body, "count": stdout}));
                            } else {
                                event.reply(dbot.t("commitcountboring",{"count": stdout}));
                            }
                        });
                    }
               });
            });
        }
    };
    this.commands = commands;

    this.on = 'PRIVMSG';
};

exports.fetch = function(dbot) {
    return new github(dbot);
};
<|endoftext|>


<commit_before>import macro                        from 'vtk.js/Sources/macro';
import vtkForwardPass               from 'vtk.js/Sources/Rendering/OpenGL/ForwardPass';
import vtkOpenGLViewNodeFactory     from 'vtk.js/Sources/Rendering/OpenGL/ViewNodeFactory';
import vtkShaderCache               from 'vtk.js/Sources/Rendering/OpenGL/ShaderCache';
import vtkViewNode                  from 'vtk.js/Sources/Rendering/SceneGraph/ViewNode';
import vtkOpenGLTextureUnitManager  from 'vtk.js/Sources/Rendering/OpenGL/TextureUnitManager';
import { VtkDataTypes }             from 'vtk.js/Sources/Common/Core/DataArray/Constants';

const { vtkDebugMacro, vtkErrorMacro } = macro;

// ----------------------------------------------------------------------------
// vtkOpenGLRenderWindow methods
// ----------------------------------------------------------------------------

function vtkOpenGLRenderWindow(publicAPI, model) {
  // Set our className
  model.classHierarchy.push('vtkOpenGLRenderWindow');

  // Auto update style
  function updateWindow() {
    // Canvas size
    if (model.renderable) {
      model.canvas.setAttribute('width', model.size[0]);
      model.canvas.setAttribute('height', model.size[1]);
    }
    // Offscreen ?
    model.canvas.style.display = model.useOffScreen ? 'none' : 'block';

    // Cursor type
    if (model.el) {
      model.el.style.cursor = model.cursorVisibility ? model.cursor : 'none';
    }
  }
  publicAPI.onModified(updateWindow);

  // Builds myself.
  publicAPI.buildPass = (prepass) => {
    if (prepass) {
      if (!model.renderable) {
        return;
      }

      publicAPI.prepareNodes();
      publicAPI.addMissingNodes(model.renderable.getRenderers());
      publicAPI.removeUnusedNodes();

      publicAPI.initialize();
      model.children.forEach((child) => {
        child.setContext(model.context);
      });
    }
  };

  publicAPI.initialize = () => {
    if (!model.initialized) {
      model.context = publicAPI.get3DContext();
      model.textureUnitManager = vtkOpenGLTextureUnitManager.newInstance();
      model.textureUnitManager.setContext(model.context);
      model.shaderCache.setContext(model.context);
      // initialize blending for transparency
      const gl = model.context;
      gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA,
                       gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
      gl.enable(gl.BLEND);
      model.initialized = true;
    }
  };

  publicAPI.makeCurrent = () => {
    model.context.makeCurrent();
  };

  publicAPI.setContainer = (el) => {
    if (model.el && model.el !== el) {
      // Remove canvas from previous container
      if (model.canvas.parentNode === model.el) {
        model.el.removeChild(model.canvas);
      } else {
        vtkErrorMacro('Error: canvas parent node does not match container');
      }
    }

    if (model.el !== el) {
      model.el = el;
      if (model.el) {
        model.el.appendChild(model.canvas);
      }

      // Trigger modified()
      publicAPI.modified();
    }
  };

  publicAPI.isInViewport = (x, y, viewport) => {
    const vCoords = viewport.getViewport();
    const size = model.size;
    if ((vCoords[0] * size[0] <= x) &&
        (vCoords[2] * size[0] >= x) &&
        (vCoords[1] * size[1] <= y) &&
        (vCoords[3] * size[1] >= y)) {
      return true;
    }
    return false;
  };

  publicAPI.getViewportSize = (viewport) => {
    const vCoords = viewport.getViewport();
    const size = model.size;
    return [(vCoords[2] - vCoords[0]) * size[0], (vCoords[3] - vCoords[1]) * size[1]];
  };

  publicAPI.getViewportCenter = (viewport) => {
    const size = publicAPI.getViewportSize(viewport);
    return [size[0] * 0.5, size[1] * 0.5];
  };

  publicAPI.displayToNormalizedDisplay = (x, y, z) =>
    [x / model.size[0], y / model.size[1], z];

  publicAPI.normalizedDisplayToDisplay = (x, y, z) =>
    [x * model.size[0], y * model.size[1], z];

  publicAPI.worldToView = (x, y, z, renderer) => {
    const dims = publicAPI.getViewportSize(renderer);
    return renderer.worldToView(y, y, z, dims[0] / dims[1]);
  };

  publicAPI.viewToWorld = (x, y, z, renderer) => {
    const dims = publicAPI.getViewportSize(renderer);
    return renderer.viewToWorld(y, y, z, dims[0] / dims[1]);
  };

  publicAPI.worldToDisplay = (x, y, z, renderer) => {
    const val = publicAPI.worldToView(x, y, z, renderer);
    const val2 = renderer.viewToNormalizedDisplay(val[0], val[1], val[2]);
    return publicAPI.normalizedDisplayToDisplay(val2[0], val2[1], val2[2]);
  };

  publicAPI.displayToWorld = (x, y, z, renderer) => {
    const val = publicAPI.displayToNormalizedDisplay(x, y, z);
    const val2 = renderer.normalizedDisplayToView(val[0], val[1], val[2]);
    return publicAPI.viewToWorld(val2[0], val2[1], val2[2], renderer);
  };

  publicAPI.getPixelData = (x1, y1, x2, y2) => {
    const pixels = new Uint8Array((x2 - x1 + 1) * (y2 - y1 + 1) * 4);
    model.context.readPixels(
      x1, y1, x2 - x1 + 1, y2 - y1 + 1,
      model.context.RGBA,
      model.context.UNSIGNED_BYTE,
      pixels);
    return pixels;
  };

  publicAPI.get2DContext = () => model.canvas.getContext('2d');

  publicAPI.get3DContext = (options = { preserveDrawingBuffer: false, depth: true, alpha: true }) => {
    let result = null;

    const webgl2Supported = (typeof WebGL2RenderingContext !== 'undefined');
    model.webgl2 = false;
    if (model.defaultToWebgl2 && webgl2Supported) {
      result = model.canvas.getContext('webgl2'); // , options);
      if (result) {
        model.webgl2 = true;
        vtkDebugMacro('using webgl2');
      }
    }
    if (!result) {
      result = model.canvas.getContext('webgl', options)
        || model.canvas.getContext('experimental-webgl', options);
    }
    return result;
  };

  publicAPI.activateTexture = (texture) => {
    // Only add if it isn't already there
    const result = model.textureResourceIds.get(texture);
    if (result !== undefined) {
      model.context.activeTexture(model.context.TEXTURE0 + result);
      return;
    }

    const activeUnit = publicAPI.getTextureUnitManager().allocate();
    if (activeUnit < 0) {
      vtkErrorMacro('Hardware does not support the number of textures defined.');
      return;
    }

    model.textureResourceIds.set(texture, activeUnit);
    model.context.activeTexture(model.context.TEXTURE0 + activeUnit);
  };

  publicAPI.deactivateTexture = (texture) => {
    // Only deactivate if it isn't already there
    const result = model.textureResourceIds.get(texture);
    if (result !== undefined) {
      publicAPI.getTextureUnitManager().free(result);
      delete model.textureResourceIds.delete(texture);
    }
  };

  publicAPI.getTextureUnitForTexture = (texture) => {
    const result = model.textureResourceIds.get(texture);
    if (result !== undefined) {
      return result;
    }
    return -1;
  };

  publicAPI.getDefaultTextureInternalFormat = (vtktype, numComps, useFloat) => {
    if (model.webgl2) {
      switch (vtktype) {
        case VtkDataTypes.UNSIGNED_CHAR:
          switch (numComps) {
            case 1: return model.context.R8;
            case 2: return model.context.RG8;
            case 3: return model.context.RGB8;
            case 4:
            default:
              return model.context.RGBA8;
          }
        default:
        case VtkDataTypes.FLOAT:
          switch (numComps) {
            case 1: return model.context.R16F;
            case 2: return model.context.RG16F;
            case 3: return model.context.RGB16F;
            case 4:
            default:
              return model.context.RGBA16F;
          }
      }
    }

    // webgl1 only supports four types
    switch (numComps) {
      case 1: return model.context.LUMINANCE;
      case 2: return model.context.LUMINANCE_ALPHA;
      case 3: return model.context.RGB;
      case 4:
      default:
        return model.context.RGBA;
    }
  };

  function getCanvasDataURL(format = 'image/png') {
    return model.canvas.toDataURL(format);
  }

  publicAPI.captureImage = (format = 'image/png') => {
    if (model.deleted) {
      return null;
    }

    publicAPI.traverseAllPasses();
    return getCanvasDataURL(format);
  };

  publicAPI.traverseAllPasses = () => {
    model.renderPasses.forEach((val) => {
      val.traverse(publicAPI, null);
    });
    if (model.notifyImageReady) {
      publicAPI.invokeImageReady(getCanvasDataURL());
    }
  };
}

// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------

const DEFAULT_VALUES = {
  shaderCache: null,
  initialized: false,
  context: null,
  canvas: null,
  size: [300, 300],
  cursorVisibility: true,
  cursor: 'pointer',
  textureUnitManager: null,
  textureResourceIds: null,
  renderPasses: [],
  notifyImageReady: false,
  webgl2: false,
  defaultToWebgl2: false, // turned off by default
};

// ----------------------------------------------------------------------------

export function extend(publicAPI, model, initialValues = {}) {
  Object.assign(model, DEFAULT_VALUES, initialValues);

  // Create internal instances
  model.canvas = document.createElement('canvas');

  model.textureResourceIds = new Map();

  // Inheritance
  vtkViewNode.extend(publicAPI, model, initialValues);

  model.myFactory = vtkOpenGLViewNodeFactory.newInstance();
  model.shaderCache = vtkShaderCache.newInstance();

  // setup default forward pass rendering
  model.renderPasses[0] = vtkForwardPass.newInstance();

  macro.event(publicAPI, model, 'imageReady');

  // on mac default to webgl2
  if (navigator.appVersion.indexOf('Mac') !== -1) {
    model.defaultToWebgl2 = true;
  }

  // Build VTK API
  macro.get(publicAPI, model, [
    'shaderCache',
    'textureUnitManager',
    'webgl2',
  ]);

  macro.setGet(publicAPI, model, [
    'initialized',
    'context',
    'canvas',
    'renderPasses',
    'notifyImageReady',
    'defaultToWebgl2',
  ]);

  macro.setGetArray(publicAPI, model, [
    'size',
  ], 2);

  // Object methods
  vtkOpenGLRenderWindow(publicAPI, model);
}

// ----------------------------------------------------------------------------

export const newInstance = macro.newInstance(extend, 'vtkOpenGLRenderWindow');

// ----------------------------------------------------------------------------

export default { newInstance, extend };
<commit_msg>fix(Rendering): bug in coordinate conversions<commit_after>import macro                        from 'vtk.js/Sources/macro';
import vtkForwardPass               from 'vtk.js/Sources/Rendering/OpenGL/ForwardPass';
import vtkOpenGLViewNodeFactory     from 'vtk.js/Sources/Rendering/OpenGL/ViewNodeFactory';
import vtkShaderCache               from 'vtk.js/Sources/Rendering/OpenGL/ShaderCache';
import vtkViewNode                  from 'vtk.js/Sources/Rendering/SceneGraph/ViewNode';
import vtkOpenGLTextureUnitManager  from 'vtk.js/Sources/Rendering/OpenGL/TextureUnitManager';
import { VtkDataTypes }             from 'vtk.js/Sources/Common/Core/DataArray/Constants';

const { vtkDebugMacro, vtkErrorMacro } = macro;

// ----------------------------------------------------------------------------
// vtkOpenGLRenderWindow methods
// ----------------------------------------------------------------------------

function vtkOpenGLRenderWindow(publicAPI, model) {
  // Set our className
  model.classHierarchy.push('vtkOpenGLRenderWindow');

  // Auto update style
  function updateWindow() {
    // Canvas size
    if (model.renderable) {
      model.canvas.setAttribute('width', model.size[0]);
      model.canvas.setAttribute('height', model.size[1]);
    }
    // Offscreen ?
    model.canvas.style.display = model.useOffScreen ? 'none' : 'block';

    // Cursor type
    if (model.el) {
      model.el.style.cursor = model.cursorVisibility ? model.cursor : 'none';
    }
  }
  publicAPI.onModified(updateWindow);

  // Builds myself.
  publicAPI.buildPass = (prepass) => {
    if (prepass) {
      if (!model.renderable) {
        return;
      }

      publicAPI.prepareNodes();
      publicAPI.addMissingNodes(model.renderable.getRenderers());
      publicAPI.removeUnusedNodes();

      publicAPI.initialize();
      model.children.forEach((child) => {
        child.setContext(model.context);
      });
    }
  };

  publicAPI.initialize = () => {
    if (!model.initialized) {
      model.context = publicAPI.get3DContext();
      model.textureUnitManager = vtkOpenGLTextureUnitManager.newInstance();
      model.textureUnitManager.setContext(model.context);
      model.shaderCache.setContext(model.context);
      // initialize blending for transparency
      const gl = model.context;
      gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA,
                       gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
      gl.enable(gl.BLEND);
      model.initialized = true;
    }
  };

  publicAPI.makeCurrent = () => {
    model.context.makeCurrent();
  };

  publicAPI.setContainer = (el) => {
    if (model.el && model.el !== el) {
      // Remove canvas from previous container
      if (model.canvas.parentNode === model.el) {
        model.el.removeChild(model.canvas);
      } else {
        vtkErrorMacro('Error: canvas parent node does not match container');
      }
    }

    if (model.el !== el) {
      model.el = el;
      if (model.el) {
        model.el.appendChild(model.canvas);
      }

      // Trigger modified()
      publicAPI.modified();
    }
  };

  publicAPI.isInViewport = (x, y, viewport) => {
    const vCoords = viewport.getViewport();
    const size = model.size;
    if ((vCoords[0] * size[0] <= x) &&
        (vCoords[2] * size[0] >= x) &&
        (vCoords[1] * size[1] <= y) &&
        (vCoords[3] * size[1] >= y)) {
      return true;
    }
    return false;
  };

  publicAPI.getViewportSize = (viewport) => {
    const vCoords = viewport.getViewport();
    const size = model.size;
    return [(vCoords[2] - vCoords[0]) * size[0], (vCoords[3] - vCoords[1]) * size[1]];
  };

  publicAPI.getViewportCenter = (viewport) => {
    const size = publicAPI.getViewportSize(viewport);
    return [size[0] * 0.5, size[1] * 0.5];
  };

  publicAPI.displayToNormalizedDisplay = (x, y, z) =>
    [x / model.size[0], y / model.size[1], z];

  publicAPI.normalizedDisplayToDisplay = (x, y, z) =>
    [x * model.size[0], y * model.size[1], z];

  publicAPI.worldToView = (x, y, z, renderer) => {
    const dims = publicAPI.getViewportSize(renderer);
    return renderer.worldToView(x, y, z, dims[0] / dims[1]);
  };

  publicAPI.viewToWorld = (x, y, z, renderer) => {
    const dims = publicAPI.getViewportSize(renderer);
    return renderer.viewToWorld(x, y, z, dims[0] / dims[1]);
  };

  publicAPI.worldToDisplay = (x, y, z, renderer) => {
    const val = publicAPI.worldToView(x, y, z, renderer);
    const val2 = renderer.viewToNormalizedDisplay(val[0], val[1], val[2]);
    return publicAPI.normalizedDisplayToDisplay(val2[0], val2[1], val2[2]);
  };

  publicAPI.displayToWorld = (x, y, z, renderer) => {
    const val = publicAPI.displayToNormalizedDisplay(x, y, z);
    const val2 = renderer.normalizedDisplayToView(val[0], val[1], val[2]);
    return publicAPI.viewToWorld(val2[0], val2[1], val2[2], renderer);
  };

  publicAPI.getPixelData = (x1, y1, x2, y2) => {
    const pixels = new Uint8Array((x2 - x1 + 1) * (y2 - y1 + 1) * 4);
    model.context.readPixels(
      x1, y1, x2 - x1 + 1, y2 - y1 + 1,
      model.context.RGBA,
      model.context.UNSIGNED_BYTE,
      pixels);
    return pixels;
  };

  publicAPI.get2DContext = () => model.canvas.getContext('2d');

  publicAPI.get3DContext = (options = { preserveDrawingBuffer: false, depth: true, alpha: true }) => {
    let result = null;

    const webgl2Supported = (typeof WebGL2RenderingContext !== 'undefined');
    model.webgl2 = false;
    if (model.defaultToWebgl2 && webgl2Supported) {
      result = model.canvas.getContext('webgl2'); // , options);
      if (result) {
        model.webgl2 = true;
        vtkDebugMacro('using webgl2');
      }
    }
    if (!result) {
      result = model.canvas.getContext('webgl', options)
        || model.canvas.getContext('experimental-webgl', options);
    }
    return result;
  };

  publicAPI.activateTexture = (texture) => {
    // Only add if it isn't already there
    const result = model.textureResourceIds.get(texture);
    if (result !== undefined) {
      model.context.activeTexture(model.context.TEXTURE0 + result);
      return;
    }

    const activeUnit = publicAPI.getTextureUnitManager().allocate();
    if (activeUnit < 0) {
      vtkErrorMacro('Hardware does not support the number of textures defined.');
      return;
    }

    model.textureResourceIds.set(texture, activeUnit);
    model.context.activeTexture(model.context.TEXTURE0 + activeUnit);
  };

  publicAPI.deactivateTexture = (texture) => {
    // Only deactivate if it isn't already there
    const result = model.textureResourceIds.get(texture);
    if (result !== undefined) {
      publicAPI.getTextureUnitManager().free(result);
      delete model.textureResourceIds.delete(texture);
    }
  };

  publicAPI.getTextureUnitForTexture = (texture) => {
    const result = model.textureResourceIds.get(texture);
    if (result !== undefined) {
      return result;
    }
    return -1;
  };

  publicAPI.getDefaultTextureInternalFormat = (vtktype, numComps, useFloat) => {
    if (model.webgl2) {
      switch (vtktype) {
        case VtkDataTypes.UNSIGNED_CHAR:
          switch (numComps) {
            case 1: return model.context.R8;
            case 2: return model.context.RG8;
            case 3: return model.context.RGB8;
            case 4:
            default:
              return model.context.RGBA8;
          }
        default:
        case VtkDataTypes.FLOAT:
          switch (numComps) {
            case 1: return model.context.R16F;
            case 2: return model.context.RG16F;
            case 3: return model.context.RGB16F;
            case 4:
            default:
              return model.context.RGBA16F;
          }
      }
    }

    // webgl1 only supports four types
    switch (numComps) {
      case 1: return model.context.LUMINANCE;
      case 2: return model.context.LUMINANCE_ALPHA;
      case 3: return model.context.RGB;
      case 4:
      default:
        return model.context.RGBA;
    }
  };

  function getCanvasDataURL(format = 'image/png') {
    return model.canvas.toDataURL(format);
  }

  publicAPI.captureImage = (format = 'image/png') => {
    if (model.deleted) {
      return null;
    }

    publicAPI.traverseAllPasses();
    return getCanvasDataURL(format);
  };

  publicAPI.traverseAllPasses = () => {
    model.renderPasses.forEach((val) => {
      val.traverse(publicAPI, null);
    });
    if (model.notifyImageReady) {
      publicAPI.invokeImageReady(getCanvasDataURL());
    }
  };
}

// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------

const DEFAULT_VALUES = {
  shaderCache: null,
  initialized: false,
  context: null,
  canvas: null,
  size: [300, 300],
  cursorVisibility: true,
  cursor: 'pointer',
  textureUnitManager: null,
  textureResourceIds: null,
  renderPasses: [],
  notifyImageReady: false,
  webgl2: false,
  defaultToWebgl2: false, // turned off by default
};

// ----------------------------------------------------------------------------

export function extend(publicAPI, model, initialValues = {}) {
  Object.assign(model, DEFAULT_VALUES, initialValues);

  // Create internal instances
  model.canvas = document.createElement('canvas');

  model.textureResourceIds = new Map();

  // Inheritance
  vtkViewNode.extend(publicAPI, model, initialValues);

  model.myFactory = vtkOpenGLViewNodeFactory.newInstance();
  model.shaderCache = vtkShaderCache.newInstance();

  // setup default forward pass rendering
  model.renderPasses[0] = vtkForwardPass.newInstance();

  macro.event(publicAPI, model, 'imageReady');

  // on mac default to webgl2
  if (navigator.appVersion.indexOf('Mac') !== -1) {
    model.defaultToWebgl2 = true;
  }

  // Build VTK API
  macro.get(publicAPI, model, [
    'shaderCache',
    'textureUnitManager',
    'webgl2',
  ]);

  macro.setGet(publicAPI, model, [
    'initialized',
    'context',
    'canvas',
    'renderPasses',
    'notifyImageReady',
    'defaultToWebgl2',
  ]);

  macro.setGetArray(publicAPI, model, [
    'size',
  ], 2);

  // Object methods
  vtkOpenGLRenderWindow(publicAPI, model);
}

// ----------------------------------------------------------------------------

export const newInstance = macro.newInstance(extend, 'vtkOpenGLRenderWindow');

// ----------------------------------------------------------------------------

export default { newInstance, extend };
<|endoftext|>


<commit_before>module.exports = {

	/* APP CONFIG */
	APP_NAME: 'Campus Mobile',
	GOOGLE_ANALYTICS_ID: 'UA-XXXXXXXX-X',

	/* APIs / FEEDS */
	WEATHER_API_URL: 'https://w3wyps9yje.execute-api.us-west-2.amazonaws.com/prod/forecast?',
	SURF_API_URL: 'https://0yi5xwy0v7.execute-api.us-west-2.amazonaws.com/dev',
	SHUTTLE_STOPS_API_URL: 'https://ies4wyrlx9.execute-api.us-west-2.amazonaws.com/prod/v2/stops/',
	SHUTTLE_VEHICLES_API_URL: 'https://hjr84cay81.execute-api.us-west-2.amazonaws.com/prod?route=',
	DINING_API_URL: 'https://zbncpgqqj4.execute-api.us-west-2.amazonaws.com/dev/v2/dining-service',
	EVENTS_API_URL: 'https://2jjml3hf27.execute-api.us-west-2.amazonaws.com/prod/events/student',
	QUICKLINKS_API_URL: 'https://s3-us-west-2.amazonaws.com/ucsd-its-wts/now_ucsandiego/v1/quick_links/ucsd-quicklinks-v3.json',
	NEWS_API_URL: 'https://s3-us-west-2.amazonaws.com/ucsd-its-wts/now_ucsandiego/v1/allstories.json',
	MAP_SEARCH_API_URL: 'https://xgu9qa7gx4.execute-api.us-west-2.amazonaws.com/prod/v2/map/search?region=0&query=',
	SPECIAL_EVENT_API_URL: 'https://2jjml3hf27.execute-api.us-west-2.amazonaws.com/prod/events/special',

	/* RESOURCES */
	SHUTTLE_SCHEDULE_URL: 'https://transportation.ucsd.edu/shuttles/',
	FEEDBACK_URL: 'https://eforms.ucsd.edu/view.php?id=175631',
	NODE_MARKERS_BASE_URL: 'https://s3-us-west-2.amazonaws.com/ucsd-its-wts/now_ucsandiego/v1/nearby_markers/',
	WEATHER_ICON_BASE_URL: 'https://s3-us-west-2.amazonaws.com/ucsd-its-wts/images/v1/weather-icons/',
	SHUTTLE_ROUTES_MASTER: 'https://s3-us-west-2.amazonaws.com/ucsd-its-wts/now_ucsandiego/v1/shuttle_routes_master_map.json',
	SHUTTLE_STOPS_MASTER: 'https://s3-us-west-2.amazonaws.com/ucsd-its-wts/now_ucsandiego/v1/shuttle_stops_master_map.json',
	SHUTTLE_STOPS_MASTER_NO_ROUTES: 'https://s3-us-west-2.amazonaws.com/ucsd-its-wts/now_ucsandiego/v1/shuttle_stops_master_map_no_routes.json',

	/* TTLs */
	WEATHER_API_TTL: 1800000, // 30 minutes
	SURF_API_TTL: 1800000, // 30 minutes
	EVENTS_API_TTL: 3600000, // 1 hour
	NEWS_API_TTL: 3600000, // 1 hour
	DINING_API_TTL: 3600000, // 1 hour
	DINING_MENU_API_TTL: 60000, // 1 minute
	QUICKLINKS_API_TTL: 86400000, // 1 day
	SHUTTLE_API_TTL: 6000, // 6 seconds
	SHUTTLE_MASTER_TTL: 86400000, // 1 day
	SPECIAL_EVENTS_TTL: 3600000, // 1 hour
	DATA_SAGA_TTL: 60000, // 1 minute
	FEEDBACK_POST_TTL: 10000, // 10 seconds

	USER_LOGIN: {
		ENABLED: false,
		METHOD: 'openid',
		OPTIONS: {
			CLIENT_ID: 'campusimplicit',
			AUTH_URL: 'https://auth-dev.ucdavis.edu/identity/connect/authorize',
			USER_INFO_URL: 'https://auth-dev.ucdavis.edu/identity/connect/userinfo',
			REDIRECT_URL: 'campusmobile://cb',
			STATE: 'M9NGbE6bnUV18FflfVeZ2U0j94'
		}
	}
};
<commit_msg>Update dining menu ttl<commit_after>module.exports = {

	/* APP CONFIG */
	APP_NAME: 'Campus Mobile',
	GOOGLE_ANALYTICS_ID: 'UA-XXXXXXXX-X',

	/* APIs / FEEDS */
	WEATHER_API_URL: 'https://w3wyps9yje.execute-api.us-west-2.amazonaws.com/prod/forecast?',
	SURF_API_URL: 'https://0yi5xwy0v7.execute-api.us-west-2.amazonaws.com/dev',
	SHUTTLE_STOPS_API_URL: 'https://ies4wyrlx9.execute-api.us-west-2.amazonaws.com/prod/v2/stops/',
	SHUTTLE_VEHICLES_API_URL: 'https://hjr84cay81.execute-api.us-west-2.amazonaws.com/prod?route=',
	DINING_API_URL: 'https://zbncpgqqj4.execute-api.us-west-2.amazonaws.com/dev/v2/dining-service',
	EVENTS_API_URL: 'https://2jjml3hf27.execute-api.us-west-2.amazonaws.com/prod/events/student',
	QUICKLINKS_API_URL: 'https://s3-us-west-2.amazonaws.com/ucsd-its-wts/now_ucsandiego/v1/quick_links/ucsd-quicklinks-v3.json',
	NEWS_API_URL: 'https://s3-us-west-2.amazonaws.com/ucsd-its-wts/now_ucsandiego/v1/allstories.json',
	MAP_SEARCH_API_URL: 'https://xgu9qa7gx4.execute-api.us-west-2.amazonaws.com/prod/v2/map/search?region=0&query=',
	SPECIAL_EVENT_API_URL: 'https://2jjml3hf27.execute-api.us-west-2.amazonaws.com/prod/events/special',

	/* RESOURCES */
	SHUTTLE_SCHEDULE_URL: 'https://transportation.ucsd.edu/shuttles/',
	FEEDBACK_URL: 'https://eforms.ucsd.edu/view.php?id=175631',
	NODE_MARKERS_BASE_URL: 'https://s3-us-west-2.amazonaws.com/ucsd-its-wts/now_ucsandiego/v1/nearby_markers/',
	WEATHER_ICON_BASE_URL: 'https://s3-us-west-2.amazonaws.com/ucsd-its-wts/images/v1/weather-icons/',
	SHUTTLE_ROUTES_MASTER: 'https://s3-us-west-2.amazonaws.com/ucsd-its-wts/now_ucsandiego/v1/shuttle_routes_master_map.json',
	SHUTTLE_STOPS_MASTER: 'https://s3-us-west-2.amazonaws.com/ucsd-its-wts/now_ucsandiego/v1/shuttle_stops_master_map.json',
	SHUTTLE_STOPS_MASTER_NO_ROUTES: 'https://s3-us-west-2.amazonaws.com/ucsd-its-wts/now_ucsandiego/v1/shuttle_stops_master_map_no_routes.json',

	/* TTLs */
	WEATHER_API_TTL: 1800000, // 30 minutes
	SURF_API_TTL: 1800000, // 30 minutes
	EVENTS_API_TTL: 3600000, // 1 hour
	NEWS_API_TTL: 3600000, // 1 hour
	DINING_API_TTL: 3600000, // 1 hour
	DINING_MENU_API_TTL: 3600000, // 1 hour
	QUICKLINKS_API_TTL: 86400000, // 1 day
	SHUTTLE_API_TTL: 6000, // 6 seconds
	SHUTTLE_MASTER_TTL: 86400000, // 1 day
	SPECIAL_EVENTS_TTL: 3600000, // 1 hour
	DATA_SAGA_TTL: 60000, // 1 minute
	FEEDBACK_POST_TTL: 10000, // 10 seconds

	USER_LOGIN: {
		ENABLED: false,
		METHOD: 'openid',
		OPTIONS: {
			CLIENT_ID: 'campusimplicit',
			AUTH_URL: 'https://auth-dev.ucdavis.edu/identity/connect/authorize',
			USER_INFO_URL: 'https://auth-dev.ucdavis.edu/identity/connect/userinfo',
			REDIRECT_URL: 'campusmobile://cb',
			STATE: 'M9NGbE6bnUV18FflfVeZ2U0j94'
		}
	}
};
<|endoftext|>


<commit_before>/*
* When on the webworks site, tries to figure out
* what page it is on in order to decide which script
* to inject
*
*
* note: "p" in the courses object is short for "problems", and
* "a" is short for "average" - single letters are used to reduce
* space in storage.sync (courses object has a size cap of 8kb)
*/

// because chrome.tabs.getCurrent(function(tab) can only be run from background pages, use window.location.href instead
var url = window.location.href;

// get the CLASS, ASSIGNMENT, and PROBLEM that WeBWorK is currently on
var CLASS, ASSIGNMENT, PROBLEM;
var captured = /math\.webwork\.rochester\.edu\/webwork2(\/(\w+))?(\/(\w+))?(\/(\w+))?/.exec(url);
try {   // if the main directory isn't "webwork2", then throw error (not on the WeBWorK website)
CLASS  = captured[2];
ASSIGNMENT = captured[4];
PROBLEM = captured[6];
} catch (e) {
  // fail silently - this block is here mainly because I don't want a huge chain of "if-else"s
}

var courses, preferences;

if (ASSIGNMENT !== "hardcopy" && ASSIGNMENT !== "options") {

  /*
  * load the courses object from background.js
  */
  chrome.runtime.sendMessage({greeting:"requestAll"}, function (reply) {

    // check that the message was successfully received
    var lastError = chrome.runtime.lastError;
    if (lastError) {
      console.log(lastError.message);
      return;
    }

    // initialize these objects with their values from storage
    courses = reply.courses;
    preferences = reply.preferences;

    // add the preferences to the body
    var script = document.createElement('script');
    script.textContent = "var preferences="+JSON.stringify(preferences)+";";
    (document.head||document.documentElement).appendChild(script);
    script.parentNode.removeChild(script);

    // do some error checking for new users (who won't have a defined course variable in storage)
    if (courses === null | courses === undefined)
    courses = {};

    // add the class to the courses object if it isn't already there
    if (CLASS) {
      if (courses[CLASS] === undefined) {
        courses[CLASS] = {};
      }
    }

    // change the lastclass preference to this class if they are different
    if (preferences.lastclass === undefined || (preferences.lastclass !== CLASS && CLASS !== undefined)) {
      preferences.lastclass = CLASS;

      // update background.js preferences info
      chrome.runtime.sendMessage({greeting:"updatePreferences", information:preferences}, function (reply) {
        if (lastError) {
          console.log(lastError.message);
          return;
        }
      });
    }

    // if the courses object was updated (we'll track that with this variable), save the changes
    var updateCourses = false;

    /*
    * Add all necessary elements to each input box.
    * Previously, this was done using jQuery in the
    * beginning of the problems.js file
    */
    if (PROBLEM) {

      // get all input boxes
      var inputs = document.querySelectorAll("input.codeshard");

      for (var i = 0; i < inputs.length; i++) {
        // cache id
        var id = inputs[i].getAttribute("id");
        // set minimum width to equal initial width
        inputs[i].style.minWidth = getComputedStyle(inputs[i])["width"];
        // create container for input boxes
        var container = document.createElement("div");
        container.setAttribute("class", "input-container");
        // add MathJax preview box
        container.innerHTML = '

';

        // add temporary element (future location of the input tag)
        var tempAnchor = document.createElement("a")
        container.appendChild(tempAnchor);
        // create highlight div
        var highlight = document.createElement("div")
        highlight.setAttribute("class", "highlight")
        highlight.setAttribute("id", id+"highlight");
        // set min-width
        highlight.style.minWidth = getComputedStyle(inputs[i])["width"];
        // append highlight div to container
        container.appendChild(highlight);
        // create errors div
        var errors = document.createElement("div")
        errors.setAttribute("class", "errors")
        errors.setAttribute("id", id+"errors");
        // append error div to container
        container.appendChild(errors);

        // add note container div information (ONLY IF NOTES ARE ENABLED)
        if (preferences.notes) {
          container.innerHTML += '

';
        }

        // add container to page
        inputs[i].parentNode.replaceChild(container, inputs[i]);
        // add input box to container
        container.replaceChild(inputs[i], container.getElementsByTagName("a")[0]);

      }

      /*
      * Get the notes for that problem from storage
      *
      * parameters correspond to problem number
      *
      * 15fallmath150 {
      *    1: "Blah blah"
      *    3: "More notes"
      *    7: "Even more notes.  Ain't life wonderful?"
      * }
      *
      */
      if (preferences.notes) {
        var noteName = CLASS+"_"+ASSIGNMENT+"_"+PROBLEM+"_notes";
        var notes;
        chrome.storage.sync.get(noteName, function(items) {
          var lastError = chrome.runtime.lastError;
          if (lastError) {
            console.log(lastError.message);
            return;
          }
          if (items[noteName] === undefined) { // no notes for that page
            notes = {};
          } else { // at least one note
            notes = items[noteName];
          }

          // add event listener to note-adder
          var adders = document.getElementsByClassName("note-adder");
          for (var i = 0; i < adders.length; i++) {
            // add note contents if they exist
            if (notes !== undefined) {
              if  (notes[i+1] !== undefined) { // add note content to the corresponding div
                adders[i].nextSibling.getElementsByClassName("body")[0].innerText = notes[i+1];
                adders[i].parentNode.parentNode.className += " has-note"; // input and adder button yellow if it already has a note
              }
            }

            // add event listeners
            adders[i].addEventListener("click", showNote, false); // show note
            adders[i].nextSibling.getElementsByClassName("note-xmark")[0].addEventListener("click", hideNote, false); // hide note
          }

          function showNote() {
            this.nextSibling.style.display = "inline-block"; // show note
            this.style.display = "none"; // hide "note-adder"
          }

          function hideNote() {
            this.parentNode.style.display = "none"; // hide "note"

            var thisContainer = this.parentNode.parentNode.parentNode;
            var thisAdder = this.parentNode.previousSibling;
            thisAdder.style.display = "none"; // show "note-adder"

            // problem# + "hidenote"
            var problemNumber = this.id.substr(0, this.id.length-8);

            var noteText = this.parentNode.getElementsByClassName("body")[0].innerText;

            // TODO: edge case where notes[n] is null and noteText = ""
            if (notes[problemNumber] !== noteText) {
              // if note is empty, reset to undefined
              if (noteText === "") {
                delete notes[problemNumber];
                // remove coloring from corresponding container div
                thisContainer.className = thisContainer.className.replace(/(?:^|\s)has-note(?!\S)/g , '')
              } else {
                // color in
                thisContainer.className += " has-note"; // color yellow for existing notes
                // save note
                notes[problemNumber] = noteText;
              }

              // if notes is empty, delete from storage as well
              if (Object.keys(notes).length === 0) {
                chrome.storage.sync.remove([noteName], function() {
                });
              } else { // save to storage
                chrome.storage.sync.set({[noteName]: notes}, function() {
                });
              }

            }

          }

        }); // notes get

      } // preferences.notes end

    }

    if (PROBLEM && courses[CLASS][ASSIGNMENT]["a"] < 100) {

      // check the "you got x% right" at the bottom, update the corresponding problems array index if different
      var percentage = /is \d+%/.exec(document.getElementsByClassName("scoreSummary")[0].children[0].innerText);

      // problems that have not yet been attempted don't display the percentage of questions answered correctly
      if (percentage !== null) {
        percentage = parseInt(percentage[0].replace(/\D/g, ""));

        // compare to the percentage in the courses object.  Use the ABS thing because the page rounds to the whole number, not down
        if (Math.abs(courses[CLASS][ASSIGNMENT]["p"][PROBLEM-1] - percentage) > 1) {
          courses[CLASS][ASSIGNMENT]["p"][PROBLEM-1] = percentage;

          // recalculate average
          var avg = 0;
          for (var i = 0; i < courses[CLASS][ASSIGNMENT]["p"].length; i++) {
            avg += courses[CLASS][ASSIGNMENT]["p"][i];
          }
          // update average
          courses[CLASS][ASSIGNMENT]["a"] = Math.floor(avg/courses[CLASS][ASSIGNMENT]["p"].length);

          // if average = 100, then delete the problems array
          if (courses[CLASS][ASSIGNMENT]["a"] === 100) {
            delete courses[CLASS][ASSIGNMENT]["p"];
          }
          updateCourses = true;

        }
      }

    } else if (ASSIGNMENT) {
      // add the problem list to the assignment
      var tableRows = document.getElementsByClassName("problem_set_table")[0];

      // check if the element actually exists (ex. doesn't exist if the user has an expired session)
      if (tableRows !== undefined) {

        tableRows = tableRows.children[1].children;

        // check if the assignment even exists (same code as below)
        if (courses[CLASS][ASSIGNMENT] === undefined) {
          courses[CLASS][ASSIGNMENT] = {
            "p": [],  // one-indexed array where the key is the percentage completed of a problem (index is the problem name)
            "a": 0  // average of all the values inside of the problems [] array
          };
          updateCourses = true;
        }

        if (courses[CLASS][ASSIGNMENT]["a"] < 100) { // don't execute if the assignment is 100% complete

        var problem_array = [];
        var total = 0;
        // fill out the problem array with the correct values
        for (var i = 1; i < tableRows.length; i++) { // skip the first row (header)
          // get the completion percentage
          var percentage = parseInt(tableRows[i].children[4].innerText, 10);
          total += percentage;
          // update the assignment's percentage array
          problem_array.push(percentage);
        }
        // check if there are any differences between the two arrays; if there are, then update the courses object with the new array
        if (problem_array.length !== courses[CLASS][ASSIGNMENT]["p"].length) {
          courses[CLASS][ASSIGNMENT]["p"] = problem_array;
          courses[CLASS][ASSIGNMENT]["a"] = Math.floor(total / problem_array.length);
          updateCourses = true;
        } else {
          for (var i = 0; i < problem_array.length; i++) {
            if (problem_array[i] !== courses[CLASS][ASSIGNMENT]["p"][i]) {
              courses[CLASS][ASSIGNMENT]["p"] = problem_array;
              courses[CLASS][ASSIGNMENT]["a"] = Math.floor(total / problem_array.length);
              updateCourses = true;
              break;
            }
          }
        }
      }
    }

  } else if (CLASS) {

    // add the assignment list to the options
    var tableRows = document.getElementsByClassName("problem_set_table")[0];

    // check if the element actually exists (ex. doesn't exist if the user has an expired session)
    if (tableRows !== undefined) {
      tableRows = tableRows.children[1].children;

      for (var i = 1; i < tableRows.length; i++) { // skip the first row (header)
        // get the assignent name (replace spaces with underscores)
        var assignmentName = tableRows[i].children[1].innerText.replace(/ /g, "_");

        // if the assignment doesn't exist in the courses object, add it
        if (courses[CLASS][assignmentName] === undefined) {
          courses[CLASS][assignmentName] = {
            "p": [],  // one-indexed array where the key is the percentage completed of a problem (index is the problem name)
            "a": 0  // average of all the values inside of the problems [] array
          };
          updateCourses = true;
        } else {

          // only give a percentage if the course has problems in it
          // if the average is 100, then the array doesn't exist
          if (courses[CLASS][assignmentName]["a"] === 100) {
            if (courses[CLASS][assignmentName]["p"] !== undefined) {
              delete courses[CLASS][assignmentName]["p"]; // delete problems array, we already know each problem is 100% complete
              updateCourses = true;
            }
            tableRows[i].children[2].innerHTML += '100';

          } else if (courses[CLASS][assignmentName]["p"].length > 0) {
            // choose the class depending on the percentage
            var className;

            if (courses[CLASS][assignmentName]["a"] < 70) {
              className = "WWdanger";
            } else if (courses[CLASS][assignmentName]["a"] < 100) {
              className = "WWwarning";
            }
            tableRows[i].children[2].innerHTML += '' +courses[CLASS][assignmentName]["a"]+'';
          }
        }

      }
    }
  }

  // if changes were made to the "courses" object, save them to storage.sync
  if (updateCourses) {

    // send updated courses to background.js
    chrome.runtime.sendMessage({greeting:"updateCourses", information:courses}, function (reply) {
      if (lastError) {
        console.log(lastError.message);
        return;
      }
    });
  }

  /*
  * Create the script in preparation for injection
  */

  var s = document.createElement('script');
  if (PROBLEM) {
    s.src = chrome.extension.getURL('problem.js'); // for answer previews and input expanding

  } else if (ASSIGNMENT) {
    s.src = chrome.extension.getURL('assignment.js'); // for showing how much is completed

  } else if (CLASS) {
    s.src = chrome.extension.getURL('class.js'); // for showing due dates
  }
  // remove from DOM when loaded as security precaution
  s.onload = function () {
    this.parentNode.removeChild(this);
  };
  (document.head || document.documentElement).appendChild(s);

}); // end of requestAll

}
<commit_msg>Notes now work properly for WeBWorK matrices<commit_after>/*
* When on the webworks site, tries to figure out
* what page it is on in order to decide which script
* to inject
*
*
* note: "p" in the courses object is short for "problems", and
* "a" is short for "average" - single letters are used to reduce
* space in storage.sync (courses object has a size cap of 8kb)
*/

// because chrome.tabs.getCurrent(function(tab) can only be run from background pages, use window.location.href instead
var url = window.location.href;

// get the CLASS, ASSIGNMENT, and PROBLEM that WeBWorK is currently on
var CLASS, ASSIGNMENT, PROBLEM;
var captured = /math\.webwork\.rochester\.edu\/webwork2(\/(\w+))?(\/(\w+))?(\/(\w+))?/.exec(url);
try {   // if the main directory isn't "webwork2", then throw error (not on the WeBWorK website)
CLASS  = captured[2];
ASSIGNMENT = captured[4];
PROBLEM = captured[6];
} catch (e) {
  // fail silently - this block is here mainly because I don't want a huge chain of "if-else"s
}

var courses, preferences;

if (ASSIGNMENT !== "hardcopy" && ASSIGNMENT !== "options") {

  /*
  * load the courses object from background.js
  */
  chrome.runtime.sendMessage({greeting:"requestAll"}, function (reply) {

    // check that the message was successfully received
    var lastError = chrome.runtime.lastError;
    if (lastError) {
      console.log(lastError.message);
      return;
    }

    // initialize these objects with their values from storage
    courses = reply.courses;
    preferences = reply.preferences;

    // add the preferences to the body
    var script = document.createElement('script');
    script.textContent = "var preferences="+JSON.stringify(preferences)+";";
    (document.head||document.documentElement).appendChild(script);
    script.parentNode.removeChild(script);

    // do some error checking for new users (who won't have a defined course variable in storage)
    if (courses === null | courses === undefined)
    courses = {};

    // add the class to the courses object if it isn't already there
    if (CLASS) {
      if (courses[CLASS] === undefined) {
        courses[CLASS] = {};
      }
    }

    // change the lastclass preference to this class if they are different
    if (preferences.lastclass === undefined || (preferences.lastclass !== CLASS && CLASS !== undefined)) {
      preferences.lastclass = CLASS;

      // update background.js preferences info
      chrome.runtime.sendMessage({greeting:"updatePreferences", information:preferences}, function (reply) {
        if (lastError) {
          console.log(lastError.message);
          return;
        }
      });
    }

    // if the courses object was updated (we'll track that with this variable), save the changes
    var updateCourses = false;

    /*
    * Add all necessary elements to each input box.
    * Previously, this was done using jQuery in the
    * beginning of the problems.js file
    */
    if (PROBLEM) {

      // get all input boxes
      var inputs = document.querySelectorAll("input.codeshard");

      for (var i = 0; i < inputs.length; i++) {
        // cache id
        var id = inputs[i].getAttribute("id");
        // set minimum width to equal initial width
        inputs[i].style.minWidth = getComputedStyle(inputs[i])["width"];
        // create container for input boxes
        var container = document.createElement("div");
        container.setAttribute("class", "input-container");
        // add MathJax preview box
        container.innerHTML = '

';

        // add temporary element (future location of the input tag)
        var tempAnchor = document.createElement("a")
        container.appendChild(tempAnchor);
        // create highlight div
        var highlight = document.createElement("div")
        highlight.setAttribute("class", "highlight")
        highlight.setAttribute("id", id+"highlight");
        // set min-width
        highlight.style.minWidth = getComputedStyle(inputs[i])["width"];
        // append highlight div to container
        container.appendChild(highlight);
        // create errors div
        var errors = document.createElement("div")
        errors.setAttribute("class", "errors")
        errors.setAttribute("id", id+"errors");
        // append error div to container
        container.appendChild(errors);

        // add note container div information (ONLY IF NOTES ARE ENABLED)
        if (preferences.notes) {
            var noteID = (/([\d|_]{4,})/g).exec(id)[1]; // note ID is the numerical/underscore part of the input box ID
            noteID = noteID.replace(/^0+/, ""); // remove leading zeroes

          container.innerHTML += '

';
        }

        // add container to page
        inputs[i].parentNode.replaceChild(container, inputs[i]);
        // add input box to container
        container.replaceChild(inputs[i], container.getElementsByTagName("a")[0]);

      }

      /*
      * Get the notes for that problem from storage
      *
      * parameters correspond to problem number
      *
      * 15fallmath150 {
      *    1: "Blah blah"
      *    3: "More notes"
      *    7: "Even more notes.  Ain't life wonderful?"
      * }
      *
      */
      if (preferences.notes) {
        var noteName = CLASS+"_"+ASSIGNMENT+"_"+PROBLEM+"_notes";
        var notes;
        chrome.storage.sync.get(noteName, function(items) {
          var lastError = chrome.runtime.lastError;
          if (lastError) {
            console.log(lastError.message);
            return;
          }
          if (items[noteName] === undefined) { // no notes for that page
            notes = {};
          } else { // at least one note
            notes = items[noteName];
            console.log(noteName);
            console.log(notes);
          }

          // add event listener to note-adder
          var adders = document.getElementsByClassName("note-adder");
          for (var i = 0; i < adders.length; i++) { // iterate over them and check if there is a matching note
            // add note contents if they exist
            if (notes !== undefined) {
                // get id and see if it matches
                var xmarkID = adders[i].nextSibling.getElementsByClassName("note-xmark")[0].id;
                xmarkID = xmarkID.substring(0, xmarkID.length-8);
                console.log(xmarkID);

              if (notes[xmarkID] !== undefined) { // add note content to the corresponding div
                adders[i].nextSibling.getElementsByClassName("body")[0].innerText = notes[xmarkID];
                adders[i].parentNode.parentNode.className += " has-note"; // input and adder button yellow if it already has a note
              }
            }

            // add event listeners
            adders[i].addEventListener("click", showNote, false); // show note
            adders[i].nextSibling.getElementsByClassName("note-xmark")[0].addEventListener("click", hideNote, false); // hide note
          }

          function showNote() {
            this.nextSibling.style.display = "inline-block"; // show note
            this.style.display = "none"; // hide "note-adder"
          }

          function hideNote() {
            this.parentNode.style.display = "none"; // hide "note"

            var thisContainer = this.parentNode.parentNode.parentNode;
            var thisAdder = this.parentNode.previousSibling;
            thisAdder.style.display = "none"; // show "note-adder"

            // problem# + "hidenote"
            var problemNumber = this.id.substr(0, this.id.length-8);

            var noteText = this.parentNode.getElementsByClassName("body")[0].innerText;

            // TODO: edge case where notes[n] is null and noteText = ""
            if (notes[problemNumber] !== noteText) {
              // if note is empty, reset to undefined
              if (noteText === "") {
                delete notes[problemNumber];
                // remove coloring from corresponding container div
                thisContainer.className = thisContainer.className.replace(/(?:^|\s)has-note(?!\S)/g , '')
              } else {
                // color in
                thisContainer.className += " has-note"; // color yellow for existing notes
                // save note
                notes[problemNumber] = noteText;
              }

              // if notes is empty, delete from storage as well
              if (Object.keys(notes).length === 0) {
                chrome.storage.sync.remove([noteName], function() {
                });
              } else { // save to storage
                chrome.storage.sync.set({[noteName]: notes}, function() {
                });
              }

            }

          }

        }); // notes get

      } // preferences.notes end

    }

    if (PROBLEM && courses[CLASS][ASSIGNMENT]["a"] < 100) {

      // check the "you got x% right" at the bottom, update the corresponding problems array index if different
      var percentage = /is \d+%/.exec(document.getElementsByClassName("scoreSummary")[0].children[0].innerText);

      // problems that have not yet been attempted don't display the percentage of questions answered correctly
      if (percentage !== null) {
        percentage = parseInt(percentage[0].replace(/\D/g, ""));

        // compare to the percentage in the courses object.  Use the ABS thing because the page rounds to the whole number, not down
        if (Math.abs(courses[CLASS][ASSIGNMENT]["p"][PROBLEM-1] - percentage) > 1) {
          courses[CLASS][ASSIGNMENT]["p"][PROBLEM-1] = percentage;

          // recalculate average
          var avg = 0;
          for (var i = 0; i < courses[CLASS][ASSIGNMENT]["p"].length; i++) {
            avg += courses[CLASS][ASSIGNMENT]["p"][i];
          }
          // update average
          courses[CLASS][ASSIGNMENT]["a"] = Math.floor(avg/courses[CLASS][ASSIGNMENT]["p"].length);

          // if average = 100, then delete the problems array
          if (courses[CLASS][ASSIGNMENT]["a"] === 100) {
            delete courses[CLASS][ASSIGNMENT]["p"];
          }
          updateCourses = true;

        }
      }

    } else if (ASSIGNMENT) {
      // add the problem list to the assignment
      var tableRows = document.getElementsByClassName("problem_set_table")[0];

      // check if the element actually exists (ex. doesn't exist if the user has an expired session)
      if (tableRows !== undefined) {

        tableRows = tableRows.children[1].children;

        // check if the assignment even exists (same code as below)
        if (courses[CLASS][ASSIGNMENT] === undefined) {
          courses[CLASS][ASSIGNMENT] = {
            "p": [],  // one-indexed array where the key is the percentage completed of a problem (index is the problem name)
            "a": 0  // average of all the values inside of the problems [] array
          };
          updateCourses = true;
        }

        if (courses[CLASS][ASSIGNMENT]["a"] < 100) { // don't execute if the assignment is 100% complete

        var problem_array = [];
        var total = 0;
        // fill out the problem array with the correct values
        for (var i = 1; i < tableRows.length; i++) { // skip the first row (header)
          // get the completion percentage
          var percentage = parseInt(tableRows[i].children[4].innerText, 10);
          total += percentage;
          // update the assignment's percentage array
          problem_array.push(percentage);
        }
        // check if there are any differences between the two arrays; if there are, then update the courses object with the new array
        if (problem_array.length !== courses[CLASS][ASSIGNMENT]["p"].length) {
          courses[CLASS][ASSIGNMENT]["p"] = problem_array;
          courses[CLASS][ASSIGNMENT]["a"] = Math.floor(total / problem_array.length);
          updateCourses = true;
        } else {
          for (var i = 0; i < problem_array.length; i++) {
            if (problem_array[i] !== courses[CLASS][ASSIGNMENT]["p"][i]) {
              courses[CLASS][ASSIGNMENT]["p"] = problem_array;
              courses[CLASS][ASSIGNMENT]["a"] = Math.floor(total / problem_array.length);
              updateCourses = true;
              break;
            }
          }
        }
      }
    }

  } else if (CLASS) {

    // add the assignment list to the options
    var tableRows = document.getElementsByClassName("problem_set_table")[0];

    // check if the element actually exists (ex. doesn't exist if the user has an expired session)
    if (tableRows !== undefined) {
      tableRows = tableRows.children[1].children;

      for (var i = 1; i < tableRows.length; i++) { // skip the first row (header)
        // get the assignent name (replace spaces with underscores)
        var assignmentName = tableRows[i].children[1].innerText.replace(/ /g, "_");

        // if the assignment doesn't exist in the courses object, add it
        if (courses[CLASS][assignmentName] === undefined) {
          courses[CLASS][assignmentName] = {
            "p": [],  // one-indexed array where the key is the percentage completed of a problem (index is the problem name)
            "a": 0  // average of all the values inside of the problems [] array
          };
          updateCourses = true;
        } else {

          // only give a percentage if the course has problems in it
          // if the average is 100, then the array doesn't exist
          if (courses[CLASS][assignmentName]["a"] === 100) {
            if (courses[CLASS][assignmentName]["p"] !== undefined) {
              delete courses[CLASS][assignmentName]["p"]; // delete problems array, we already know each problem is 100% complete
              updateCourses = true;
            }
            tableRows[i].children[2].innerHTML += '100';

          } else if (courses[CLASS][assignmentName]["p"].length > 0) {
            // choose the class depending on the percentage
            var className;

            if (courses[CLASS][assignmentName]["a"] < 70) {
              className = "WWdanger";
            } else if (courses[CLASS][assignmentName]["a"] < 100) {
              className = "WWwarning";
            }
            tableRows[i].children[2].innerHTML += '' +courses[CLASS][assignmentName]["a"]+'';
          }
        }

      }
    }
  }

  // if changes were made to the "courses" object, save them to storage.sync
  if (updateCourses) {

    // send updated courses to background.js
    chrome.runtime.sendMessage({greeting:"updateCourses", information:courses}, function (reply) {
      if (lastError) {
        console.log(lastError.message);
        return;
      }
    });
  }

  /*
  * Create the script in preparation for injection
  */

  var s = document.createElement('script');
  if (PROBLEM) {
    s.src = chrome.extension.getURL('problem.js'); // for answer previews and input expanding

  } else if (ASSIGNMENT) {
    s.src = chrome.extension.getURL('assignment.js'); // for showing how much is completed

  } else if (CLASS) {
    s.src = chrome.extension.getURL('class.js'); // for showing due dates
  }
  // remove from DOM when loaded as security precaution
  s.onload = function () {
    this.parentNode.removeChild(this);
  };
  (document.head || document.documentElement).appendChild(s);

}); // end of requestAll

}
<|endoftext|>