<commit_before>/*
 * Developed by Radu Puspana
 * Date August 2017
 * Version 1.0
 */

// module that handles the budget data using the module pattern
// this controller keeps track of all the income, expenses, the budget itself, and
// also the percentage of how much an income/expense represents of the total budget
var budgetController = (function() {

    // private Expense constructor
    var prvExpense = function(id, description, value) {
       this.id = id;
       this.description = description;
       this.value = value;
    };

    // private Income constructor
    var prvIncome = function(id, description, value) {
        this.id = id;
        this.description = description;
        this.value = value;
    };

    // object for storing instances of prvExpense, prvIncome, totalExpenses, totalIncomes
    // every expense entered in the UI will map to an instance of prvExpense
    // every income entered in the UI will map to an instance of prvIncome
    var prvData = {
        allItems: {
            exp: [],
            inc: []
        },
        totals: {
            totalExpenses: 0,
            totalIncomes: 0
        }
    };

    return {

        // pubic method for creating a new Expense or Income instance based on user input from the UI,
        // add it to the exp or inc array of prvData.allItems, and return the new instance created
        pblAddItem: function(type, descripton, value) {

            // new reference to a new intance of prvExpense or prvIncome
            var newItem;

            // create unique id to put in each prvExpense or prvIncome item
            // id = last element of prvData.allItems[type] + 1
            var id = prvData.allItems[type][prvData.allItems[type].length - 1].id + 1;

            // create new instance of prvExpense or prvIncome based on the type parameter
            if(type === "exp") {
                newItem = new prvExpense(id, descripton, value);
            } else if (type === "inc") {
                newItem = new prvIncome(id, descripton, value);
            }

            // object[property]
            // add expense/income to the prvData.allItems[exp] or prvData.allItems[inc] array
            // based on the type parameter
            data.allItems[type].push(newItem);

            // return new instance of prvExpense or prvIncome
            return newItem;
        }
    }

})();

// UI module manipulates the UI of the app
var uiController = (function() {

    // private object containing the class names used in index.html and style.css
    var prvDOMstrings = {
        inputType: ".add__type",
        inputDescription: ".add__description",
        inputValue: ".add__value",
        inputButton: ".add__btn"};

    return {
        // public method to retrieve and return all three field values as strings from the UI
        pblGetInput: function() {

            // return an object with all three fields values as strings from the UI
            return {
                // return "inc" or "exp" from the transaction type list
                type: document.querySelector(prvDOMstrings.inputType).value,

                // return the transaction description as string
                description: document.querySelector(prvDOMstrings.inputDescription).value,

                // return the transaction value as a string
                value: document.querySelector(prvDOMstrings.inputValue).value
            };
        },

        // public method for returning the object containing the class names
        // in the index.html and style.css
        pblGetDOMstrings: function() {
            return prvDOMstrings;
        }
    }

})();

// App controller for communicating between the budgetController and the UIconroller
var controller = (function(budgetCtrl, UIctrl) {

    // private function to place the event listeners and the HTML tags' classes
    var prvSetupEventListeners = function() {

        // object containing the class names in the index.html and style.css
        var DOMstrings = uiController.pblGetDOMstrings();

        // register click event for the button with the tick sign
        document.querySelector(DOMstrings.inputButton).addEventListener("click", prvCtrlAddItem, false);

        // register Enter keypress event for the global object. Used only for the ENTER key
        document.getElementById("enterSum").addEventListener("keypress", function(event) {

            // use event.which to assure comptatibility with IE 9..11, Edge 14, UC Browser for Android 11.4
            // code 13 is returned when the "ENTER" key is pressed
            if (event.key === "Enter" || event.which === 13) { prvCtrlAddItem(); }

        }, false);
    };

    // private function for :
    // - retrieving all three user input field values
    var prvCtrlAddItem = function() {

        // get the field input data(expense or income)
        var userInput = uiController.pblGetInput();
        console.log(userInput);

        // add the item to the budget controller

        // add the new item to the UI

        // update the budget taking into account the expense/budget just entered

        // display the newly calculated budget on the UI

        console.log("You pressed enter and an item will be added to one of the tables and the budget will be updated")
    };

    return {
        initialiseVarsAndEvents: function() {
            console.log("App has started.");
            prvSetupEventListeners();
        }
    }

})(budgetController, uiController);

// Global execution scope
controller.initialiseVarsAndEvents();
<commit_msg>controller-Call the budgetController.pblAddItem and store it's return value in a var. budgetCotroller-Add a test method that logs to the console the prvData.allItems object<commit_after>/*
 * Developed by Radu Puspana
 * Date August 2017
 * Version 1.0
 */

// module that handles the budget data using the module pattern
// this controller keeps track of all the income, expenses, the budget itself, and
// also the percentage of how much an income/expense represents of the total budget
var budgetController = (function() {

    // private Expense constructor
    var prvExpense = function(id, description, value) {
       this.id = id;
       this.description = description;
       this.value = value;
    };

    // private Income constructor
    var prvIncome = function(id, description, value) {
        this.id = id;
        this.description = description;
        this.value = value;
    };

    // object for storing instances of prvExpense, prvIncome, totalExpenses, totalIncomes
    // every expense entered in the UI will map to an instance of prvExpense
    // every income entered in the UI will map to an instance of prvIncome
    var prvData = {
        allItems: {
            exp: [],
            inc: []
        },
        totals: {
            totalExpenses: 0,
            totalIncomes: 0
        }
    };

    return {

        // pubic method for creating a new Expense or Income instance based on user input from the UI,
        // add it to the exp or inc array of prvData.allItems, and return the new instance created
        pblAddItem: function(type, descripton, value) {

            // new reference to a new intance of prvExpense or prvIncome
            var newItem;

            // create unique id to put in each prvExpense or prvIncome item
            // id = last element of prvData.allItems[type] + 1
            var id = prvData.allItems[type][prvData.allItems[type].length - 1].id + 1;

            // create new instance of prvExpense or prvIncome based on the type parameter
            if(type === "exp") {
                newItem = new prvExpense(id, descripton, value);
            } else if (type === "inc") {
                newItem = new prvIncome(id, descripton, value);
            }

            // object[property]
            // add expense/income to the prvData.allItems[exp] or prvData.allItems[inc] array
            // based on the type parameter
            data.allItems[type].push(newItem);

            // return new instance of prvExpense or prvIncome
            return newItem;
        },

        pblTestGetDataStr: function() {
            console.info("prvData.allItems = %O", prvData.allItems);
        }
    }

})();

// UI module manipulates the UI of the app
var uiController = (function() {

    // private object containing the class names used in index.html and style.css
    var prvDOMstrings = {
        inputType: ".add__type",
        inputDescription: ".add__description",
        inputValue: ".add__value",
        inputButton: ".add__btn"};

    return {
        // public method to retrieve and return all three field values as strings from the UI
        pblGetInput: function() {

            // return an object with all three fields values as strings from the UI
            return {
                // return "inc" or "exp" from the transaction type list
                type: document.querySelector(prvDOMstrings.inputType).value,

                // return the transaction description as string
                description: document.querySelector(prvDOMstrings.inputDescription).value,

                // return the transaction value as a string
                value: document.querySelector(prvDOMstrings.inputValue).value
            };
        },

        // public method for returning the object containing the class names
        // in the index.html and style.css
        pblGetDOMstrings: function() {
            return prvDOMstrings;
        }
    }

})();

// App controller for communicating between the budgetController and the UIconroller
var controller = (function(budgetCtrl, UIctrl) {

    // private function to place the event listeners and the HTML tags' classes
    var prvSetupEventListeners = function() {

        // object containing the class names in the index.html and style.css
        var DOMstrings = uiController.pblGetDOMstrings();

        // register click event for the button with the tick sign
        document.querySelector(DOMstrings.inputButton).addEventListener("click", prvCtrlAddItem, false);

        // register Enter keypress event for the global object. Used only for the ENTER key
        document.getElementById("enterSum").addEventListener("keypress", function(event) {

            // use event.which to assure comptatibility with IE 9..11, Edge 14, UC Browser for Android 11.4
            // code 13 is returned when the "ENTER" key is pressed
            if (event.key === "Enter" || event.which === 13) { prvCtrlAddItem(); }

        }, false);
    };

    // private function for :
    // - retrieving all three user input field values
    var prvCtrlAddItem = function() {
        var userInput, newTransaction;

        console.log("You pressed enter and an item will be added to one of the tables and the budget will be updated");

        // get the user input data from the UI. This input will be called a transcation
        userInput = uiController.pblGetInput();
        console.log(userInput);

        // add the transaction to the budget controller
        newTransaction = budgetController.pblAddItem(userInput.type, userInput.description, userInput.value);
        console.info(newTransaction);

        // add the transaction to the UI

        // update the budget taking into account the transaction

        // display the newly calculated budget on the UI

    };

    return {
        initialiseVarsAndEvents: function() {
            console.log("App has started.");
            prvSetupEventListeners();
        }
    }

})(budgetController, uiController);

// Global execution scope
controller.initialiseVarsAndEvents();
<|endoftext|>


<commit_before>$(document).ready(function () {

    var COUNTDOWN_SECONDS = 3;
    var SERVER_URL = "http://boban.jovanoski.net/:8080/save_images";
    var curtainopen = false;
    var rope = $('.rope');
    var countdown = $('.countdown');
    var inProgress = false;
    var photoUris = [];
    var shutter = new Audio();
    var clock = new FlipClock(countdown, COUNTDOWN_SECONDS, {
        clockFace: 'Counter',
        minimumDigits: 1,
        countdown: true,
        autoStart: false,
        callbacks: {
            stop: function () {
                console.log("STOP THAT SHIT!");
                countdown.trigger('countdown:finished');
            }
        }
    });
    shutter.autoplay = false;
    shutter.src = navigator.userAgent.match(/Firefox/) ? 'audio/shutter.ogg' : 'audio/camera.mp3';

    countdown.on('photo:taken', function () {
        if (photoUris.length >= 4) {
            inProgress = false;
            toggleCurtains();
            sendPhotos(photoUris);
            photoUris = [];
        } else {
            console.log("Start COUNTDOWN!!!");
            var photoTimeout = setTimeout(function () {
                console.log("PHOTO TAKEN, START COUNTDOWN");
                startCountdown();
                clearTimeout(photoTimeout);
            }, 1000)
        }
    });

    countdown.on('countdown:finished', function () {
        //countdown.hide();
        takePhoto();
    });

    var sendPhotos = function(photoUris) {
        $.ajax({
            url : SERVER_URL,
            data : {
                "image_1" : photoUris[0],
                "image_2" : photoUris[1],
                "image_3" : photoUris[2],
                "image_4" : photoUris[3]
            },
            type : "POST",
            crossDomain: true
        });
    };

    var takePhoto = function () {
        shutter.load();
        shutter.play();

        Webcam.snap(function (dataUri) {
            photoUris.push(dataUri);
        });

        countdown.trigger('photo:taken');
    };

    var setClock = function(){
        var clockTimeout = setTimeout(function () {
            if (clock.getTime().time == 0) {
                clock.stop();
            } else {
                clock.decrement();
                setClock();
            }
            clearTimeout(clockTimeout);
        }, 1000);
    };

    var startCountdown = function () {
        clock.setValue(COUNTDOWN_SECONDS);
        setClock();
    };

    var curtainsOpened = function () {
        console.log("CURTAINS OPEN, START COUNTDOWN!!!");
        inProgress = true;
        startCountdown();
    };

    var setCamera = function () {
        Webcam.set({
            // live preview size
            width: 640,
            height: 480,

            dest_width: 640,
            dest_height: 480,

            // final cropped size
            crop_width: 480,
            crop_height: 480,

            // format and quality
            image_format: 'jpeg',
            jpeg_quality: 90
        });
        Webcam.attach('#camera');
    };

    var toggleCurtains = function () {
        if (inProgress) {
            return false;
        }
        if (curtainopen == false) {
            clock.setValue(COUNTDOWN_SECONDS);
            rope.stop().animate({top: '0px'}, {queue: false, duration: 350, easing: 'easeOutBounce'});
            $(".leftcurtain").stop().animate({width: '240px'}, 2000);
            $(".rightcurtain").stop().animate({width: '240px'}, 2000, curtainsOpened);
            curtainopen = true;
        } else {
            rope.stop().animate({top: '-40px'}, {queue: false, duration: 350, easing: 'easeOutBounce'});
            $(".leftcurtain").stop().animate({width: '50%'}, 2000);
            $(".rightcurtain").stop().animate({width: '51%'}, 2000);
            curtainopen = false;
        }
    };

    rope.click(function (e) {
        e.preventDefault();
        $(this).blur();
        toggleCurtains();
        return false;
    });

    $('body').keyup(function (e) {
        if (e.keyCode == 32) {
            rope.click();
        }
    });

    setCamera();

    $("#countdown").click(function (e) {
        e.preventDefault();
        clock.start();
    });
});<commit_msg>typooo<commit_after>$(document).ready(function () {

    var COUNTDOWN_SECONDS = 3;
    var SERVER_URL = "http://boban.jovanoski.net:8080/save_images";
    var curtainopen = false;
    var rope = $('.rope');
    var countdown = $('.countdown');
    var inProgress = false;
    var photoUris = [];
    var shutter = new Audio();
    var clock = new FlipClock(countdown, COUNTDOWN_SECONDS, {
        clockFace: 'Counter',
        minimumDigits: 1,
        countdown: true,
        autoStart: false,
        callbacks: {
            stop: function () {
                console.log("STOP THAT SHIT!");
                countdown.trigger('countdown:finished');
            }
        }
    });
    shutter.autoplay = false;
    shutter.src = navigator.userAgent.match(/Firefox/) ? 'audio/shutter.ogg' : 'audio/camera.mp3';

    countdown.on('photo:taken', function () {
        if (photoUris.length >= 4) {
            inProgress = false;
            toggleCurtains();
            sendPhotos(photoUris);
            photoUris = [];
        } else {
            console.log("Start COUNTDOWN!!!");
            var photoTimeout = setTimeout(function () {
                console.log("PHOTO TAKEN, START COUNTDOWN");
                startCountdown();
                clearTimeout(photoTimeout);
            }, 1000)
        }
    });

    countdown.on('countdown:finished', function () {
        //countdown.hide();
        takePhoto();
    });

    var sendPhotos = function(photoUris) {
        $.ajax({
            url : SERVER_URL,
            data : {
                "image_1" : photoUris[0],
                "image_2" : photoUris[1],
                "image_3" : photoUris[2],
                "image_4" : photoUris[3]
            },
            type : "POST",
            crossDomain: true
        });
    };

    var takePhoto = function () {
        shutter.load();
        shutter.play();

        Webcam.snap(function (dataUri) {
            photoUris.push(dataUri);
        });

        countdown.trigger('photo:taken');
    };

    var setClock = function(){
        var clockTimeout = setTimeout(function () {
            if (clock.getTime().time == 0) {
                clock.stop();
            } else {
                clock.decrement();
                setClock();
            }
            clearTimeout(clockTimeout);
        }, 1000);
    };

    var startCountdown = function () {
        clock.setValue(COUNTDOWN_SECONDS);
        setClock();
    };

    var curtainsOpened = function () {
        console.log("CURTAINS OPEN, START COUNTDOWN!!!");
        inProgress = true;
        startCountdown();
    };

    var setCamera = function () {
        Webcam.set({
            // live preview size
            width: 640,
            height: 480,

            dest_width: 640,
            dest_height: 480,

            // final cropped size
            crop_width: 480,
            crop_height: 480,

            // format and quality
            image_format: 'jpeg',
            jpeg_quality: 90
        });
        Webcam.attach('#camera');
    };

    var toggleCurtains = function () {
        if (inProgress) {
            return false;
        }
        if (curtainopen == false) {
            clock.setValue(COUNTDOWN_SECONDS);
            rope.stop().animate({top: '0px'}, {queue: false, duration: 350, easing: 'easeOutBounce'});
            $(".leftcurtain").stop().animate({width: '240px'}, 2000);
            $(".rightcurtain").stop().animate({width: '240px'}, 2000, curtainsOpened);
            curtainopen = true;
        } else {
            rope.stop().animate({top: '-40px'}, {queue: false, duration: 350, easing: 'easeOutBounce'});
            $(".leftcurtain").stop().animate({width: '50%'}, 2000);
            $(".rightcurtain").stop().animate({width: '51%'}, 2000);
            curtainopen = false;
        }
    };

    rope.click(function (e) {
        e.preventDefault();
        $(this).blur();
        toggleCurtains();
        return false;
    });

    $('body').keyup(function (e) {
        if (e.keyCode == 32) {
            rope.click();
        }
    });

    setCamera();

    $("#countdown").click(function (e) {
        e.preventDefault();
        clock.start();
    });
});<|endoftext|>


<commit_before>(function(){
    //initiate the client
    var oh = Ohmage("/app", "campaign-manager")

    //debugging
    window.oh = oh;

    //attach global callbacks
    oh.callback("done", function(x, status, req){
        //for debugging only
        //console.log(x);
    })

    //global error handler. In ohmage 200 means unauthenticated
    oh.callback("error", function(msg, code, req){
        (code == 200) ? window.location.replace("../web/#login") : message("Error! " + msg);
    });

    //prevent timeout
    oh.keepalive();

    //get data
    oh.user.whoami().done(function(username){
        updateProgress(10)
        oh.campaign.readall().done(function(data){
            updateProgress(15)
            $("#progressdiv").removeClass("hidden");
            var urns = Object.keys(data);
            var progress = 0;
            var total = 0;
            var requests = $.map(urns.sort(), function(urn, i){
                var roles = data[urn]["user_roles"];
                var count = -1;
                total++;

                var tr = $("
").appendTo("#campaigntablebody")
                var td5 = $("").appendTo(tr);
                var td1 = $("").appendTo(tr).text(data[urn].name);
                var td2 = $("").appendTo(tr).text(data[urn].creation_timestamp);
                var td3 = $("").appendTo(tr).text(data[urn].running_state);
                var td4 = $("").appendTo(tr);

                var btn = $("
").addClass("btn-group").append('\
                    <button type="button" class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown"> \
                    </button>').appendTo(td5);

                var ul = $("
").addClass("dropdown-menu").attr("role", "menu").appendTo(btn);

                if($.inArray("author", roles) > -1 || $.inArray("supervisor", roles) > -1) {

                    var a2 = $("").appendTo($("
").appendTo(ul)).append(' Edit Campaign').attr("href", '../surveytool/#' + urn).click(function(e){
                        if(count < 0){
                            e.preventDefault();
                            message("Loading campaign info, please be patient.", "info")
                        } else if(count > 0){
                            e.preventDefault();
                            message("Campaign " + urn + " has existing responses and can therefore not be modified.")
                        }
                    });
                }

                var a3 = $("").appendTo($("
").appendTo(ul)).append(' Visualize').attr("href", '../dashboard/#' + urn).click(function(e){
                    if(count < 0){
                        e.preventDefault();
                        message("Loading campaign info, please be patient.", "info")
                    } else if(count === 0){
                        e.preventDefault();
                        message("Campaign " + urn + " has no existing responses. Nothing to visualize.")
                    }
                });

                var responselink = $("").appendTo($("
").appendTo(ul)).append(' Responses').attr("href", '../responsetool/#' + urn).attr("target", "_blank").click(function(e){
                    if(count < 0){
                        e.preventDefault();
                        message("Loading campaign info, please be patient.", "info")
                    } else if(count === 0){
                        e.preventDefault();
                        message("Campaign " + urn + " has no existing responses.")
                    }
                });

                var a4 = $("").appendTo($("
").appendTo(ul)).append(' Download XML').attr("href", "#").click(function(e){
                    e.preventDefault();
                    $("#hiddenurn").val(urn)
                    $("#hiddenform").submit()
                });

                var a5 = $("").appendTo($("
").appendTo(ul)).append(' Export Data')
                    .attr("href", "../../app/survey_response/read?campaign_urn=" + urn + "&privacy_state=shared&client=manager&user_list=urn:ohmage:special:all&prompt_id_list=urn:ohmage:special:all&output_format=csv&sort_oder=timestamp&column_list=urn:ohmage:user:id,urn:ohmage:context:timestamp,urn:ohmage:prompt:response,urn:ohmage:context:location:latitude,urn:ohmage:context:location:longitude&suppress_metadata=true")

                ul.append($("
").addClass('divider'))

                var a1 = $("").appendTo($("
").appendTo(ul)).append(' Settings').attr("href", "#").click(function(e){
                    e.preventDefault();
                    populateModal();
                });

                function populateModal(){
                    oh.campaign.readall({
                        campaign_urn_list : urn,
                        output_format:"long"
                    }).done(function(x){
                        var longdata = x[urn];
                        $("#campaign_name").val(longdata.name);
                        $("#campaign_description").val(longdata.description);
                        $("#campaign_urn").val(urn);

                        //$("#campaign_running")[0].checked = (data["running_state"] == "running");
                        //$("#campaign_privacy")[0].checked = (data["privacy_state"] == "shared");

                        $("#campaign_running").bootstrapSwitch({size: "small", onColor: "success", offColor: "danger", onText:"running", offText:"stopped"})
                        $("#campaign_privacy").bootstrapSwitch({size: "small", onColor: "success", offColor: "danger", onText:"enabled", offText:"disabled"})
                        $("#campaign_privacy").bootstrapSwitch("state", longdata["privacy_state"] == "shared");
                        $("#campaign_running").bootstrapSwitch("state", longdata["running_state"] == "running");

                        $("#campaign_class option").each(function(i){
                            $(this).prop("selected", $.inArray($(this).attr("value"), longdata.classes) > -1);
                        });
                        $("#campaign_class").trigger("chosen:updated");

                        if(count){
                            $(".xml-upload-form").hide();
                        }

                        $('#myModal').modal("show").on("shown.bs.modal", function(){
                            $("#campaign_class").chosen({search_contains:true, no_results_text: "Class not found."});
                            $(".xml-upload-form").fileinput();
                        });

                        var xmldata;
                        $("input.xml-file-input").on("change", function(){
                            var f = this.files[0];
                            if(f){
                                var r = new FileReader();
                                r.onload = function(e) {
                                    xmldata = r.result;
                                }
                                r.readAsText(f);
                            } else {
                                xmldata = null;
                            }
                        })

                        $("#campaign_delete_button").unbind("click").click(function(e){
                            e.preventDefault();

                            // test for existing responses
                            if(count && !confirm("This campaign has " + count + " responses. Are you sure?")){
                                return;
                            }

                            var btn = $(this).attr("disabled", "disabled");
                            oh.campaign.delete({campaign_urn:urn}).done(function(){
                                $('#myModal').modal("hide");
                                tr.hide("slow", function(){
                                    alert("Campaign " + urn + " deleted!")
                                });
                            }).always(function(){
                                btn.removeAttr("disabled");
                            });
                        });

                        $("#campaign_save_button").unbind("click").click(function(e){
                            e.preventDefault();
                            var btn = $(this).attr("disabled", "disabled");
                            var running_state = $("#campaign_running")[0].checked ? "running" : "stopped";
                            var privacy_state = $("#campaign_privacy")[0].checked ? "shared" : "private";
                            var args = {
                                campaign_urn : urn,
                                running_state : running_state,
                                privacy_state : privacy_state,
                                description : $("#campaign_description").val(),
                                class_list_remove : longdata.classes,
                                class_list_add : $("#campaign_class").val()
                            }

                            //update xml only if selected
                            if(xmldata){
                                args.xml = fixxml(xmldata, longdata.name ,urn);
                            }

                            oh.campaign.update(args).done(function(){
                                td3.text(running_state);
                                $('#myModal').modal("hide")
                            }).always(function(){
                                btn.removeAttr("disabled");
                            });
                        });
                    });
                }

                // Disable for current deployment because confusing?
                //a3.hide()
                //a4.hide()
                //a5.hide()

                return oh.survey.count(urn).done(function(counts){
                    if(!Object.keys(counts).length){
                        //no existing responses found
                        count = 0;
                    } else {
                        count = $.map(counts, function(val, key) {
                            return val[0].count;
                        }).reduce(function(previousValue, currentValue) {
                            return previousValue + currentValue;
                        });
                    }
                    td4.text(count);
                }).always(function(){
                    updateProgress((progress++/total) * 75 + 25);
                });
            });

            //data tables widget
            function initTable(){
                $('#campaigntable').dataTable( {
                    "dom" : '<"pull-right"l><"pull-left"f>tip',
                    "lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
                    "aoColumnDefs": [
                       { 'bSortable': false, 'aTargets': [ 0 ] }
                    ]
                });
            }

            //init temporary datatable
            initTable()

            //reinit final datatable after counts have been updated
            $.when.apply($, requests).always(function() {
                $("#progressdiv").addClass("hidden");
                $('#campaigntable').dataTable().fnDestroy();
                initTable();
            });

            //resetters
            $("#myModal").on("hidden.bs.modal", function(){
                $(".xml-upload-form").show();
                //$(".fileinput").fileinput("clear");
            })
        });

        //get users
        oh.user.read().done(function(x){
            $.each(Object.keys(x).sort(), function( i, name ) {
                //$("#campaign_author").append($("<option />").text(name));
            });
        });

        //get classes
        oh.class.read().done(function(x){
            $.each(Object.keys(x).sort(), function( i, urn ) {
                $("#campaign_class").append($("<option />").text(urn).attr("value", urn));
            });
        });
    });

    updateProgress = _.throttle(function(pct){
        $(".progress-bar").css("width", + pct + "%");
    }, 300);

    function message(msg, type){
        // type must be one of success, info, warning, danger
        type = type || "danger"
        $("#errordiv").empty().append('
×' + msg + '
');
        $('html, body').animate({
           scrollTop: 100
        }, 200);
    }

    //XML parser for mixed case tag names (HTML only supports lowercase tags)
    var parse = (function(parser, jQuery){
        return function(str) {
            return jQuery(parser.parseFromString(str, "text/xml").documentElement)
        }
    })(new DOMParser(), jQuery)

    function fixxml(input, name, urn){
        var xml = $.parseXML(input);
        var campaign = $("campaign", xml);
        campaign.children("campaignName").remove();
        campaign.children("campaignUrn").remove();
        campaign.prepend(parse("<campaignName/>").text(name))
        campaign.prepend(parse("<campaignUrn/>").text(urn))
        return (new XMLSerializer()).serializeToString(xml);
    }

})();
<commit_msg>do not list campaigns we are not participating in<commit_after>(function(){
    //initiate the client
    var oh = Ohmage("/app", "campaign-manager")

    //debugging
    window.oh = oh;

    //attach global callbacks
    oh.callback("done", function(x, status, req){
        //for debugging only
        //console.log(x);
    })

    //global error handler. In ohmage 200 means unauthenticated
    oh.callback("error", function(msg, code, req){
        (code == 200) ? window.location.replace("../web/#login") : message("Error! " + msg);
    });

    //prevent timeout
    oh.keepalive();

    //get data
    oh.user.whoami().done(function(username){
        updateProgress(10)
        oh.campaign.readall().done(function(data){
            updateProgress(15)
            $("#progressdiv").removeClass("hidden");
            var urns = Object.keys(data);
            var progress = 0;
            var total = 0;
            var requests = $.map(urns.sort(), function(urn, i){
                var roles = data[urn]["user_roles"];

                if(roles.length == 0) return;

                var count = -1;
                total++;

                var tr = $("
").appendTo("#campaigntablebody")
                var td5 = $("").appendTo(tr);
                var td1 = $("").appendTo(tr).text(data[urn].name);
                var td2 = $("").appendTo(tr).text(data[urn].creation_timestamp);
                var td3 = $("").appendTo(tr).text(data[urn].running_state);
                var td4 = $("").appendTo(tr);

                var btn = $("
").addClass("btn-group").append('\
                    <button type="button" class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown"> \
                    </button>').appendTo(td5);

                var ul = $("
").addClass("dropdown-menu").attr("role", "menu").appendTo(btn);

                if($.inArray("author", roles) > -1 || $.inArray("supervisor", roles) > -1) {

                    var a2 = $("").appendTo($("
").appendTo(ul)).append(' Edit Campaign').attr("href", '../surveytool/#' + urn).click(function(e){
                        if(count < 0){
                            e.preventDefault();
                            message("Loading campaign info, please be patient.", "info")
                        } else if(count > 0){
                            e.preventDefault();
                            message("Campaign " + urn + " has existing responses and can therefore not be modified.")
                        }
                    });
                }

                var a3 = $("").appendTo($("
").appendTo(ul)).append(' Visualize').attr("href", '../dashboard/#' + urn).click(function(e){
                    if(count < 0){
                        e.preventDefault();
                        message("Loading campaign info, please be patient.", "info")
                    } else if(count === 0){
                        e.preventDefault();
                        message("Campaign " + urn + " has no existing responses. Nothing to visualize.")
                    }
                });

                var responselink = $("").appendTo($("
").appendTo(ul)).append(' Responses').attr("href", '../responsetool/#' + urn).attr("target", "_blank").click(function(e){
                    if(count < 0){
                        e.preventDefault();
                        message("Loading campaign info, please be patient.", "info")
                    } else if(count === 0){
                        e.preventDefault();
                        message("Campaign " + urn + " has no existing responses.")
                    }
                });

                var a4 = $("").appendTo($("
").appendTo(ul)).append(' Download XML').attr("href", "#").click(function(e){
                    e.preventDefault();
                    $("#hiddenurn").val(urn)
                    $("#hiddenform").submit()
                });

                var a5 = $("").appendTo($("
").appendTo(ul)).append(' Export Data')
                    .attr("href", "../../app/survey_response/read?campaign_urn=" + urn + "&privacy_state=shared&client=manager&user_list=urn:ohmage:special:all&prompt_id_list=urn:ohmage:special:all&output_format=csv&sort_oder=timestamp&column_list=urn:ohmage:user:id,urn:ohmage:context:timestamp,urn:ohmage:prompt:response,urn:ohmage:context:location:latitude,urn:ohmage:context:location:longitude&suppress_metadata=true")

                ul.append($("
").addClass('divider'))

                var a1 = $("").appendTo($("
").appendTo(ul)).append(' Settings').attr("href", "#").click(function(e){
                    e.preventDefault();
                    populateModal();
                });

                function populateModal(){
                    oh.campaign.readall({
                        campaign_urn_list : urn,
                        output_format:"long"
                    }).done(function(x){
                        var longdata = x[urn];
                        $("#campaign_name").val(longdata.name);
                        $("#campaign_description").val(longdata.description);
                        $("#campaign_urn").val(urn);

                        //$("#campaign_running")[0].checked = (data["running_state"] == "running");
                        //$("#campaign_privacy")[0].checked = (data["privacy_state"] == "shared");

                        $("#campaign_running").bootstrapSwitch({size: "small", onColor: "success", offColor: "danger", onText:"running", offText:"stopped"})
                        $("#campaign_privacy").bootstrapSwitch({size: "small", onColor: "success", offColor: "danger", onText:"enabled", offText:"disabled"})
                        $("#campaign_privacy").bootstrapSwitch("state", longdata["privacy_state"] == "shared");
                        $("#campaign_running").bootstrapSwitch("state", longdata["running_state"] == "running");

                        $("#campaign_class option").each(function(i){
                            $(this).prop("selected", $.inArray($(this).attr("value"), longdata.classes) > -1);
                        });
                        $("#campaign_class").trigger("chosen:updated");

                        if(count){
                            $(".xml-upload-form").hide();
                        }

                        $('#myModal').modal("show").on("shown.bs.modal", function(){
                            $("#campaign_class").chosen({search_contains:true, no_results_text: "Class not found."});
                            $(".xml-upload-form").fileinput();
                        });

                        var xmldata;
                        $("input.xml-file-input").on("change", function(){
                            var f = this.files[0];
                            if(f){
                                var r = new FileReader();
                                r.onload = function(e) {
                                    xmldata = r.result;
                                }
                                r.readAsText(f);
                            } else {
                                xmldata = null;
                            }
                        })

                        $("#campaign_delete_button").unbind("click").click(function(e){
                            e.preventDefault();

                            // test for existing responses
                            if(count && !confirm("This campaign has " + count + " responses. Are you sure?")){
                                return;
                            }

                            var btn = $(this).attr("disabled", "disabled");
                            oh.campaign.delete({campaign_urn:urn}).done(function(){
                                $('#myModal').modal("hide");
                                tr.hide("slow", function(){
                                    alert("Campaign " + urn + " deleted!")
                                });
                            }).always(function(){
                                btn.removeAttr("disabled");
                            });
                        });

                        $("#campaign_save_button").unbind("click").click(function(e){
                            e.preventDefault();
                            var btn = $(this).attr("disabled", "disabled");
                            var running_state = $("#campaign_running")[0].checked ? "running" : "stopped";
                            var privacy_state = $("#campaign_privacy")[0].checked ? "shared" : "private";
                            var args = {
                                campaign_urn : urn,
                                running_state : running_state,
                                privacy_state : privacy_state,
                                description : $("#campaign_description").val(),
                                class_list_remove : longdata.classes,
                                class_list_add : $("#campaign_class").val()
                            }

                            //update xml only if selected
                            if(xmldata){
                                args.xml = fixxml(xmldata, longdata.name ,urn);
                            }

                            oh.campaign.update(args).done(function(){
                                td3.text(running_state);
                                $('#myModal').modal("hide")
                            }).always(function(){
                                btn.removeAttr("disabled");
                            });
                        });
                    });
                }

                // Disable for current deployment because confusing?
                //a3.hide()
                //a4.hide()
                //a5.hide()

                return oh.survey.count(urn).done(function(counts){
                    if(!Object.keys(counts).length){
                        //no existing responses found
                        count = 0;
                    } else {
                        count = $.map(counts, function(val, key) {
                            return val[0].count;
                        }).reduce(function(previousValue, currentValue) {
                            return previousValue + currentValue;
                        });
                    }
                    td4.text(count);
                }).always(function(){
                    updateProgress((progress++/total) * 75 + 25);
                });
            });

            //data tables widget
            function initTable(){
                $('#campaigntable').dataTable( {
                    "dom" : '<"pull-right"l><"pull-left"f>tip',
                    "lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
                    "aoColumnDefs": [
                       { 'bSortable': false, 'aTargets': [ 0 ] }
                    ]
                });
            }

            //init temporary datatable
            initTable()

            //reinit final datatable after counts have been updated
            $.when.apply($, requests).always(function() {
                $("#progressdiv").addClass("hidden");
                $('#campaigntable').dataTable().fnDestroy();
                initTable();
            });

            //resetters
            $("#myModal").on("hidden.bs.modal", function(){
                $(".xml-upload-form").show();
                //$(".fileinput").fileinput("clear");
            })
        });

        //get users
        oh.user.read().done(function(x){
            $.each(Object.keys(x).sort(), function( i, name ) {
                //$("#campaign_author").append($("<option />").text(name));
            });
        });

        //get classes
        oh.class.read().done(function(x){
            $.each(Object.keys(x).sort(), function( i, urn ) {
                $("#campaign_class").append($("<option />").text(urn).attr("value", urn));
            });
        });
    });

    updateProgress = _.throttle(function(pct){
        $(".progress-bar").css("width", + pct + "%");
    }, 300);

    function message(msg, type){
        // type must be one of success, info, warning, danger
        type = type || "danger"
        $("#errordiv").empty().append('
×' + msg + '
');
        $('html, body').animate({
           scrollTop: 100
        }, 200);
    }

    //XML parser for mixed case tag names (HTML only supports lowercase tags)
    var parse = (function(parser, jQuery){
        return function(str) {
            return jQuery(parser.parseFromString(str, "text/xml").documentElement)
        }
    })(new DOMParser(), jQuery)

    function fixxml(input, name, urn){
        var xml = $.parseXML(input);
        var campaign = $("campaign", xml);
        campaign.children("campaignName").remove();
        campaign.children("campaignUrn").remove();
        campaign.prepend(parse("<campaignName/>").text(name))
        campaign.prepend(parse("<campaignUrn/>").text(urn))
        return (new XMLSerializer()).serializeToString(xml);
    }

})();
<|endoftext|>


<commit_before>const React = require("react")
const _ = require("lodash")
const Paginator = require("./paginator")
const classes = require("./classes")

const $ = React.createElement

function makeType(t, i) {
  const className = classes(
    `type-${t}`,
    "ttu tc db ph1 pv2 f5-ns f6 br2 ba badge with-border-color b",
    {mt1: i > 0}
  )
  const style = {
    minWidth: "7em"
  }
  return $("span", {key: t, className, style}, t)
}

function makePKMN(p, i) {
  const className = classes(
    "b--black-10",
    "ph2 pv3",
    "flex items-center",
    {bt: i > 0},
    {mt2: i === 0},
  )
  const displayNumber = "#" + _.padStart(p.number, 3, "0")
  const style = {minHeight: "100px"}
  return $("div", {key: `pkmn-${p.number}`, className, style},
    $("div", {className: "flex-auto f4 f2-ns mv0"},
      $("h3", {className: "truncate mt0 mb1"}, p.name),
      $("p", {className: "silver mv0"}, displayNumber)
    ),
    $("div", {}, p.types.map(makeType))
  )
}

// TODO: Debounce the input event
// TODO: Improve performance
// TODO: Switch to image for "back to top" link

function Dex(props) {
  const {
    pkmn,
    search,
    updateSearch,
    updateCurrentPage,
    currentPage
  } = props
  const className = classes(
    "ph2 mt3",
    "center mw7"
  )
  const searchInput =
    $("input", {
      type: "search",
      autoComplete: "off",
      autoCorrect: "off",
      inputMode: "verbatim",
      autoCapitalize: "none",
      className: classes(
        "f2 w-100 border-box",
        "pv2 ph4",
        "mv4",
        "chunky-focus",
        "br-pill ba b--black-20"
      ),
      placeholder: "search",
      value: search,
      onChange: event =>
        updateSearch(event.target.value),
    })
  const mons = $(Paginator, {
    currentPage,
    updatePageNext: () => updateCurrentPage(currentPage + 1),
    updatePagePrev: () => updateCurrentPage(currentPage - 1),
    pageSize: 100,
    // pageSize: 10,
    items: pkmn,
    render: makePKMN
  })
  return $("div", {className},
    $("a", {href: "#", className: "GoToTop"}, "⬆"),
    $("div", {className: "mh2"}, searchInput),
    mons
  )
}

module.exports = Dex
<commit_msg>Comments<commit_after>const React = require("react")
const _ = require("lodash")
const Paginator = require("./paginator")
const classes = require("./classes")

const $ = React.createElement

function makeType(t, i) {
  const className = classes(
    `type-${t}`,
    "ttu tc db ph1 pv2 f5-ns f6 br2 ba badge with-border-color b",
    {mt1: i > 0}
  )
  const style = {
    minWidth: "7em"
  }
  return $("span", {key: t, className, style}, t)
}

function makePKMN(p, i) {
  const className = classes(
    "b--black-10",
    "ph2 pv3",
    "flex items-center",
    {bt: i > 0},
    {mt2: i === 0},
  )
  const displayNumber = "#" + _.padStart(p.number, 3, "0")
  const style = {minHeight: "100px"}
  return $("div", {key: `pkmn-${p.number}`, className, style},
    $("div", {className: "flex-auto f4 f2-ns mv0"},
      $("h3", {className: "truncate mt0 mb1"}, p.name),
      $("p", {className: "silver mv0"}, displayNumber)
    ),
    $("div", {}, p.types.map(makeType))
  )
}

// TODO: Improve performance, somehow?
// TODO: Switch to image for "back to top" link

function Dex(props) {
  const {
    pkmn,
    search,
    updateSearch,
    updateCurrentPage,
    currentPage
  } = props
  const className = classes(
    "ph2 mt3",
    "center mw7"
  )
  const searchInput =
    $("input", {
      type: "search",
      autoComplete: "off",
      autoCorrect: "off",
      inputMode: "verbatim",
      autoCapitalize: "none",
      className: classes(
        "f2 w-100 border-box",
        "pv2 ph4",
        "mv4",
        "chunky-focus",
        "br-pill ba b--black-20"
      ),
      placeholder: "search",
      value: search,
      onChange: event =>
        updateSearch(event.target.value),
    })
  const mons = $(Paginator, {
    currentPage,
    updatePageNext: () => updateCurrentPage(currentPage + 1),
    updatePagePrev: () => updateCurrentPage(currentPage - 1),
    pageSize: 100,
    // pageSize: 10,
    items: pkmn,
    render: makePKMN
  })
  return $("div", {className},
    $("a", {href: "#", className: "GoToTop"}, "⬆"),
    $("div", {className: "mh2"}, searchInput),
    mons
  )
}

module.exports = Dex
<|endoftext|>


<commit_before>'use strict';

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

const Exchange = require ('./base/Exchange');
const { ExchangeError, AuthenticationError } = require ('./base/errors');

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

module.exports = class exx extends Exchange {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'exx',
            'name': 'EXX',
            'countries': 'CN',
            'rateLimit': 1000 / 10,
            'has': {
                'fetchTickers': true,
                'fetchOpenOrders': true,
            },
            'urls': {
                'logo': 'https://www.exx.com/src/images/icohome/exxlogo.png',
                'api': {
                    'public': 'https://api.exx.com/data/v1',
                    'private': 'https://trade.exx.com/api',
                },
                'www': 'https://www.exx.com/',
                'doc': 'https://www.exx.com/help/restApi',
                'fees': 'https://www.exx.com/help/rate',
            },
            'api': {
                'public': {
                    'get': [
                        'markets',
                        'tickers',
                        'ticker',
                        'depth',
                        'trades',
                    ],
                },
                'private': {
                    'get': [
                        'order',
                        'cancel',
                        'getOrder',
                        'getOpenOrders',
                        'getBalance',
                    ],
                },
            },
            'fees': {
                'trading': {
                    'maker': 0.1 / 100,
                    'taker': 0.1 / 100,
                },
                'funding': {
                    'withdraw': {
                        'BCC': 0.0003,
                        'BCD': 0.0,
                        'BOT': 10.0,
                        'BTC': 0.001,
                        'BTG': 0.0,
                        'BTM': 25.0,
                        'BTS': 3.0,
                        'EOS': 1.0,
                        'ETC': 0.01,
                        'ETH': 0.01,
                        'ETP': 0.012,
                        'HPY': 0.0,
                        'HSR': 0.001,
                        'INK': 20.0,
                        'LTC': 0.005,
                        'MCO': 0.6,
                        'MONA': 0.01,
                        'QASH': 5.0,
                        'QCASH': 5.0,
                        'QTUM': 0.01,
                        'USDT': 5.0,
                    },
                },
            },
        });
    }

    async fetchMarkets () {
        let markets = await this.publicGetMarkets ();
        let ids = Object.keys (markets);
        let result = [];
        for (let i = 0; i < ids.length; i++) {
            let id = ids[i];
            let market = markets[id];
            let [ baseId, quoteId ] = id.split ('_');
            let upper = id.toUpperCase ();
            let [ base, quote ] = upper.split ('_');
            base = this.commonCurrencyCode (base);
            quote = this.commonCurrencyCode (quote);
            let symbol = base + '/' + quote;
            let active = market['isOpen'] === true;
            let precision = {
                'amount': parseInt (market['amountScale']),
                'price': parseInt (market['priceScale']),
            };
            let lot = Math.pow (10, -precision['amount']);
            result.push ({
                'id': id,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'baseId': baseId,
                'quoteId': quoteId,
                'active': active,
                'lot': lot,
                'precision': precision,
                'limits': {
                    'amount': {
                        'min': lot,
                        'max': Math.pow (10, precision['amount']),
                    },
                    'price': {
                        'min': Math.pow (10, -precision['price']),
                        'max': Math.pow (10, precision['price']),
                    },
                    'cost': {
                        'min': undefined,
                        'max': undefined,
                    },
                },
                'info': market,
            });
        }
        return result;
    }

    parseTicker (ticker, market = undefined) {
        let symbol = market['symbol'];
        let timestamp = parseInt (ticker['date']);
        ticker = ticker['ticker'];
        let last = parseFloat (ticker['last']);
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'high': parseFloat (ticker['high']),
            'low': parseFloat (ticker['low']),
            'bid': parseFloat (ticker['buy']),
            'bidVolume': undefined,
            'ask': parseFloat (ticker['sell']),
            'askVolume': undefined,
            'vwap': undefined,
            'open': undefined,
            'close': last,
            'last': last,
            'previousClose': undefined,
            'change': parseFloat (ticker['riseRate']),
            'percentage': undefined,
            'average': undefined,
            'baseVolume': parseFloat (ticker['vol']),
            'quoteVolume': undefined,
            'info': ticker,
        };
    }

    async fetchTicker (symbol, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let ticker = await this.publicGetTicker (this.extend ({
            'currency': market['id'],
        }, params));
        return this.parseTicker (ticker, market);
    }

    async fetchTickers (symbols = undefined, params = {}) {
        await this.loadMarkets ();
        let tickers = await this.publicGetTickers (params);
        let result = {};
        let timestamp = this.milliseconds ();
        let ids = Object.keys (tickers);
        for (let i = 0; i < ids.length; i++) {
            let id = ids[i];
            if (!(id in this.marketsById))
                continue;
            let market = this.marketsById[id];
            let symbol = market['symbol'];
            let ticker = {
                'date': timestamp,
                'ticker': tickers[id],
            };
            result[symbol] = this.parseTicker (ticker, market);
        }
        return result;
    }

    async fetchOrderBook (symbol, params = {}) {
        await this.loadMarkets ();
        let orderbook = await this.publicGetDepth (this.extend ({
            'currency': this.marketId (symbol),
        }, params));
        return this.parseOrderBook (orderbook, orderbook['timestamp']);
    }

    parseTrade (trade, market = undefined) {
        let timestamp = trade['date'] * 1000;
        let price = parseFloat (trade['price']);
        let amount = parseFloat (trade['amount']);
        let symbol = market['symbol'];
        let cost = this.costToPrecision (symbol, price * amount);
        return {
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'symbol': symbol,
            'id': this.safeString (trade, 'tid'),
            'order': undefined,
            'type': 'limit',
            'side': trade['type'],
            'price': price,
            'amount': amount,
            'cost': cost,
            'fee': undefined,
            'info': trade,
        };
    }

    async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let trades = await this.publicGetTrades (this.extend ({
            'currency': market['id'],
        }, params));
        return this.parseTrades (trades, market, since, limit);
    }

    async fetchBalance (params = {}) {
        await this.loadMarkets ();
        let balances = await this.privateGetBalance (params);
        let result = { 'info': balances };
        balances = balances['funds'];
        let currencies = Object.keys (balances);
        for (let i = 0; i < currencies.length; i++) {
            let id = currencies[i];
            let balance = balances[id];
            let currency = this.commonCurrencyCode (id);
            let account = {
                'free': parseFloat (balance['balance']),
                'used': parseFloat (balance['freeze']),
                'total': parseFloat (balance['total']),
            };
            result[currency] = account;
        }
        return this.parseBalance (result);
    }

    parseOrder (order, market = undefined) {
        let symbol = market['symbol'];
        let timestamp = parseInt (order['trade_date']);
        let price = parseFloat (order['price']);
        let cost = this.safeFloat (order, 'trade_money');
        let amount = this.safeFloat (order, 'total_amount');
        let filled = this.safeFloat (order, 'trade_amount', 0.0);
        let remaining = this.amountToPrecision (symbol, amount - filled);
        let status = this.safeInteger (order, 'status');
        if (status === 1) {
            status = 'canceled';
        } else if (status === 2) {
            status = 'closed';
        } else {
            status = 'open';
        }
        let fee = undefined;
        if ('fees' in order) {
            fee = {
                'cost': this.safeFloat (order, 'fees'),
                'currency': market['quote'],
            };
        }
        return {
            'id': this.safeString (order, 'id'),
            'datetime': this.iso8601 (timestamp),
            'timestamp': timestamp,
            'status': 'open',
            'symbol': symbol,
            'type': 'limit',
            'side': order['type'],
            'price': price,
            'cost': cost,
            'amount': amount,
            'filled': filled,
            'remaining': remaining,
            'trades': undefined,
            'fee': fee,
            'info': order,
        };
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let response = await this.privateGetOrder (this.extend ({
            'currency': market['id'],
            'type': side,
            'price': price,
            'amount': amount,
        }, params));
        let id = response['id'];
        let order = this.parseOrder ({
            'id': id,
            'trade_date': this.milliseconds (),
            'total_amount': amount,
            'price': price,
            'type': side,
            'info': response,
        }, market);
        this.orders[id] = order;
        return order;
    }

    async cancelOrder (id, symbol = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let result = await this.privateGetCancel (this.extend ({
            'id': id,
            'currency': market['id'],
        }, params));
        return result;
    }

    async fetchOrder (id, symbol = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let order = await this.privateGetGetOrder (this.extend ({
            'id': id,
            'currency': market['id'],
        }, params));
        return this.parseOrder (order, market);
    }

    async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let orders = await this.privateGetOpenOrders (this.extend ({
            'currency': market['id'],
        }, params));
        return this.parseOrders (orders, market, since, limit);
    }

    nonce () {
        return this.milliseconds ();
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let url = this.urls['api'][api] + '/' + path;
        if (api === 'public') {
            if (Object.keys (params).length)
                url += '?' + this.urlencode (params);
        } else {
            this.checkRequiredCredentials ();
            let query = this.urlencode (this.keysort (this.extend ({
                'accesskey': this.apiKey,
                'nonce': this.nonce (),
            }, params)));
            let signature = this.hmac (this.encode (body), this.encode (this.secret), 'sha512');
            url += '?' + query + '&signature=' + signature;
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }

    async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let response = await this.fetch2 (path, api, method, params, headers, body);
        let code = this.safeInteger (response, 'code');
        let message = this.safeString (response, 'message');
        if (code && code !== 100 && message) {
            if (code === 103)
                throw new AuthenticationError (message);
            throw new ExchangeError (message);
        }
        return response;
    }
};
<commit_msg>exx logo #1410<commit_after>'use strict';

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

const Exchange = require ('./base/Exchange');
const { ExchangeError, AuthenticationError } = require ('./base/errors');

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

module.exports = class exx extends Exchange {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'exx',
            'name': 'EXX',
            'countries': 'CN',
            'rateLimit': 1000 / 10,
            'has': {
                'fetchTickers': true,
                'fetchOpenOrders': true,
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/37770292-fbf613d0-2de4-11e8-9f79-f2dc451b8ccb.jpg',
                'api': {
                    'public': 'https://api.exx.com/data/v1',
                    'private': 'https://trade.exx.com/api',
                },
                'www': 'https://www.exx.com/',
                'doc': 'https://www.exx.com/help/restApi',
                'fees': 'https://www.exx.com/help/rate',
            },
            'api': {
                'public': {
                    'get': [
                        'markets',
                        'tickers',
                        'ticker',
                        'depth',
                        'trades',
                    ],
                },
                'private': {
                    'get': [
                        'order',
                        'cancel',
                        'getOrder',
                        'getOpenOrders',
                        'getBalance',
                    ],
                },
            },
            'fees': {
                'trading': {
                    'maker': 0.1 / 100,
                    'taker': 0.1 / 100,
                },
                'funding': {
                    'withdraw': {
                        'BCC': 0.0003,
                        'BCD': 0.0,
                        'BOT': 10.0,
                        'BTC': 0.001,
                        'BTG': 0.0,
                        'BTM': 25.0,
                        'BTS': 3.0,
                        'EOS': 1.0,
                        'ETC': 0.01,
                        'ETH': 0.01,
                        'ETP': 0.012,
                        'HPY': 0.0,
                        'HSR': 0.001,
                        'INK': 20.0,
                        'LTC': 0.005,
                        'MCO': 0.6,
                        'MONA': 0.01,
                        'QASH': 5.0,
                        'QCASH': 5.0,
                        'QTUM': 0.01,
                        'USDT': 5.0,
                    },
                },
            },
        });
    }

    async fetchMarkets () {
        let markets = await this.publicGetMarkets ();
        let ids = Object.keys (markets);
        let result = [];
        for (let i = 0; i < ids.length; i++) {
            let id = ids[i];
            let market = markets[id];
            let [ baseId, quoteId ] = id.split ('_');
            let upper = id.toUpperCase ();
            let [ base, quote ] = upper.split ('_');
            base = this.commonCurrencyCode (base);
            quote = this.commonCurrencyCode (quote);
            let symbol = base + '/' + quote;
            let active = market['isOpen'] === true;
            let precision = {
                'amount': parseInt (market['amountScale']),
                'price': parseInt (market['priceScale']),
            };
            let lot = Math.pow (10, -precision['amount']);
            result.push ({
                'id': id,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'baseId': baseId,
                'quoteId': quoteId,
                'active': active,
                'lot': lot,
                'precision': precision,
                'limits': {
                    'amount': {
                        'min': lot,
                        'max': Math.pow (10, precision['amount']),
                    },
                    'price': {
                        'min': Math.pow (10, -precision['price']),
                        'max': Math.pow (10, precision['price']),
                    },
                    'cost': {
                        'min': undefined,
                        'max': undefined,
                    },
                },
                'info': market,
            });
        }
        return result;
    }

    parseTicker (ticker, market = undefined) {
        let symbol = market['symbol'];
        let timestamp = parseInt (ticker['date']);
        ticker = ticker['ticker'];
        let last = parseFloat (ticker['last']);
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'high': parseFloat (ticker['high']),
            'low': parseFloat (ticker['low']),
            'bid': parseFloat (ticker['buy']),
            'bidVolume': undefined,
            'ask': parseFloat (ticker['sell']),
            'askVolume': undefined,
            'vwap': undefined,
            'open': undefined,
            'close': last,
            'last': last,
            'previousClose': undefined,
            'change': parseFloat (ticker['riseRate']),
            'percentage': undefined,
            'average': undefined,
            'baseVolume': parseFloat (ticker['vol']),
            'quoteVolume': undefined,
            'info': ticker,
        };
    }

    async fetchTicker (symbol, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let ticker = await this.publicGetTicker (this.extend ({
            'currency': market['id'],
        }, params));
        return this.parseTicker (ticker, market);
    }

    async fetchTickers (symbols = undefined, params = {}) {
        await this.loadMarkets ();
        let tickers = await this.publicGetTickers (params);
        let result = {};
        let timestamp = this.milliseconds ();
        let ids = Object.keys (tickers);
        for (let i = 0; i < ids.length; i++) {
            let id = ids[i];
            if (!(id in this.marketsById))
                continue;
            let market = this.marketsById[id];
            let symbol = market['symbol'];
            let ticker = {
                'date': timestamp,
                'ticker': tickers[id],
            };
            result[symbol] = this.parseTicker (ticker, market);
        }
        return result;
    }

    async fetchOrderBook (symbol, params = {}) {
        await this.loadMarkets ();
        let orderbook = await this.publicGetDepth (this.extend ({
            'currency': this.marketId (symbol),
        }, params));
        return this.parseOrderBook (orderbook, orderbook['timestamp']);
    }

    parseTrade (trade, market = undefined) {
        let timestamp = trade['date'] * 1000;
        let price = parseFloat (trade['price']);
        let amount = parseFloat (trade['amount']);
        let symbol = market['symbol'];
        let cost = this.costToPrecision (symbol, price * amount);
        return {
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'symbol': symbol,
            'id': this.safeString (trade, 'tid'),
            'order': undefined,
            'type': 'limit',
            'side': trade['type'],
            'price': price,
            'amount': amount,
            'cost': cost,
            'fee': undefined,
            'info': trade,
        };
    }

    async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let trades = await this.publicGetTrades (this.extend ({
            'currency': market['id'],
        }, params));
        return this.parseTrades (trades, market, since, limit);
    }

    async fetchBalance (params = {}) {
        await this.loadMarkets ();
        let balances = await this.privateGetBalance (params);
        let result = { 'info': balances };
        balances = balances['funds'];
        let currencies = Object.keys (balances);
        for (let i = 0; i < currencies.length; i++) {
            let id = currencies[i];
            let balance = balances[id];
            let currency = this.commonCurrencyCode (id);
            let account = {
                'free': parseFloat (balance['balance']),
                'used': parseFloat (balance['freeze']),
                'total': parseFloat (balance['total']),
            };
            result[currency] = account;
        }
        return this.parseBalance (result);
    }

    parseOrder (order, market = undefined) {
        let symbol = market['symbol'];
        let timestamp = parseInt (order['trade_date']);
        let price = parseFloat (order['price']);
        let cost = this.safeFloat (order, 'trade_money');
        let amount = this.safeFloat (order, 'total_amount');
        let filled = this.safeFloat (order, 'trade_amount', 0.0);
        let remaining = this.amountToPrecision (symbol, amount - filled);
        let status = this.safeInteger (order, 'status');
        if (status === 1) {
            status = 'canceled';
        } else if (status === 2) {
            status = 'closed';
        } else {
            status = 'open';
        }
        let fee = undefined;
        if ('fees' in order) {
            fee = {
                'cost': this.safeFloat (order, 'fees'),
                'currency': market['quote'],
            };
        }
        return {
            'id': this.safeString (order, 'id'),
            'datetime': this.iso8601 (timestamp),
            'timestamp': timestamp,
            'status': 'open',
            'symbol': symbol,
            'type': 'limit',
            'side': order['type'],
            'price': price,
            'cost': cost,
            'amount': amount,
            'filled': filled,
            'remaining': remaining,
            'trades': undefined,
            'fee': fee,
            'info': order,
        };
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let response = await this.privateGetOrder (this.extend ({
            'currency': market['id'],
            'type': side,
            'price': price,
            'amount': amount,
        }, params));
        let id = response['id'];
        let order = this.parseOrder ({
            'id': id,
            'trade_date': this.milliseconds (),
            'total_amount': amount,
            'price': price,
            'type': side,
            'info': response,
        }, market);
        this.orders[id] = order;
        return order;
    }

    async cancelOrder (id, symbol = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let result = await this.privateGetCancel (this.extend ({
            'id': id,
            'currency': market['id'],
        }, params));
        return result;
    }

    async fetchOrder (id, symbol = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let order = await this.privateGetGetOrder (this.extend ({
            'id': id,
            'currency': market['id'],
        }, params));
        return this.parseOrder (order, market);
    }

    async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let orders = await this.privateGetOpenOrders (this.extend ({
            'currency': market['id'],
        }, params));
        return this.parseOrders (orders, market, since, limit);
    }

    nonce () {
        return this.milliseconds ();
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let url = this.urls['api'][api] + '/' + path;
        if (api === 'public') {
            if (Object.keys (params).length)
                url += '?' + this.urlencode (params);
        } else {
            this.checkRequiredCredentials ();
            let query = this.urlencode (this.keysort (this.extend ({
                'accesskey': this.apiKey,
                'nonce': this.nonce (),
            }, params)));
            let signature = this.hmac (this.encode (body), this.encode (this.secret), 'sha512');
            url += '?' + query + '&signature=' + signature;
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }

    async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let response = await this.fetch2 (path, api, method, params, headers, body);
        let code = this.safeInteger (response, 'code');
        let message = this.safeString (response, 'message');
        if (code && code !== 100 && message) {
            if (code === 103)
                throw new AuthenticationError (message);
            throw new ExchangeError (message);
        }
        return response;
    }
};
<|endoftext|>


<commit_before>jQuery(function($) {
	$("pre").addClass("prettyprint");
	prettyPrint();
});
<commit_msg>requires linenums class<commit_after>jQuery(function($) {
	$("pre").addClass("prettyprint linenums");
	prettyPrint();
});
<|endoftext|>


<commit_before>(function (Framework7, $$, T7, moment, hnapi) {
	'use strict';

	// Helpers
	T7.registerHelper('time_ago', function (time) {
		return moment.unix(time).fromNow();
	});
	T7.registerHelper('array_length', function (arr) {
		return arr ? arr.length : 0;
	});

	// Init App
	var app = new Framework7({
		modalTitle: 'HackerNews7',

		animateNavBackIcon: true,

		precompileTemplates: true,
		template7Pages: true
	});

	// Add View
	var mainView = app.addView('.view-main', {
		dynamicNavbar: true
	});

	// Update data
	function updateStories(stories) {
		app.template7Data.stories = stories;
		$$('.page[data-page="index"] .page-content .list-block').html(T7.templates.storiesTemplate(stories));
	}
	// Fetch Stories
	function getStories(refresh) {
		var results = refresh ? [] : JSON.parse(window.localStorage.getItem('stories')) || [];
		if (results.length === 0) {
			if (!refresh) app.showPreloader('Loading top stories : 0 %');
			var storiesCount = 0;
			hnapi.topStories(function (data) {
				data = JSON.parse(data);
				data.forEach(function(id) {
					hnapi.item(id, function(data) {
						data = JSON.parse(data);
						data.domain = data.url.split('/')[2];
						results.push(data);
						storiesCount++;
						$$('.page[data-page="index"]').find('.preloader-progress').text(Math.floor(storiesCount/100*100));
						if (results.length === 100) {
							if (!refresh) app.hidePreloader();
							// Update local storage data
							window.localStorage.setItem('stories', JSON.stringify(results));
							// PTR Done
							app.pullToRefreshDone();
							// Clear searchbar
							$$('.searchbar-input input')[0].value = '';
							// Update T7 data and render home page stories
							updateStories(results);
						}
					});
				});
			});
		}
		else {
			// Update T7 data and render home page stories
			updateStories(results);
		}
		return results;
	}

	// Update stories on PTR
	$$('.pull-to-refresh-content').on('refresh', function () {
		getStories(true);
	});

	// Comments
	var allowCommentsInsert;
	app.onPageAfterAnimation('item', function (page) {
		allowCommentsInsert = true;
		var id = $$(page.container).attr('data-story-id');
		var comments = [];
		var story;
		for (var i = 0; i < app.template7Data.stories.length; i++) {
			if (app.template7Data.stories[i].id === parseInt(id, 10)) {
				story = app.template7Data.stories[i];
			}
		}
		var commentsCount = 0;
		if(story.kids) {
			story.kids.forEach(function (child) {
				hnapi.item(child, function(data) {
					var comment = JSON.parse(data);
					if (comment.text && comment.text.length && !comment.deleted) comments.push(comment);
					commentsCount ++;

					$$(page.container).find('.preloader-progress').text(Math.floor(commentsCount/story.kids.length*100));
					if (commentsCount === story.kids.length && allowCommentsInsert) {
						$$(page.container).find('.story-comments .messages').html(T7.templates.commentsTemplate(comments));
					}
				});
			});
		} else {
			$$(page.container).find('.story-comments .messages').html('
No comment
');
		}
	});
	app.onPageBack('item', function () {
		allowCommentsInsert = false;
	});
	$$(document).on('click', '.message a', function (e) {
		window.open($$(this).attr('href'));
	});

	// Get and parse stories on app load
	getStories();

	// Export app to global
	window.app = app;

})(Framework7, Dom7, Template7, moment, hnapi);<commit_msg>fixes #5<commit_after>(function (Framework7, $$, T7, moment, hnapi) {
	'use strict';

	// Helpers
	T7.registerHelper('time_ago', function (time) {
		return moment.unix(time).fromNow();
	});
	T7.registerHelper('array_length', function (arr) {
		return arr ? arr.length : 0;
	});

	// Init App
	var app = new Framework7({
		modalTitle: 'HackerNews7',

		animateNavBackIcon: true,

		precompileTemplates: true,
		template7Pages: true
	});

	// Add View
	var mainView = app.addView('.view-main', {
		dynamicNavbar: true
	});

	// Update data
	function updateStories(stories) {
		app.template7Data.stories = stories;
		$$('.page[data-page="index"] .page-content .list-block').html(T7.templates.storiesTemplate(stories));
	}
	// Fetch Stories
	function getStories(refresh) {
		var results = refresh ? [] : JSON.parse(window.localStorage.getItem('stories')) || [];
		if (results.length === 0) {
			if (!refresh) app.showPreloader('Loading top stories : 0 %');
			var storiesCount = 0;
			hnapi.topStories(function (data) {
				data = JSON.parse(data);
				data.forEach(function(id) {
					hnapi.item(id, function(data) {
						data = JSON.parse(data);
						data.domain = data.url.split('/')[2];
						results.push(data);
						storiesCount++;
						$$('.preloader-progress').text(Math.floor(storiesCount/100*100));
						if (results.length === 100) {
							if (!refresh) app.hidePreloader();
							// Update local storage data
							window.localStorage.setItem('stories', JSON.stringify(results));
							// PTR Done
							app.pullToRefreshDone();
							// Clear searchbar
							$$('.searchbar-input input')[0].value = '';
							// Update T7 data and render home page stories
							updateStories(results);
						}
					});
				});
			});
		}
		else {
			// Update T7 data and render home page stories
			updateStories(results);
		}
		return results;
	}

	// Update stories on PTR
	$$('.pull-to-refresh-content').on('refresh', function () {
		getStories(true);
	});

	// Comments
	var allowCommentsInsert;
	app.onPageAfterAnimation('item', function (page) {
		allowCommentsInsert = true;
		var id = $$(page.container).attr('data-story-id');
		var comments = [];
		var story;
		for (var i = 0; i < app.template7Data.stories.length; i++) {
			if (app.template7Data.stories[i].id === parseInt(id, 10)) {
				story = app.template7Data.stories[i];
			}
		}
		var commentsCount = 0;
		if(story.kids) {
			story.kids.forEach(function (child) {
				hnapi.item(child, function(data) {
					var comment = JSON.parse(data);
					if (comment.text && comment.text.length && !comment.deleted) comments.push(comment);
					commentsCount ++;

					$$(page.container).find('.preloader-progress').text(Math.floor(commentsCount/story.kids.length*100));
					if (commentsCount === story.kids.length && allowCommentsInsert) {
						$$(page.container).find('.story-comments .messages').html(T7.templates.commentsTemplate(comments));
					}
				});
			});
		} else {
			$$(page.container).find('.story-comments .messages').html('
No comment
');
		}
	});
	app.onPageBack('item', function () {
		allowCommentsInsert = false;
	});
	$$(document).on('click', '.message a', function (e) {
		window.open($$(this).attr('href'));
	});

	// Get and parse stories on app load
	getStories();

	// Export app to global
	window.app = app;

})(Framework7, Dom7, Template7, moment, hnapi);<|endoftext|>


<commit_before>(function() {
  "use strict";
  var states = {
    MAIN: 0,
    VIEW: 1
  };

  var sequenceTypes = {
    ALPHABETICAL: 0,
    NUMERIC: 1
  };

  var casings = {
    LOWERCASE: 0,
    UPPERCASE: 1,
    MIXED: 2
  };

  var state = null;
  var baseUrl = null;
  var sequences = [];

  function byId(input) {
    return document.getElementById(input);
  }

  function byClass(input) {
    return document.getElementsByClassName(input);
  }

  function byTag(input) {
    return document.getElementsByTagName(input);
  }

  Element.prototype.byId = function(input) {
    return this.getElementById(input);
  };

  Element.prototype.byClass = function(input) {
    return this.getElementsByClassName(input);
  };

  Element.prototype.byTag = function(input) {
    return this.getElementsByTagName(input);
  };

  var casingHtml = '<select class="config"><option value="0">Lowercase</option><option value="1">Uppercase</option><option value="1">Mixed</option></select>';
  var paddingHtml = '<input class="config" type="number" value="PAD">';

  function addSequence(type, padding, casing, start) {
    var element = document.createElement("div");
    element.className = "sequence";
    element.innerHTML = '<select class="type"><option value="0">Alphabetical</option><option value="1">Numeric</option></select>
' +
      ' ' + (type === sequenceTypes.ALPHABETICAL ? casingHtml : paddingHtml.replace("PAD", padding)) +
      'Start at: <input type="text" class="start" value="' + (type === sequenceTypes.ALPHABETICAL ? "a" : "1") + '">';
    byId("sequences").appendChild(element);
    var sel = element.byClass("type")[0];
    sel.selectedIndex = type;
    sel.addEventListener("change", onTypeChange);
  }

  function addNewSequence() {
    addSequence(sequenceTypes.NUMERIC, 3, casings.LOWERCASE, 1);
  }

  function onTypeChange(e) {
      let elem = this.parentElement.byClass("config")[0];
      if (this.selectedIndex === sequenceTypes.ALPHABETICAL) {
        elem.outerHTML = casingHtml;
        this.parentElement.byClass("start")[0].value = "a";
      }
      else if (this.selectedIndex === sequenceTypes.NUMERIC) {
        elem.outerHTML = paddingHtml;
        this.parentElement.byClass("start")[0].value = "1";
      }
  }

  function removeSequence(index) {
    if (index > -1 && index < sequences.length) {
      sequences.splice(index, 1);
    }
  }

  function doNextSequence() {
    doSequence(++seqIndex);
  }

  function doPrevSequence() {
    doSequence(--seqIndex);
  }

  function doSequence() {
    if (sequences.length < 1) {
      alert("Error!");
    }
    if (seqIndex < 0) {
      seqIndex = 0;
    }
    var seq = sequences[0];
    var image = byId("image");
    var src = baseUrl;
    var name = seqIndex.toString();
    while (name.length < seq.padding) {
      name = "0" + name;
    }
    src += name + ".jpg";
    image.src = src;
    image.alt = src;
    setImageSize();
  }

  function onImageClick(e) {
    if (this.classList.contains("fit")) {
      this.classList.remove("fit");
      this.classList.add("full");
      this.removeAttribute("height");
      this.removeAttribute("width");
    }
    else {
      this.classList.add("fit");
      this.classList.remove("full");
      setImageSize();
    }
  }

  function start() {
    state = states.VIEW;
    buildSequences();
    byId("main").classList.add("hidden");
    byId("view").classList.remove("hidden");
    document.addEventListener("keydown", keyCheck);
    document.body.classList.add("view");
    window.addEventListener("resize", setImageSize);
    byId("image").addEventListener("click", onImageClick);
    doSequence();
  }

  function setImageSize() {
    var image = byId("image");
    image.removeAttribute("height");
    image.removeAttribute("width");
    if (image.classList.contains("fit")) {
      let height = image.height;
      let width = image.width;
      if (height > width) {
        if (height > window.innerHeight) {
          constrainByHeight(image);
        }
        else if (width > window.innerWidth) {
          constrainByWidth(image);
        }
      }
      else {
        if (width > window.innerWidth) {
          constrainByWidth(image);
        }
        else if (height > window.innerHeight) {
          constrainByHeight(image);
        }
      }
    }
  }

  function constrainByWidth(image) {
    let height = image.height;
    let width = image.width;
    height = Math.floor(height * (window.innerWidth / width));
    width = window.innerWidth;
    image.setAttribute("height", height);
    image.setAttribute("width", width);
  }

  function constrainByHeight(image) {
    let height = image.height;
    let width = image.width;
    width = Math.floor(width * (window.innerHeight / height));
    height = window.innerHeight;
    image.setAttribute("height", height);
    image.setAttribute("width", width);
  }

  function keyCheck(e) {
    if (e.keyCode === 39) {
      doNextSequence();
    }
    else if (e.keyCode === 37) {
      doPrevSequence();
    }
  }

  var seqIndex = 0;

  function buildSequences() {
    baseUrl = byId("base-url").value;
    sequences = [];
    var elems = byClass("sequence");
    for (let i = elems.length - 1; i >= 0; i--) {
      let elem = elems[i];
      let seq = {};
      let type = elem.byClass("type")[0].selectedIndex;
      seq.type = type;
      seq.start = elem.byClass("start")[0].value;
      if (type === sequenceTypes.ALPHABETICAL) {
        seq.padding = 0;
        seq.casing = elem.byClass("config")[0].selectedIndex;
      }
      else if (type === sequenceTypes.NUMERIC) {
        seq.padding = elem.byClass("config")[0].value;
        seq.casing = casings.LOWERCASE;
        seq.start = +seq.start;
      }
      sequences.push(seq);
    }
    seqIndex = sequences[0].start;
  }

  function setup() {
    document.removeEventListener("DOMContentLoaded", setup);
    state = states.MAIN;
    byId("add-sequence").addEventListener("click", addNewSequence);
    byId("start").addEventListener("click", start);
    addNewSequence();
  }

  document.addEventListener("DOMContentLoaded", setup);
}).call(this);
<commit_msg>Update img.js<commit_after>(function() {
  "use strict";
  var states = {
    MAIN: 0,
    VIEW: 1
  };

  var sequenceTypes = {
    ALPHABETICAL: 0,
    NUMERIC: 1
  };

  var casings = {
    LOWERCASE: 0,
    UPPERCASE: 1,
    MIXED: 2
  };

  var state = null;
  var baseUrl = null;
  var sequences = [];

  function byId(input) {
    return document.getElementById(input);
  }

  function byClass(input) {
    return document.getElementsByClassName(input);
  }

  function byTag(input) {
    return document.getElementsByTagName(input);
  }

  Element.prototype.byId = function(input) {
    return this.getElementById(input);
  };

  Element.prototype.byClass = function(input) {
    return this.getElementsByClassName(input);
  };

  Element.prototype.byTag = function(input) {
    return this.getElementsByTagName(input);
  };

  var casingHtml = '<select class="config"><option value="0">Lowercase</option><option value="1">Uppercase</option><option value="1">Mixed</option></select>';
  var paddingHtml = '<input class="config" type="number" value="PAD">';

  function addSequence(type, padding, casing, start) {
    var element = document.createElement("div");
    element.className = "sequence";
    element.innerHTML = '<select class="type"><option value="0">Alphabetical</option><option value="1">Numeric</option></select>
' +
      ' ' + (type === sequenceTypes.ALPHABETICAL ? casingHtml : paddingHtml.replace("PAD", padding)) +
      'Start at: <input type="text" class="start" value="' + (type === sequenceTypes.ALPHABETICAL ? "a" : "1") + '">';
    byId("sequences").appendChild(element);
    var sel = element.byClass("type")[0];
    sel.selectedIndex = type;
    sel.addEventListener("change", onTypeChange);
  }

  function addNewSequence() {
    addSequence(sequenceTypes.NUMERIC, 3, casings.LOWERCASE, 1);
  }

  function onTypeChange(e) {
      let elem = this.parentElement.byClass("config")[0];
      if (this.selectedIndex === sequenceTypes.ALPHABETICAL) {
        elem.outerHTML = casingHtml;
        this.parentElement.byClass("start")[0].value = "a";
      }
      else if (this.selectedIndex === sequenceTypes.NUMERIC) {
        elem.outerHTML = paddingHtml;
        this.parentElement.byClass("start")[0].value = "1";
      }
  }

  function removeSequence(index) {
    if (index > -1 && index < sequences.length) {
      sequences.splice(index, 1);
    }
  }

  function doNextSequence() {
    doSequence(++seqIndex);
  }

  function doPrevSequence() {
    doSequence(--seqIndex);
  }

  function doSequence() {
    if (sequences.length < 1) {
      alert("Error!");
    }
    if (seqIndex < 0) {
      seqIndex = 0;
    }
    var seq = sequences[0];
    var image = byId("image");
    var src = baseUrl;
    var name = seqIndex.toString();
    while (name.length < seq.padding) {
      name = "0" + name;
    }
    src += name + ".jpg";
    image.src = src;
    image.alt = src;
    setTimeout(setImageSize, 50);
  }

  function onImageClick(e) {
    if (this.classList.contains("fit")) {
      this.classList.remove("fit");
      this.classList.add("full");
      this.removeAttribute("height");
      this.removeAttribute("width");
    }
    else {
      this.classList.add("fit");
      this.classList.remove("full");
      setImageSize();
    }
  }

  function start() {
    state = states.VIEW;
    buildSequences();
    byId("main").classList.add("hidden");
    byId("view").classList.remove("hidden");
    document.addEventListener("keydown", keyCheck);
    document.body.classList.add("view");
    window.addEventListener("resize", setImageSize);
    byId("image").addEventListener("click", onImageClick);
    doSequence();
  }

  function setImageSize() {
    var image = byId("image");
    image.removeAttribute("height");
    image.removeAttribute("width");
    if (image.classList.contains("fit")) {
      let height = image.height;
      let width = image.width;
      if (height > width) {
        if (height > window.innerHeight) {
          constrainByHeight(image);
        }
        else if (width > window.innerWidth) {
          constrainByWidth(image);
        }
      }
      else {
        if (width > window.innerWidth) {
          constrainByWidth(image);
        }
        else if (height > window.innerHeight) {
          constrainByHeight(image);
        }
      }
    }
  }

  function constrainByWidth(image) {
    let height = image.height;
    let width = image.width;
    height = Math.floor(height * (window.innerWidth / width));
    width = window.innerWidth;
    image.setAttribute("height", height);
    image.setAttribute("width", width);
  }

  function constrainByHeight(image) {
    let height = image.height;
    let width = image.width;
    width = Math.floor(width * (window.innerHeight / height));
    height = window.innerHeight;
    image.setAttribute("height", height);
    image.setAttribute("width", width);
  }

  function keyCheck(e) {
    if (e.keyCode === 39) {
      doNextSequence();
    }
    else if (e.keyCode === 37) {
      doPrevSequence();
    }
  }

  var seqIndex = 0;

  function buildSequences() {
    baseUrl = byId("base-url").value;
    sequences = [];
    var elems = byClass("sequence");
    for (let i = elems.length - 1; i >= 0; i--) {
      let elem = elems[i];
      let seq = {};
      let type = elem.byClass("type")[0].selectedIndex;
      seq.type = type;
      seq.start = elem.byClass("start")[0].value;
      if (type === sequenceTypes.ALPHABETICAL) {
        seq.padding = 0;
        seq.casing = elem.byClass("config")[0].selectedIndex;
      }
      else if (type === sequenceTypes.NUMERIC) {
        seq.padding = elem.byClass("config")[0].value;
        seq.casing = casings.LOWERCASE;
        seq.start = +seq.start;
      }
      sequences.push(seq);
    }
    seqIndex = sequences[0].start;
  }

  function setup() {
    document.removeEventListener("DOMContentLoaded", setup);
    state = states.MAIN;
    byId("add-sequence").addEventListener("click", addNewSequence);
    byId("start").addEventListener("click", start);
    addNewSequence();
  }

  document.addEventListener("DOMContentLoaded", setup);
}).call(this);
<|endoftext|>