<commit_before>$(document).ready(function() {
    // paginate if value is set
    if($("#to_paginate").val() == "true"){
        paginate();
    }

    $("#coll_create").click(function() {
        if($("#new_coll_name").val() != ""){
            $.ajax({
                method: "POST",
                url: "/" + $("#conn_name").val() + "/" + $("#db_name").val()+ "/coll_create",
                data: {"collection_name" : $("#new_coll_name").val()}
            })
            .success(function(msg) {
                show_notification(msg,"success", true);
            })
            .error(function(msg) {
                show_notification(msg.responseText,"danger");
            });
        }else{
            show_notification("Please enter a collection name","danger");
        }
    });

    // To reset we call paginate() with no query object
    $("#searchReset").click(function() {
        localStorage.removeItem('searchQuery');
        window.location.href = "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/" + $("#coll_name").val() + "/view/1";
    });

    $("#queryDocumentsAction").click(function() {
        var editor = ace.edit("json");
        var editor_val = editor.getValue();

        if(editor_val != ""){
            // set the query in localStorage
            localStorage.setItem('searchQuery',editor_val);

            // go to page 1 to remove any issues being on page X from another query/view
            window.location.href = "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/" + $("#coll_name").val() + "/view/1";

            // close the queryDocuments
            $('#queryDocuments').modal('hide');
        }else{
            show_notification("Please enter a query","danger");
        }
    });

    // redirect to export
    $("#exportModalAction").click(function() {
        var exportId = $("#exportExcludeID").is(":checked") ? "true" : "false";
        window.location.href = "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/" + $('#export_coll').val() + "/export/" + exportId;
    });

    // sets the collection name to be used later to export entire collection
    $(".exportLink").click(function() {
        $('#exportExcludeID').prop('checked', false);
        $('#export_coll').val($(this).attr("id"));
    });

    // set the URL search parameters
    $("#searchModalAction").click(function() {
        var key_name = $("#search_key_fields option:selected").text();

        if (key_name === "_id") {
            key_name = "id";
        }
        var val = $("#search_value_value").val();
        if(key_name != "" && val != ""){
            // build the simply key/value query object and call paginate();
            var qry_obj = {};
            qry_obj[key_name] = val;

            // set the object to local storage to be used if page changes
            localStorage.setItem('searchQuery',JSON.stringify(qry_obj));

            // go to page 1 to remove any issues being on page X from another query/view
            window.location.href = "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/" + $("#coll_name").val() + "/view/1";

            // close the searchModal
            $('#searchModal').modal('hide');
        }else{
            show_notification("Please enter a key (field) and a value to search for","danger");
        }
    });

    $("#coll_name_edit").click(function() {
        var data = $("#coll_name_newval").val();
        if(data != ""){
            $.ajax({
                method: "POST",
                url: "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/" + $("#coll_name").val() + "/coll_name_edit",
                data: {"new_collection_name" : data}
            })
            .success(function(msg) {
                show_notification(msg,"success");
                window.location.href = "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/" + data + "/view?page=1";
            })
            .error(function(msg) {
                show_notification(msg.responseText,"danger");
            });
        }
        else{
            show_notification("Please enter an index","danger");
        }
    });

    $("#coll_delete").click(function() {
        if (confirm("WARNING: Are you sure you want to delete this collection and all documents?") == true) {
            $.ajax({
                method: "POST",
                url: "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/coll_delete",
                data: {"collection_name" : $("#del_coll_name option:selected" ).text()}
            })
            .success(function(msg) {
                show_notification(msg,"success", true);
            })
            .error(function(msg) {
                show_notification(msg.responseText,"danger");
            });
        }
    });

    $("#db_create").click(function() {
        if($("#new_db_name").val() != ""){
            $.ajax({
                method: "POST",
                url: "/" + $("#conn_name").val() + "/db_create",
                data: {"db_name" : $("#new_db_name").val()}
            })
            .success(function(msg) {
                show_notification(msg,"success", true);
            })
            .error(function(msg) {
                show_notification(msg.responseText,"danger");
            });
        }else{
            show_notification("Please enter a database name","danger");
        }
    });

    $("#db_delete").click(function() {
        if (confirm("WARNING: Are you sure you want to delete this collection and all documents?") == true) {
            $.ajax({
                method: "POST",
                url: "/" + $("#conn_name").val() + "/db_delete",
                data: {"db_name" : $("#del_db_name option:selected" ).text()}
            })
            .success(function(msg) {
                show_notification(msg,"success", true);
            })
            .error(function(msg) {
                show_notification(msg.responseText,"danger");
            });
        }else{
            show_notification("Please enter a database name","danger");
        }
    });

    $("#coll_addindex").click(function() {
        var edit = ace.edit("json");
        var json = $.parseJSON(edit.getValue());

        if(json != "{}"){
            var data_obj = {};
            data_obj[0] = JSON.stringify(json);
            data_obj[1] = $("#index_unique").is(":checked") ? "true" : "false";
            data_obj[2] = $("#index_sparse").is(":checked") ? "true" : "false";

            $.ajax({
                method: "POST",
                url: "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/" + $("#coll_name").val() + "/create_index",
                data: data_obj
            })
            .success(function(msg) {
                show_notification(msg,"success", true);
            })
            .error(function(msg) {
                show_notification(msg.responseText,"danger");
            });
        }
        else{
            show_notification("Please enter an index","danger");
        }
    });

    $("#user_create").click(function() {
        if($("#new_username").val() == ""){
            show_notification("Please enter a Username","danger");
            return;
        }
        if($("#new_password").val() == "" || $("#new_password_confirm").val() == ""){
            show_notification("Please enter a password and confirm","danger");
            return;
        }
        if($("#new_password").val() != $("#new_password_confirm").val()){
            show_notification("Passwords do not match","danger");
            return;
        }

        $.ajax({
            method: "POST",
            url: "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/na/user_create",
                data: {
                    "username": $("#new_username").val(),
                    "user_password": $("#new_password").val(),
                    "roles_text": $("#new_user_roles").val()
                }
        })
        .success(function(msg) {
            show_notification(msg,"success");
            setInterval(function() {
                window.location = "/" + $("#conn_name").val() + "/" + $("#db_name").val();
            }, 2000);
        })
        .error(function(msg) {
            show_notification(msg.responseText,"danger");
        });
    });

    $("#btnqueryDocuments").click(function() {
        var editor = ace.edit("json");
        if(localStorage.getItem('searchQuery')){
            editor.setValue(localStorage.getItem('searchQuery'));
        }else{
            editor.setValue("{}");
        }
    });

    $("#user_delete").click(function() {
        if(confirm("WARNING: Are you sure you want to delete this user?") == true) {
            $.ajax({
                method: "POST",
                url: "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/na/user_delete",
                data: {"username": $("#del_user_name option:selected" ).text()}
            })
            .success(function(msg) {
                show_notification(msg,"success");
                setInterval(function() {
                    window.location = "/" + $("#conn_name").val() + "/" + $("#db_name").val();
                }, 2000);
            })
            .error(function(msg) {
                show_notification(msg.responseText,"danger");
            });
        }
    });

    $("#add_config").click(function() {
        if($("#new_conf_conn_name").val() != "" && $("#new_conf_conn_string").val() != ""){
            var data_obj = {};
            data_obj[0] = $("#new_conf_conn_name").val();
            data_obj[1] = $("#new_conf_conn_string").val();

            $.ajax({
                method: "POST",
                url: "/add_config",
                data: data_obj
            })
            .success(function(msg) {
                show_notification(msg,"success");
                setInterval(function() {
                    location.reload();
                }, 2500);
            })
            .error(function(msg) {
                show_notification(msg.responseText,"danger");
            });
        }else{
            show_notification("Please enter both a connection name and connection string","danger");
        }
    });

    function redirect(url){
        window.location = url;
    }

    function paginate(){
        $('#doc_load_placeholder').show();

        var page_num = $('#page_num').val();
        var page_len = $('#docs_per_page').val();
        var coll_name = $('#coll_name').val();
        var conn_name = $('#conn_name').val();
        var db_name = $('#db_name').val();

        // get the query (if any)
        var query_string = localStorage.getItem('searchQuery');
        query_string = toEJSON.serializeString(query_string);

        // add search to the API URL if it exists
        var api_url = '/api/' +  conn_name + '/' + db_name + '/' + coll_name + '/' + page_num;
        var pager_href = '/' +  conn_name + '/' + db_name + '/' + coll_name + '/view/{{number}}';

        $.ajax({
            type: "POST",
            dataType: 'json',
            url: api_url,
            data: {"query" : query_string}
        })
        .done(function(response) {
            // show message when none are found
            if(response.data == ""){
                $('#doc_none_found').removeClass('hidden');
            }else{
                $('#doc_none_found').addClass('hidden');
            }

            var total_docs = Math.ceil(response.total_docs / page_len);

            $('#pager').bootpag({
                total: total_docs,
                page: page_num,
                maxVisible: 5,
                href: pager_href
            });

            //clear the div first
            $('#coll_docs').empty();
            for (var i = 0; i < response.data.length; i++) {
                var inner_html = '

' + JSON.stringify(response.data[i]) + '

';
                inner_html += '
Delete
';
                inner_html += '
Edit
';
                $('#coll_docs').append(inner_html);
            };

            //Bind the DropDown Select For Fields
            var option = '';
            for (var i=0;i<response.fields.length;i++){
               option += '<option value="'+ response.fields[i] + '">' + response.fields[i] + '</option>';
            }
            $('#search_key_fields').append(option);

            $('#doc_load_placeholder').hide();

            // hook up the syntax highlight and prettify the json
            $(".code-block").each(function (i, block) {
                var jsonString = this.textContent;
                var jsonPretty = JSON.stringify(JSON.parse(jsonString),null,2);
                $(this).html(jsonPretty);
                hljs.highlightBlock(block);
            });
        })
        .fail(function() {
            show_notification("Error getting data from Query API","danger");
        });
    }
});

function deleteDoc(doc_id){
    if(confirm("WARNING: Are you sure you want to delete this document?") == true) {
        $.ajax({
            method: "POST",
            url: "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/" + $("#coll_name").val() + "/doc_delete",
            data: {"doc_id": doc_id}
        })
        .success(function(msg) {
            show_notification(msg,"success", true);
        })
        .error(function(msg) {
            show_notification(msg.responseText,"danger");
        });
    }
}

function dropIndex(index_index){
    $.ajax({
        method: "POST",
        url: "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/" + $("#coll_name").val() + "/drop_index",
        data: {"index": index_index}
    })
    .success(function(msg) {
        show_notification(msg,"success", true);
    })
    .error(function(msg) {
        show_notification(msg.responseText,"danger");
    });
}

function dropConfig(config_index){
    if(confirm("WARNING: Are you sure you want to delete this connection?") == true) {
        $.ajax({
            method: "POST",
            url: "/drop_config",
            data: {"curr_config":  $("#curr_conf_conn_name_" + config_index).val()}
        })
        .success(function(msg) {
            show_notification(msg,"success");
            setInterval(function() {
                location.reload();
            }, 2500);
        })
        .error(function(msg) {
            show_notification(msg.responseText,"danger");
        });
    }
}

function updateConfig(config_index){
    if($("#conf_conn_name").val() != "" || $("#conf_conn_string").val() != "") {
        $.ajax({
            method: "POST",
            url: "/update_config",
            data: {"curr_config":  $("#curr_conf_conn_name_" + config_index).val(),"conn_name": $("#conf_conn_name_" + config_index).val(), "conn_string": $("#conf_conn_string_" + config_index).val()}
        })
        .success(function(msg) {
            show_notification(msg,"success");
            setInterval(function() {
                location.reload();
            }, 2500);
        })
        .error(function(msg) {
            show_notification(msg.responseText,"danger");
        });
    }else{
        show_notification("Please enter a connection name and connection string","danger");
    }
}

// show notification popup
function show_notification(msg, type, reload_page){
    // defaults to false
    reload_page = reload_page || false;

    $("#notify_message").removeClass();
    $("#notify_message").addClass('notify_message-' + type);
    $("#notify_message").html(msg);
    $('#notify_message').slideDown(600).delay(1200).slideUp(600, function() {
        if(reload_page == true){
            location.reload();
        }
    });
}<commit_msg>CleanUp<commit_after>$(document).ready(function() {
    // paginate if value is set
    if($("#to_paginate").val() == "true"){
        paginate();
    }

    $("#coll_create").click(function() {
        if($("#new_coll_name").val() != ""){
            $.ajax({
                method: "POST",
                url: "/" + $("#conn_name").val() + "/" + $("#db_name").val()+ "/coll_create",
                data: {"collection_name" : $("#new_coll_name").val()}
            })
            .success(function(msg) {
                show_notification(msg,"success", true);
            })
            .error(function(msg) {
                show_notification(msg.responseText,"danger");
            });
        }else{
            show_notification("Please enter a collection name","danger");
        }
    });

    // To reset we call paginate() with no query object
    $("#searchReset").click(function() {
        localStorage.removeItem('searchQuery');
        window.location.href = "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/" + $("#coll_name").val() + "/view/1";
    });

    $("#queryDocumentsAction").click(function() {
        var editor = ace.edit("json");
        var editor_val = editor.getValue();

        if(editor_val != ""){
            // set the query in localStorage
            localStorage.setItem('searchQuery',editor_val);

            // go to page 1 to remove any issues being on page X from another query/view
            window.location.href = "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/" + $("#coll_name").val() + "/view/1";

            // close the queryDocuments
            $('#queryDocuments').modal('hide');
        }else{
            show_notification("Please enter a query","danger");
        }
    });

    // redirect to export
    $("#exportModalAction").click(function() {
        var exportId = $("#exportExcludeID").is(":checked") ? "true" : "false";
        window.location.href = "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/" + $('#export_coll').val() + "/export/" + exportId;
    });

    // sets the collection name to be used later to export entire collection
    $(".exportLink").click(function() {
        $('#exportExcludeID').prop('checked', false);
        $('#export_coll').val($(this).attr("id"));
    });

    // set the URL search parameters
    $("#searchModalAction").click(function() {
        var key_name = $("#search_key_fields option:selected").text();
        var val = $("#search_value_value").val();
        if(key_name != "" && val != ""){
            // build the simply key/value query object and call paginate();
            var qry_obj = {};
            qry_obj[key_name] = val;

            // set the object to local storage to be used if page changes
            localStorage.setItem('searchQuery',JSON.stringify(qry_obj));

            // go to page 1 to remove any issues being on page X from another query/view
            window.location.href = "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/" + $("#coll_name").val() + "/view/1";

            // close the searchModal
            $('#searchModal').modal('hide');
        }else{
            show_notification("Please enter a key (field) and a value to search for","danger");
        }
    });

    $("#coll_name_edit").click(function() {
        var data = $("#coll_name_newval").val();
        if(data != ""){
            $.ajax({
                method: "POST",
                url: "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/" + $("#coll_name").val() + "/coll_name_edit",
                data: {"new_collection_name" : data}
            })
            .success(function(msg) {
                show_notification(msg,"success");
                window.location.href = "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/" + data + "/view?page=1";
            })
            .error(function(msg) {
                show_notification(msg.responseText,"danger");
            });
        }
        else{
            show_notification("Please enter an index","danger");
        }
    });

    $("#coll_delete").click(function() {
        if (confirm("WARNING: Are you sure you want to delete this collection and all documents?") == true) {
            $.ajax({
                method: "POST",
                url: "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/coll_delete",
                data: {"collection_name" : $("#del_coll_name option:selected" ).text()}
            })
            .success(function(msg) {
                show_notification(msg,"success", true);
            })
            .error(function(msg) {
                show_notification(msg.responseText,"danger");
            });
        }
    });

    $("#db_create").click(function() {
        if($("#new_db_name").val() != ""){
            $.ajax({
                method: "POST",
                url: "/" + $("#conn_name").val() + "/db_create",
                data: {"db_name" : $("#new_db_name").val()}
            })
            .success(function(msg) {
                show_notification(msg,"success", true);
            })
            .error(function(msg) {
                show_notification(msg.responseText,"danger");
            });
        }else{
            show_notification("Please enter a database name","danger");
        }
    });

    $("#db_delete").click(function() {
        if (confirm("WARNING: Are you sure you want to delete this collection and all documents?") == true) {
            $.ajax({
                method: "POST",
                url: "/" + $("#conn_name").val() + "/db_delete",
                data: {"db_name" : $("#del_db_name option:selected" ).text()}
            })
            .success(function(msg) {
                show_notification(msg,"success", true);
            })
            .error(function(msg) {
                show_notification(msg.responseText,"danger");
            });
        }else{
            show_notification("Please enter a database name","danger");
        }
    });

    $("#coll_addindex").click(function() {
        var edit = ace.edit("json");
        var json = $.parseJSON(edit.getValue());

        if(json != "{}"){
            var data_obj = {};
            data_obj[0] = JSON.stringify(json);
            data_obj[1] = $("#index_unique").is(":checked") ? "true" : "false";
            data_obj[2] = $("#index_sparse").is(":checked") ? "true" : "false";

            $.ajax({
                method: "POST",
                url: "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/" + $("#coll_name").val() + "/create_index",
                data: data_obj
            })
            .success(function(msg) {
                show_notification(msg,"success", true);
            })
            .error(function(msg) {
                show_notification(msg.responseText,"danger");
            });
        }
        else{
            show_notification("Please enter an index","danger");
        }
    });

    $("#user_create").click(function() {
        if($("#new_username").val() == ""){
            show_notification("Please enter a Username","danger");
            return;
        }
        if($("#new_password").val() == "" || $("#new_password_confirm").val() == ""){
            show_notification("Please enter a password and confirm","danger");
            return;
        }
        if($("#new_password").val() != $("#new_password_confirm").val()){
            show_notification("Passwords do not match","danger");
            return;
        }

        $.ajax({
            method: "POST",
            url: "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/na/user_create",
                data: {
                    "username": $("#new_username").val(),
                    "user_password": $("#new_password").val(),
                    "roles_text": $("#new_user_roles").val()
                }
        })
        .success(function(msg) {
            show_notification(msg,"success");
            setInterval(function() {
                window.location = "/" + $("#conn_name").val() + "/" + $("#db_name").val();
            }, 2000);
        })
        .error(function(msg) {
            show_notification(msg.responseText,"danger");
        });
    });

    $("#btnqueryDocuments").click(function() {
        var editor = ace.edit("json");
        if(localStorage.getItem('searchQuery')){
            editor.setValue(localStorage.getItem('searchQuery'));
        }else{
            editor.setValue("{}");
        }
    });

    $("#user_delete").click(function() {
        if(confirm("WARNING: Are you sure you want to delete this user?") == true) {
            $.ajax({
                method: "POST",
                url: "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/na/user_delete",
                data: {"username": $("#del_user_name option:selected" ).text()}
            })
            .success(function(msg) {
                show_notification(msg,"success");
                setInterval(function() {
                    window.location = "/" + $("#conn_name").val() + "/" + $("#db_name").val();
                }, 2000);
            })
            .error(function(msg) {
                show_notification(msg.responseText,"danger");
            });
        }
    });

    $("#add_config").click(function() {
        if($("#new_conf_conn_name").val() != "" && $("#new_conf_conn_string").val() != ""){
            var data_obj = {};
            data_obj[0] = $("#new_conf_conn_name").val();
            data_obj[1] = $("#new_conf_conn_string").val();

            $.ajax({
                method: "POST",
                url: "/add_config",
                data: data_obj
            })
            .success(function(msg) {
                show_notification(msg,"success");
                setInterval(function() {
                    location.reload();
                }, 2500);
            })
            .error(function(msg) {
                show_notification(msg.responseText,"danger");
            });
        }else{
            show_notification("Please enter both a connection name and connection string","danger");
        }
    });

    function redirect(url){
        window.location = url;
    }

    function paginate(){
        $('#doc_load_placeholder').show();

        var page_num = $('#page_num').val();
        var page_len = $('#docs_per_page').val();
        var coll_name = $('#coll_name').val();
        var conn_name = $('#conn_name').val();
        var db_name = $('#db_name').val();

        // get the query (if any)
        var query_string = localStorage.getItem('searchQuery');
        query_string = toEJSON.serializeString(query_string);

        // add search to the API URL if it exists
        var api_url = '/api/' +  conn_name + '/' + db_name + '/' + coll_name + '/' + page_num;
        var pager_href = '/' +  conn_name + '/' + db_name + '/' + coll_name + '/view/{{number}}';

        $.ajax({
            type: "POST",
            dataType: 'json',
            url: api_url,
            data: {"query" : query_string}
        })
        .done(function(response) {
            // show message when none are found
            if(response.data == ""){
                $('#doc_none_found').removeClass('hidden');
            }else{
                $('#doc_none_found').addClass('hidden');
            }

            var total_docs = Math.ceil(response.total_docs / page_len);

            $('#pager').bootpag({
                total: total_docs,
                page: page_num,
                maxVisible: 5,
                href: pager_href
            });

            //clear the div first
            $('#coll_docs').empty();
            for (var i = 0; i < response.data.length; i++) {
                var inner_html = '

' + JSON.stringify(response.data[i]) + '

';
                inner_html += '
Delete
';
                inner_html += '
Edit
';
                $('#coll_docs').append(inner_html);
            };

            //Bind the DropDown Select For Fields
            var option = '';
            for (var i=0;i<response.fields.length;i++){
               option += '<option value="'+ response.fields[i] + '">' + response.fields[i] + '</option>';
            }
            $('#search_key_fields').append(option);

            $('#doc_load_placeholder').hide();

            // hook up the syntax highlight and prettify the json
            $(".code-block").each(function (i, block) {
                var jsonString = this.textContent;
                var jsonPretty = JSON.stringify(JSON.parse(jsonString),null,2);
                $(this).html(jsonPretty);
                hljs.highlightBlock(block);
            });
        })
        .fail(function() {
            show_notification("Error getting data from Query API","danger");
        });
    }
});

function deleteDoc(doc_id){
    if(confirm("WARNING: Are you sure you want to delete this document?") == true) {
        $.ajax({
            method: "POST",
            url: "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/" + $("#coll_name").val() + "/doc_delete",
            data: {"doc_id": doc_id}
        })
        .success(function(msg) {
            show_notification(msg,"success", true);
        })
        .error(function(msg) {
            show_notification(msg.responseText,"danger");
        });
    }
}

function dropIndex(index_index){
    $.ajax({
        method: "POST",
        url: "/" + $("#conn_name").val() + "/" + $("#db_name").val() + "/" + $("#coll_name").val() + "/drop_index",
        data: {"index": index_index}
    })
    .success(function(msg) {
        show_notification(msg,"success", true);
    })
    .error(function(msg) {
        show_notification(msg.responseText,"danger");
    });
}

function dropConfig(config_index){
    if(confirm("WARNING: Are you sure you want to delete this connection?") == true) {
        $.ajax({
            method: "POST",
            url: "/drop_config",
            data: {"curr_config":  $("#curr_conf_conn_name_" + config_index).val()}
        })
        .success(function(msg) {
            show_notification(msg,"success");
            setInterval(function() {
                location.reload();
            }, 2500);
        })
        .error(function(msg) {
            show_notification(msg.responseText,"danger");
        });
    }
}

function updateConfig(config_index){
    if($("#conf_conn_name").val() != "" || $("#conf_conn_string").val() != "") {
        $.ajax({
            method: "POST",
            url: "/update_config",
            data: {"curr_config":  $("#curr_conf_conn_name_" + config_index).val(),"conn_name": $("#conf_conn_name_" + config_index).val(), "conn_string": $("#conf_conn_string_" + config_index).val()}
        })
        .success(function(msg) {
            show_notification(msg,"success");
            setInterval(function() {
                location.reload();
            }, 2500);
        })
        .error(function(msg) {
            show_notification(msg.responseText,"danger");
        });
    }else{
        show_notification("Please enter a connection name and connection string","danger");
    }
}

// show notification popup
function show_notification(msg, type, reload_page){
    // defaults to false
    reload_page = reload_page || false;

    $("#notify_message").removeClass();
    $("#notify_message").addClass('notify_message-' + type);
    $("#notify_message").html(msg);
    $('#notify_message').slideDown(600).delay(1200).slideUp(600, function() {
        if(reload_page == true){
            location.reload();
        }
    });
}<|endoftext|>


<commit_before>// Load gulp and global config
var gulp      = require('gulp');
var debug     = require('gulp-debug');
var config    = require('../config.json');
var argv      = require('yargs').argv;
var gulpif    = require('gulp-if');

// Specific task modules
var sourcemaps  = require('gulp-sourcemaps');
var postcss     = require('gulp-postcss');

// Postcss css4 specification modules
var atImport          = require('postcss-import');
var customProperties  = require('postcss-custom-properties');
var nesting           = require('postcss-nesting');
var calc              = require('postcss-calc');

// Postcss workflow modules
var lost          = require('lost');
var autoprefixer  = require('autoprefixer');
var pxtorem       = require('postcss-pxtorem');
var mqpacker      = require('css-mqpacker');
var cssnano       = require('cssnano');

// Postcss processors
if (argv.production) {
  var processors = [
    atImport(),
    customProperties(),
    nesting(),
    calc(),
    lost(),
    autoprefixer({ browsers: config.autoprefixer.browsers }),
    pxtorem({
      replace: true
    }),
    mqpacker(),
    cssnano()
  ];
}

else {
  var processors = [
    atImport(),
    customProperties(),
    nesting(),
    calc(),
    lost(),
    autoprefixer({ browsers: config.autoprefixer.browsers }),
    pxtorem({
      replace: true
    }),
    mqpacker()
  ];
}

// Postcss task
gulp.task('css', function () {
  return gulp.src(config.paths.css + '*.css')
    .pipe(gulpif(argv.debug === true, debug({title: 'CSS Processed:'})))
    .pipe(gulpif(!argv.production, sourcemaps.init())) // Sourcemaps if there is no production flag
    .pipe(postcss(processors))
    .pipe(gulpif(!argv.production, sourcemaps.write('.'))) // Sourcemaps if there is no production flag
    .pipe(gulp.dest(config.paths.buildAssets + 'css'));
});
<commit_msg>don't need to have two css processor variables<commit_after>// Load gulp and global config
var gulp      = require('gulp');
var debug     = require('gulp-debug');
var config    = require('../config.json');
var argv      = require('yargs').argv;
var gulpif    = require('gulp-if');

// Specific task modules
var sourcemaps  = require('gulp-sourcemaps');
var postcss     = require('gulp-postcss');

// Postcss css4 specification modules
var atImport          = require('postcss-import');
var customProperties  = require('postcss-custom-properties');
var nesting           = require('postcss-nesting');
var calc              = require('postcss-calc');

// Postcss workflow modules
var lost          = require('lost');
var autoprefixer  = require('autoprefixer');
var pxtorem       = require('postcss-pxtorem');
var mqpacker      = require('css-mqpacker');
var cssnano       = require('cssnano');

var processors = [
  atImport(),
  customProperties(),
  nesting(),
  calc(),
  lost(),
  autoprefixer({ browsers: config.autoprefixer.browsers }),
  pxtorem({
    replace: true
  }),
  mqpacker()
];

// Add cssnano if there is a production flag
if (argv.production) {
  processors.push(cssnano());
}

// Postcss task
gulp.task('css', function () {
  return gulp.src(config.paths.css + '*.css')
    .pipe(gulpif(argv.debug === true, debug({title: 'CSS Processed:'})))
    .pipe(gulpif(!argv.production, sourcemaps.init())) // Sourcemaps if there is no production flag
    .pipe(postcss(processors))
    .pipe(gulpif(!argv.production, sourcemaps.write('.'))) // Sourcemaps if there is no production flag
    .pipe(gulp.dest(config.paths.buildAssets + 'css'));
});
<|endoftext|>


<commit_before>import {run} from 'runjs'
import * as _ from "ramda"
import LineDriver from "line-driver"
import fs from "fs"
import tempy from "tempy"

function fixWarningsFrom(warnFilePath) {
    LineDriver.read({
        sync: true,
        in: warnFilePath,
        line: function (props, parser) {
            const line = parser.line
            // console.log(parser.line);

            if (props.fileName) {
                const lineNumRegexp = /^([0-9]+)\|/
                const match = lineNumRegexp.exec(line)
                if (match) {
                    run("line-replace " + props.fileName + ":" + match[1] + " > /dev/null")
                    props.fileName = null
                }

            } else {
                const unusedImportRegexp = /^-- unused import -* ([./a-zA-Z0-9]+)$/
                const match = unusedImportRegexp.exec(line)
                if (match) {
                    console.log(match[1]);
                    props.fileName = match[1]
                    // console.log("fileName", props.fileName)
                }
            }
        }
    })
    /*return new Promise(function (resolve, reject) {

    })*/

}
export const removeUnusedImports = function() {
    run("rimraf ./elm-stuff/build-artifacts/0.18.0/jigargosar")
    // run(`fish -c "rm -fv elm-stuff/build-artifacts/0.18.0/jigargosar/**/L-*.* ; or echo no match"`)

    const warnFilePath = '/tmp/main-warn.txt'

    run(`elm-make --warn src/elm/L/Main.elm --output /dev/null 2> ${warnFilePath}`)
    fixWarningsFrom(warnFilePath)

    run(`elm-make --warn src/elm/Main.elm --output /dev/null 2> ${warnFilePath}`)
    fixWarningsFrom(warnFilePath)

    run(`fish -c "elm-format --yes src/elm/**.elm"`)
}

export const parseWPD = function() {
    LineDriver.read({
        in: 'wp-dev-server.log',
        line: function (props, parser) {
            const line = parser.line
            // console.log(parser.line);

            if (props.fileName) {
                const lineNumRegexp = /^([0-9]+)\|/
                const match = lineNumRegexp.exec(line)
                if (match) {
                    // run("line-replace " + props.fileName + ":" + match[1] + " > /dev/null")
                    props.fileName = null
                }

            } else {
                // const unusedImportRegexp = /^-- PORT ERROR -+ ([./a-zA-Z0-9]+)$/
                const unusedImportRegexp = /^-- PORT ERROR -+ (.+)$/
                const match = unusedImportRegexp.exec(line)
                if (match) {
                    props.fileName = match[1]
                    console.error(props.fileName+":1-3 -- Error: Foo");
                    // console.log("fileName", props.fileName)
                }
            }
        }
    })
    // run("tail -F wp-dev-server.log")
}

function ruiHelp(elmFile) {
    if (_.isNil(elmFile) || !_.endsWith(".elm", elmFile) || !fs.existsSync(elmFile)) {
        console.error("Invalid file:", elmFile)
        return
    }

    const tmpFile = tempy.file({extension: 'log'});
    run(`echo " " >> ${elmFile}`)
    run(`elm-make --warn ${elmFile} --output /dev/null 2> ${tmpFile}`)
    LineDriver.read({
        sync: true,
        in: tmpFile,
        line: function (props, parser) {
            const line = parser.line
            // console.log(parser.line);

            if (props.fileName) {
                const lineNumRegexp = /^([0-9]+)\|/
                const match = lineNumRegexp.exec(line)
                if (match) {
                    run("line-replace " + props.fileName + ":" + match[1] + " > /dev/null")
                    props.fileName = null
                }

            } else {
                const unusedImportRegexp = /^-- unused import -* ([./a-zA-Z0-9]+)$/
                const match = unusedImportRegexp.exec(line)
                if (match) {
                    console.log(match[1]);
                    props.fileName = match[1]
                    // console.log("fileName", props.fileName)
                }
            }
        }
    })
    // console.log(tmpFile)
    run(`elm-format --yes ${elmFile}`)
}

function sleep(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms)
    })
}

export async function rui(...fileNames) {
    // run(`pkill -laf "/Users/jigargosar/GitHub/elm-simple-gtd/node_modules/.bin/nodemon" ;  true`)
    // run("pgrep -laf /Users/jigargosar/GitHub/elm-simple-gtd/ && true")
    // run("pkill -laf /Users/jigargosar/GitHub/elm-simple-gtd/ && true")
    // await sleep(100)
    console.log(fileNames)
    _.forEach(ruiHelp, fileNames)

}
<commit_msg>* try to reduce elm compile time<commit_after>import {run} from 'runjs'
import * as _ from "ramda"
import LineDriver from "line-driver"
import fs from "fs"
import tempy from "tempy"

function fixWarningsFrom(warnFilePath) {
    LineDriver.read({
        sync: true,
        in: warnFilePath,
        line: function (props, parser) {
            const line = parser.line
            // console.log(parser.line);

            if (props.fileName) {
                const lineNumRegexp = /^([0-9]+)\|/
                const match = lineNumRegexp.exec(line)
                if (match) {
                    run("line-replace " + props.fileName + ":" + match[1] + " > /dev/null")
                    props.fileName = null
                }

            } else {
                const unusedImportRegexp = /^-- unused import -* ([./a-zA-Z0-9]+)$/
                const match = unusedImportRegexp.exec(line)
                if (match) {
                    console.log(match[1]);
                    props.fileName = match[1]
                    // console.log("fileName", props.fileName)
                }
            }
        }
    })
    /*return new Promise(function (resolve, reject) {

    })*/

}
export const removeUnusedImports = function() {
    run("rimraf ./elm-stuff/build-artifacts/0.18.0/jigargosar")
    // run(`fish -c "rm -fv elm-stuff/build-artifacts/0.18.0/jigargosar/**/L-*.* ; or echo no match"`)

    const warnFilePath = '/tmp/main-warn.txt'

    run(`elm-make --warn src/elm/L/Main.elm --output /dev/null 2> ${warnFilePath}`)
    fixWarningsFrom(warnFilePath)

    run(`elm-make --warn src/elm/Main.elm --output /dev/null 2> ${warnFilePath}`)
    fixWarningsFrom(warnFilePath)

    run(`fish -c "elm-format --yes src/elm/**.elm"`)
}

export const parseWPD = function() {
    LineDriver.read({
        in: 'wp-dev-server.log',
        line: function (props, parser) {
            const line = parser.line
            // console.log(parser.line);

            if (props.fileName) {
                const lineNumRegexp = /^([0-9]+)\|/
                const match = lineNumRegexp.exec(line)
                if (match) {
                    // run("line-replace " + props.fileName + ":" + match[1] + " > /dev/null")
                    props.fileName = null
                }

            } else {
                // const unusedImportRegexp = /^-- PORT ERROR -+ ([./a-zA-Z0-9]+)$/
                const unusedImportRegexp = /^-- PORT ERROR -+ (.+)$/
                const match = unusedImportRegexp.exec(line)
                if (match) {
                    props.fileName = match[1]
                    console.error(props.fileName+":1-3 -- Error: Foo");
                    // console.log("fileName", props.fileName)
                }
            }
        }
    })
    // run("tail -F wp-dev-server.log")
}

const ruiHelp = _.curry((tmpFile, elmFile) =>{
    if (_.isNil(elmFile) || !_.endsWith(".elm", elmFile) || !fs.existsSync(elmFile)) {
        console.error("Invalid file:", elmFile)
        return
    }

    run(`echo " " >> ${elmFile}`)
    run(`elm-make --warn ${elmFile} --output /dev/null 2> ${tmpFile}`)
    LineDriver.read({
        sync: true,
        in: tmpFile,
        line: function (props, parser) {
            const line = parser.line
            // console.log(parser.line);

            if (props.fileName) {
                const lineNumRegexp = /^([0-9]+)\|/
                const match = lineNumRegexp.exec(line)
                if (match) {
                    run("line-replace " + props.fileName + ":" + match[1] + " > /dev/null")
                    props.fileName = null
                }

            } else {
                const unusedImportRegexp = /^-- unused import -* ([./a-zA-Z0-9]+)$/
                const match = unusedImportRegexp.exec(line)
                if (match) {
                    console.log(match[1]);
                    props.fileName = match[1]
                    // console.log("fileName", props.fileName)
                }
            }
        }
    })
    // console.log(tmpFile)
    run(`elm-format --yes ${elmFile}`)
}
)

function sleep(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms)
    })
}

export async function rui(...fileNames) {
    // run(`pkill -laf "/Users/jigargosar/GitHub/elm-simple-gtd/node_modules/.bin/nodemon" ;  true`)
    // run("pgrep -laf /Users/jigargosar/GitHub/elm-simple-gtd/ && true")
    // run("pkill -laf /Users/jigargosar/GitHub/elm-simple-gtd/ && true")
    // await sleep(100)
    const tmpFile = tempy.file({extension: 'log'});
    console.log(fileNames)
    _.forEach(ruiHelp(tmpFile), fileNames)
    run("rimraf " + tmpFile)

}
<|endoftext|>


<commit_before>'use strict';
var React = require('react');
var SvgIcon = require('../libs/svg-icons').SvgIcon;
var fetched = require('./fetched');
var search = require('./search');
var url = require('url');
var globals = require('./globals');
var parseAndLogError = require('./mixins').parseAndLogError;
var StickyHeader = require('./StickyHeader');
var _ = require('underscore');

var FacetList = search.FacetList;

var columnChoices = function(schema, selected) {
    // start with id
    var columns = {};
    columns['@id'] = {
        title: 'ID',
        visible: true
    };
    // default selected columns are the schema's `columns`,
    // or whichever of title, description, name, accession & aliases
    // are found in the schema's properties
    // (note, this has to match the defaults sent from the server)
    var schemaColumns = schema.columns;
    const defaultColumns = { title: 'Title', description: 'Description', name: 'Name', accession: 'Accession', aliases: 'Aliases' };
    if (schemaColumns === undefined) {
        schemaColumns = {};
        Object.keys(defaultColumns).forEach((name) => {
            if (schema.properties[name] !== undefined) {
                schemaColumns[name] = defaultColumns[name];
            }
        });
    }
    // add embedded columns
    _.each(schemaColumns, (column, path) => {
        columns[path] = {
            title: column,
            visible: !selected,
        };
    });

    // add all properties (with a few exceptions)
    _.each(schema.properties, (property, name) => {
        if (name == '@id' || name == '@type' || name == 'uuid' || name == 'replicates') return;
        if (!columns.hasOwnProperty(name) && property.title) {
            columns[name] = {
                title: property.title,
                visible: false
            };
        }
    });

    // if selected fields are specified, update visibility
    if (selected) {
        // Reset @id to not visible if not in selected
        if (!selected['@id'] && columns['@id']) {
            columns['@id'].visible = false;
        }
        _.each(selected, (path) => {
            if (columns[path] === undefined) {
                columns[path] = {
                    title: path,
                    visible: true
                };
            } else {
                columns[path].visible = true;
            }
        });
    }

    return columns;
};

var visibleColumns = function(columns) {
    var visible_columns = [];
    _.mapObject(columns, (column, path) => {
        if (column.visible) {
            visible_columns.push({
                path: path,
                title: column.title
            });
        }
    });
    return visible_columns;
};

var lookupColumn = function (result, column) {
    var nodes = [result];
    var names = column.split('.');

    // Get the column's custom display function and call it if it exists
    var colViewer = globals.report_cell.lookup(result, column);
    if (colViewer) {
        var colViewResult = colViewer(result, column);
        if (colViewResult) {
            return
{colViewResult}
;
        }
    }

    for (var i = 0, len = names.length; i < len && nodes.length; i++) {
        var nextnodes = [];
        _.each(nodes.map(node => node[names[i]]), v => {
            if (v === undefined) return;
            if (Array.isArray(v)) {
                nextnodes = nextnodes.concat(v);
            } else {
                nextnodes.push(v);
            }
        });
        if (names[i + 1] === 'length' || names[i + 1] === 'uuid') {
            // Displaying the length of an array. That's not a property of each array element so we
            // can't get it that way. Just return the length of the array.
            nodes = [nextnodes.length];
            break;
        } else {
            // Moving on to the next node defined by the `names` array.
            nodes = nextnodes;
        }
    }
    // if we ended with an embedded object, show the @id
    if (nodes.length && nodes[0]['@id'] !== undefined) {
        nodes = nodes.map(node => node['@id']);
    }
    return _.uniq(nodes).join(', ');
};

class Cell {
    constructor(value) {
        this.value = value;
    }
}

class Row {
    constructor(item, cells) {
        this.item = item;
        this.cells = cells;
    }
}

var RowView = function (props) {
    var row = props.row;
    var id = row.item['@id'];
    var tds = row.cells.map( function (cell, index) {
        if (index === 0) {
            return (
                {cell.value}
            );
        }
        return (
            {cell.value}
        );
    });
    return (

{tds}

    );
};

var Table = module.exports.Table = React.createClass({
    contextTypes: {
        location_href: React.PropTypes.string
    },

    extractData: function (items) {
        var columns = visibleColumns(this.props.columns);
        var rows = items.map(function (item) {
            var cells = columns.map(column => {
                var factory;
                var value = lookupColumn(item, column.path);
                if (column.path == '@id') {
                    factory = globals.listing_titles.lookup(item);
                    value = factory({context: item});
                } else if (value === null || value === undefined) {
                    value = '';
                } else if (value instanceof Array) {
                    value = value;
                } else if (value['@type']) {
                    factory = globals.listing_titles.lookup(value);
                    value = factory({context: value});
                }
                return new Cell(value);
            });
            return new Row(item, cells);
        });
        return rows;
    },

    getSort: function() {
        if (this.props.context.sort) {
            var sortColumn = Object.keys(this.props.context.sort)[0];
            return {
                column: sortColumn,
                reversed: this.props.context.sort[sortColumn].order == 'desc'
            };
        } else {
            return {};
        }
    },

    render: function () {
        var context = this.props.context;
        var columns = visibleColumns(this.props.columns);
        var sort = this.getSort();

        var headers = columns.map((column, index) => {
            var className = "icon";
            if (column.path === sort.column) {
                className += sort.reversed ? " icon-chevron-up" : " icon-chevron-down";
            }
            return (

                    {column.title}

            );
        });

        var data = this.extractData(context['@graph']).concat(this.extractData(this.props.more));
        var rows = data.map(row => RowView({row: row}));
        var table_class = "sticky-area collection-table";
        return (

                    <StickyHeader>

{headers}

                    </StickyHeader>

{rows}

        );
    },

    setSort: function(path) {
        const sort = this.getSort();
        const column = sort.column == path && !sort.reversed ? '-' + path : path;
        this.props.setSort(column);
    }

});

var ColumnSelector = React.createClass({
    getInitialState: function() {
        return {
            open: false
        };
    },

    render: function() {
        return (

                 Columns
                {this.state.open &&

Columns

                    {_.mapObject(this.props.columns, (column, path) =>

                        <input type="checkbox" checked={column.visible} /> {column.title}

)}

}

        );
    },

    toggle: function(e) {
        e.preventDefault();
        this.setState({open: !this.state.open});
    },

    toggleColumn: function(path) {
        this.props.toggleColumn(path);
    }
});

var Report = React.createClass({
    contextTypes: {
        location_href: React.PropTypes.string,
        navigate: React.PropTypes.func,
        fetch: React.PropTypes.func
    },

    getInitialState: function() {
        var parsed_url = url.parse(this.context.location_href, true);
        var from = parseInt(parsed_url.query.from) || 0;
        var size = parseInt(parsed_url.query.limit) || 25;
        return {
            from,
            size,
            to: from + size,
            loading: false,
            more: []
        };
    },

    componentWillReceiveProps: function(nextProps, nextContext) {
        // reset pagination when filter is changed
        if (nextContext.location_href != this.context.location_href) {
            var parsed_url = url.parse(this.context.location_href, true);
            var from = parseInt(parsed_url.query.from) || 0;
            var size = parseInt(parsed_url.query.limit) || 25;
            this.setState({
                from: from,
                to: from + size,
                more: []
            });
        }
    },

    render: function () {
        var parsed_url = url.parse(this.context.location_href, true);
        if (parsed_url.pathname.indexOf('/report') !== 0) return false;  // avoid breaking on re-render when navigate changes href before context is changed
        var context = this.props.context;
        var results = context['@graph'];
        var searchBase = parsed_url.search || '';
        searchBase = searchBase + (searchBase ? '&' : '?');

        var type = parsed_url.query.type;
        var schema = this.props.schemas[type];
        var query_fields = parsed_url.query.field;
        if (typeof query_fields === 'string') {
            query_fields = [query_fields];
        }
        var columns = columnChoices(schema, query_fields);

        // Map view icons to svg icons
        var view2svg = {
            'list-alt': 'search',
            'th': 'matrix'
        };

        return (

                            <FacetList facets={context.facets} filters={context.filters} searchBase={searchBase} />

                                Showing results {this.state.from + 1} to {Math.min(context.total, this.state.to)} of {context.total}

                                    {context.views && context.views.map((view, i) => {
                                        // Strip any `field` properties out of the view's href as
                                        // they don't apply to search or matrix
                                        var parsedUrl = url.parse(view.href, true);
                                        delete parsedUrl.query.field;
                                        delete parsedUrl.search;
                                        var href = url.format(parsedUrl);
                                        return {SvgIcon(view2svg[view.icon])};
                                    })}

                                <ColumnSelector columns={columns} toggleColumn={this.toggleColumn} />
                                Download TSV

                            {this.state.to < context.total &&

                                    {this.state.loading ?

                                    : Load more} Showing
                                    results {this.state.from + 1} to {Math.min(context.total, this.state.to)} of {context.total}

                            }

        );
    },

    toggleColumn: function(toggled_path) {
        var parsed_url = url.parse(this.context.location_href, true);
        var type = parsed_url.query.type;
        var schema = this.props.schemas[type];
        var query_fields = parsed_url.query.field ? (typeof parsed_url.query.field === 'object' ? parsed_url.query.field : [parsed_url.query.field]) : undefined;
        var columns = columnChoices(schema, query_fields);

        var fields = [];
        _.mapObject(columns, (column, path) => {
            if (path == toggled_path ? !column.visible : column.visible) {
                fields.push(path);
            }
        });
        parsed_url.query.field = fields;
        delete parsed_url.search;
        this.context.navigate(url.format(parsed_url));
    },

    setSort: function(sort) {
        var parsed_url = url.parse(this.context.location_href, true);
        parsed_url.query.sort = sort;
        delete parsed_url.search;
        this.context.navigate(url.format(parsed_url));
    },

    loadMore: function() {
        if (this.state.request) {
            this.state.request.abort();
        }
        var parsed_url = url.parse(this.context.location_href, true);
        parsed_url.query.from = this.state.to;
        delete parsed_url.search;
        var request = this.context.fetch(url.format(parsed_url), {
            headers: {'Accept': 'application/json'}
        });
        request.then(response => {
            if (!response.ok) throw response;
            return response.json();
        })
        .catch(parseAndLogError.bind(undefined, 'loadMore'))
        .then(data => {
            this.setState({
                more: this.state.more.concat(data['@graph']),
                loading: false,
                request: null
            });
        });

        this.setState({
            request: request,
            to: this.state.to + this.state.size,
            loading: true
        });
    },

    componentWillUnmount: function () {
        if (this.state.request) this.state.request.abort();
    }
});

var ReportLoader = React.createClass({
    render: function() {
        return (
            <fetched.FetchedData>
                <fetched.Param name="schemas" url="/profiles/" />
                <Report context={this.props.context} />
            </fetched.FetchedData>
        );
    }
});

globals.content_views.register(ReportLoader, 'Report');

// Custom cell-display function example.
// var CustomCellDisplay = function(item, column property name) {
//     if (displayCondition) {
//        return (
//            {display}
//        );
//     }
//
//     // No custom display necessary for the requested column
//     return null;
// };

// Register cell-display components
// globals.report_cell.register(CustomCellDisplay, @type[0] in quotes, column property name in quotes);
<commit_msg>Fix problem with titles concated with types<commit_after>'use strict';
var React = require('react');
var SvgIcon = require('../libs/svg-icons').SvgIcon;
var fetched = require('./fetched');
var search = require('./search');
var url = require('url');
var globals = require('./globals');
var parseAndLogError = require('./mixins').parseAndLogError;
var StickyHeader = require('./StickyHeader');
var _ = require('underscore');

var FacetList = search.FacetList;

var columnChoices = function(schema, selected) {
    // start with id
    var columns = {};
    columns['@id'] = {
        title: 'ID',
        visible: true
    };
    // default selected columns are the schema's `columns`,
    // or whichever of title, description, name, accession & aliases
    // are found in the schema's properties
    // (note, this has to match the defaults sent from the server)
    var schemaColumns = schema.columns;
    const defaultColumns = { title: 'Title', description: 'Description', name: 'Name', accession: 'Accession', aliases: 'Aliases' };
    if (schemaColumns === undefined) {
        schemaColumns = {};
        Object.keys(defaultColumns).forEach((name) => {
            if (schema.properties[name] !== undefined) {
                schemaColumns[name] = { title: defaultColumns[name], type: 'string' };
            }
        });
    }
    // add embedded columns
    _.each(schemaColumns, (column, path) => {
        columns[path] = {
            title: column.title,
            visible: !selected,
        };
    });

    // add all properties (with a few exceptions)
    _.each(schema.properties, (property, name) => {
        if (name == '@id' || name == '@type' || name == 'uuid' || name == 'replicates') return;
        if (!columns.hasOwnProperty(name) && property.title) {
            columns[name] = {
                title: property.title,
                visible: false
            };
        }
    });

    // if selected fields are specified, update visibility
    if (selected) {
        // Reset @id to not visible if not in selected
        if (!selected['@id'] && columns['@id']) {
            columns['@id'].visible = false;
        }
        _.each(selected, (path) => {
            if (columns[path] === undefined) {
                columns[path] = {
                    title: path,
                    visible: true
                };
            } else {
                columns[path].visible = true;
            }
        });
    }

    return columns;
};

var visibleColumns = function(columns) {
    var visible_columns = [];
    _.mapObject(columns, (column, path) => {
        if (column.visible) {
            visible_columns.push({
                path: path,
                title: column.title
            });
        }
    });
    return visible_columns;
};

var lookupColumn = function (result, column) {
    var nodes = [result];
    var names = column.split('.');

    // Get the column's custom display function and call it if it exists
    var colViewer = globals.report_cell.lookup(result, column);
    if (colViewer) {
        var colViewResult = colViewer(result, column);
        if (colViewResult) {
            return
{colViewResult}
;
        }
    }

    for (var i = 0, len = names.length; i < len && nodes.length; i++) {
        var nextnodes = [];
        _.each(nodes.map(node => node[names[i]]), v => {
            if (v === undefined) return;
            if (Array.isArray(v)) {
                nextnodes = nextnodes.concat(v);
            } else {
                nextnodes.push(v);
            }
        });
        if (names[i + 1] === 'length' || names[i + 1] === 'uuid') {
            // Displaying the length of an array. That's not a property of each array element so we
            // can't get it that way. Just return the length of the array.
            nodes = [nextnodes.length];
            break;
        } else {
            // Moving on to the next node defined by the `names` array.
            nodes = nextnodes;
        }
    }
    // if we ended with an embedded object, show the @id
    if (nodes.length && nodes[0]['@id'] !== undefined) {
        nodes = nodes.map(node => node['@id']);
    }
    return _.uniq(nodes).join(', ');
};

class Cell {
    constructor(value) {
        this.value = value;
    }
}

class Row {
    constructor(item, cells) {
        this.item = item;
        this.cells = cells;
    }
}

var RowView = function (props) {
    var row = props.row;
    var id = row.item['@id'];
    var tds = row.cells.map( function (cell, index) {
        if (index === 0) {
            return (
                {cell.value}
            );
        }
        return (
            {cell.value}
        );
    });
    return (

{tds}

    );
};

var Table = module.exports.Table = React.createClass({
    contextTypes: {
        location_href: React.PropTypes.string
    },

    extractData: function (items) {
        var columns = visibleColumns(this.props.columns);
        var rows = items.map(function (item) {
            var cells = columns.map(column => {
                var factory;
                var value = lookupColumn(item, column.path);
                if (column.path == '@id') {
                    factory = globals.listing_titles.lookup(item);
                    value = factory({context: item});
                } else if (value === null || value === undefined) {
                    value = '';
                } else if (value instanceof Array) {
                    value = value;
                } else if (value['@type']) {
                    factory = globals.listing_titles.lookup(value);
                    value = factory({context: value});
                }
                return new Cell(value);
            });
            return new Row(item, cells);
        });
        return rows;
    },

    getSort: function() {
        if (this.props.context.sort) {
            var sortColumn = Object.keys(this.props.context.sort)[0];
            return {
                column: sortColumn,
                reversed: this.props.context.sort[sortColumn].order == 'desc'
            };
        } else {
            return {};
        }
    },

    render: function () {
        var context = this.props.context;
        var columns = visibleColumns(this.props.columns);
        var sort = this.getSort();

        var headers = columns.map((column, index) => {
            var className = "icon";
            if (column.path === sort.column) {
                className += sort.reversed ? " icon-chevron-up" : " icon-chevron-down";
            }
            return (

                    {column.title}

            );
        });

        var data = this.extractData(context['@graph']).concat(this.extractData(this.props.more));
        var rows = data.map(row => RowView({row: row}));
        var table_class = "sticky-area collection-table";
        return (

                    <StickyHeader>

{headers}

                    </StickyHeader>

{rows}

        );
    },

    setSort: function(path) {
        const sort = this.getSort();
        const column = sort.column == path && !sort.reversed ? '-' + path : path;
        this.props.setSort(column);
    }

});

var ColumnSelector = React.createClass({
    getInitialState: function() {
        return {
            open: false
        };
    },

    render: function() {
        return (

                 Columns
                {this.state.open &&

Columns

                    {_.mapObject(this.props.columns, (column, path) =>

                        <input type="checkbox" checked={column.visible} /> {column.title}

)}

}

        );
    },

    toggle: function(e) {
        e.preventDefault();
        this.setState({open: !this.state.open});
    },

    toggleColumn: function(path) {
        this.props.toggleColumn(path);
    }
});

var Report = React.createClass({
    contextTypes: {
        location_href: React.PropTypes.string,
        navigate: React.PropTypes.func,
        fetch: React.PropTypes.func
    },

    getInitialState: function() {
        var parsed_url = url.parse(this.context.location_href, true);
        var from = parseInt(parsed_url.query.from) || 0;
        var size = parseInt(parsed_url.query.limit) || 25;
        return {
            from,
            size,
            to: from + size,
            loading: false,
            more: []
        };
    },

    componentWillReceiveProps: function(nextProps, nextContext) {
        // reset pagination when filter is changed
        if (nextContext.location_href != this.context.location_href) {
            var parsed_url = url.parse(this.context.location_href, true);
            var from = parseInt(parsed_url.query.from) || 0;
            var size = parseInt(parsed_url.query.limit) || 25;
            this.setState({
                from: from,
                to: from + size,
                more: []
            });
        }
    },

    render: function () {
        var parsed_url = url.parse(this.context.location_href, true);
        if (parsed_url.pathname.indexOf('/report') !== 0) return false;  // avoid breaking on re-render when navigate changes href before context is changed
        var context = this.props.context;
        var results = context['@graph'];
        var searchBase = parsed_url.search || '';
        searchBase = searchBase + (searchBase ? '&' : '?');

        var type = parsed_url.query.type;
        var schema = this.props.schemas[type];
        var query_fields = parsed_url.query.field;
        if (typeof query_fields === 'string') {
            query_fields = [query_fields];
        }
        var columns = columnChoices(schema, query_fields);

        // Map view icons to svg icons
        var view2svg = {
            'list-alt': 'search',
            'th': 'matrix'
        };

        return (

                            <FacetList facets={context.facets} filters={context.filters} searchBase={searchBase} />

                                Showing results {this.state.from + 1} to {Math.min(context.total, this.state.to)} of {context.total}

                                    {context.views && context.views.map((view, i) => {
                                        // Strip any `field` properties out of the view's href as
                                        // they don't apply to search or matrix
                                        var parsedUrl = url.parse(view.href, true);
                                        delete parsedUrl.query.field;
                                        delete parsedUrl.search;
                                        var href = url.format(parsedUrl);
                                        return {SvgIcon(view2svg[view.icon])};
                                    })}

                                <ColumnSelector columns={columns} toggleColumn={this.toggleColumn} />
                                Download TSV

                            {this.state.to < context.total &&

                                    {this.state.loading ?

                                    : Load more} Showing
                                    results {this.state.from + 1} to {Math.min(context.total, this.state.to)} of {context.total}

                            }

        );
    },

    toggleColumn: function(toggled_path) {
        var parsed_url = url.parse(this.context.location_href, true);
        var type = parsed_url.query.type;
        var schema = this.props.schemas[type];
        var query_fields = parsed_url.query.field ? (typeof parsed_url.query.field === 'object' ? parsed_url.query.field : [parsed_url.query.field]) : undefined;
        var columns = columnChoices(schema, query_fields);

        var fields = [];
        _.mapObject(columns, (column, path) => {
            if (path == toggled_path ? !column.visible : column.visible) {
                fields.push(path);
            }
        });
        parsed_url.query.field = fields;
        delete parsed_url.search;
        this.context.navigate(url.format(parsed_url));
    },

    setSort: function(sort) {
        var parsed_url = url.parse(this.context.location_href, true);
        parsed_url.query.sort = sort;
        delete parsed_url.search;
        this.context.navigate(url.format(parsed_url));
    },

    loadMore: function() {
        if (this.state.request) {
            this.state.request.abort();
        }
        var parsed_url = url.parse(this.context.location_href, true);
        parsed_url.query.from = this.state.to;
        delete parsed_url.search;
        var request = this.context.fetch(url.format(parsed_url), {
            headers: {'Accept': 'application/json'}
        });
        request.then(response => {
            if (!response.ok) throw response;
            return response.json();
        })
        .catch(parseAndLogError.bind(undefined, 'loadMore'))
        .then(data => {
            this.setState({
                more: this.state.more.concat(data['@graph']),
                loading: false,
                request: null
            });
        });

        this.setState({
            request: request,
            to: this.state.to + this.state.size,
            loading: true
        });
    },

    componentWillUnmount: function () {
        if (this.state.request) this.state.request.abort();
    }
});

var ReportLoader = React.createClass({
    render: function() {
        return (
            <fetched.FetchedData>
                <fetched.Param name="schemas" url="/profiles/" />
                <Report context={this.props.context} />
            </fetched.FetchedData>
        );
    }
});

globals.content_views.register(ReportLoader, 'Report');

// Custom cell-display function example.
// var CustomCellDisplay = function(item, column property name) {
//     if (displayCondition) {
//        return (
//            {display}
//        );
//     }
//
//     // No custom display necessary for the requested column
//     return null;
// };

// Register cell-display components
// globals.report_cell.register(CustomCellDisplay, @type[0] in quotes, column property name in quotes);
<|endoftext|>


<commit_before>// use lodash instead of underscore
// https://github.com/meteor/meteor/issues/1009
_ = lodash;

Utilities = {

  getBitDataId: function (bitHtmlElement){
    // TODO: improve so either an HTML element/node, or a jQuery obj works.
    // Greensock does this, look at source
    return $(bitHtmlElement).data('id');
  },

  getBitElement: function (bitDatabaseId){
    return $("[data-id='" + bitDatabaseId + "']");
  },

  getBitTemplate: function (bitId){
    var $bit = this.getBitElement(bitId);
    return Blaze.getView( _.first($bit) );
  },

  // person interacts with only one map at a time, ie singleton obj
  getMapTemplate: function (){
    var mapElement = _.first( $(".map") );
    var mapView = Blaze.getView( mapElement );
    return mapView.templateInstance();
  },

  // Usually, we'd just use jQuery's .position method.
  // In situations where the element is display:none, we can use the transform
  // property, if it's set, to get the position
  getTransformedPosition: function(element){
    var cssTransform = element.style["transform"];
    var pattern = /[,();]|(px)|(em)|(rem)|(translate)|(matrix)|(3d)/gi;

    // slice + dice the string with a regexp to remove everything except
    // for number values. Split the string into an array.
    var array = _.words(cssTransform.replace(pattern, ''));

    return {
      top: array[0],
      left: array[1]
    };
  },

  getClass: function(object){
    // http://phpjs.org/functions/getClass
    // http://kevin.vanzonneveld.net
    // +   original by: Ates Goral (http://magnetiq.com)
    // +   improved by: David James
    // +   improved by: David Neilsen

    // *     example 1: getClass(new (function MyClass() {}));
    // *     returns 1: "MyClass"

    // *     example 2: getClass({});
    // *     returns 2: "Object"

    // *     example 3: getClass([]);
    // *     returns 3: false

    // *     example 4: getClass(42);
    // *     returns 4: false

    // *     example 5: getClass(window);
    // *     returns 5: false

    // *     example 6: getClass(function MyFunction() {});
    // *     returns 6: false
    if (object && typeof object === 'object' &&
        Object.prototype.toString.call(object) !== '[object Array]' &&
        object.constructor && object !== this.window)
    {

      var arr = object.constructor.toString().match(/function\s*(\w+)/);

      if (arr && arr.length === 2) {
        return arr[1];
      }
    }

    return false;
  },

  getRandomColor: function() {
    return 'rgb('
      + Math.floor(Math.random() * 255) + ','
      + Math.floor(Math.random() * 255) + ','
      + Math.floor(Math.random() * 255) + ')';
  },

  getViewportCenter: function(){
    return {
      x: verge.viewportW() / 2,
      y: verge.viewportH() / 2
    }
  }

};
<commit_msg>bit:shimmer- fixing Safari bug<commit_after>// use lodash instead of underscore
// https://github.com/meteor/meteor/issues/1009
_ = lodash;

Utilities = {

  getBitDataId: function (bitHtmlElement){
    // TODO: improve so either an HTML element/node, or a jQuery obj works.
    // Greensock does this, look at source
    return $(bitHtmlElement).data('id');
  },

  getBitElement: function (bitDatabaseId){
    return $("[data-id='" + bitDatabaseId + "']");
  },

  getBitTemplate: function (bitId){
    var $bit = this.getBitElement(bitId);
    return Blaze.getView( _.first($bit) );
  },

  // person interacts with only one map at a time, ie singleton obj
  getMapTemplate: function (){
    var mapElement = _.first( $(".map") );
    var mapView = Blaze.getView( mapElement );
    return mapView.templateInstance();
  },

  // Usually, we'd just use jQuery's .position method.
  // In situations where the element is display:none, we can use the transform
  // property, if it's set, to get the position
  getTransformedPosition: function(element){
    var cssTransform = element.style["transform"] || element.style["webkitTransform"];
    var pattern = /[,();]|(px)|(em)|(rem)|(translate)|(matrix)|(3d)/gi;

    // slice + dice the string with a regexp to remove everything except
    // for number values. Split the string into an array.
    var array = _.words(cssTransform.replace(pattern, ''));

    return {
      top: array[0],
      left: array[1]
    };
  },

  getClass: function(object){
    // http://phpjs.org/functions/getClass
    // http://kevin.vanzonneveld.net
    // +   original by: Ates Goral (http://magnetiq.com)
    // +   improved by: David James
    // +   improved by: David Neilsen

    // *     example 1: getClass(new (function MyClass() {}));
    // *     returns 1: "MyClass"

    // *     example 2: getClass({});
    // *     returns 2: "Object"

    // *     example 3: getClass([]);
    // *     returns 3: false

    // *     example 4: getClass(42);
    // *     returns 4: false

    // *     example 5: getClass(window);
    // *     returns 5: false

    // *     example 6: getClass(function MyFunction() {});
    // *     returns 6: false
    if (object && typeof object === 'object' &&
        Object.prototype.toString.call(object) !== '[object Array]' &&
        object.constructor && object !== this.window)
    {

      var arr = object.constructor.toString().match(/function\s*(\w+)/);

      if (arr && arr.length === 2) {
        return arr[1];
      }
    }

    return false;
  },

  getRandomColor: function() {
    return 'rgb('
      + Math.floor(Math.random() * 255) + ','
      + Math.floor(Math.random() * 255) + ','
      + Math.floor(Math.random() * 255) + ')';
  },

  getViewportCenter: function(){
    return {
      x: verge.viewportW() / 2,
      y: verge.viewportH() / 2
    }
  }

};
<|endoftext|>


<commit_before>var Static = require('node-static');
var http = require('http');
var Spider = require('node-spider');
var assert = require('assert');
var config = require('./config.js');
var _ = require('lodash');

function length(obj) {
  var size = 0, key;
  for (key in obj) {
    if (obj.hasOwnProperty(key)) size++;
  }
  return size;
}

/**
 * Export closure, so that checkLinks can be used in gulp without
 * creating an anonymous function.
 *
 * @module.exports
 * @param {string} start URL where crawler should start looking for links.
 * @return {function} checkLinks Calling checkLinks will start crawling.
 */
module.exports = function(start) {
  /**
  * checkLinks crawls all pages and check that href and src attributes does
  * have a HTTP 200 response. It checks links outside the start domain, but
  * does _not_ crawl pages outside start.
  *
  * @param {function} cb Called when all links have been checked.
  */
  return function checkLinks(cb){
    console.log('Checking all links found at ' + start);
    var webserver;

    if (start.search('http://localhost') === 0) {
      // we need to start a web server
      var files = new Static.Server(config.buildRoot);
      webserver = http.createServer(function (request, response) {
        request.addListener('end', function () {
          files.serve(request, response);
        }).resume();
      });
      webserver.listen(3000, crawl);
    } else {
      crawl();
    }
    function crawl(){
      var resources = {};  // dict of referrers {link: [referrer1, referrer2, ..], link2..}
      resources[start] = ['start'];
      var failed = [];  // list of failed links
      var ok = 0;  // number of OK links
      var broken = 0;  // number of broken links

      var opts = {
        concurrent: 5,
        done: done,
        error: error,
        headers: { 'user-agent': 'codeclub_lesson_builder' },
        timeout: 5000
      };  // spider options

      // text spider for HTML, CSS, etc
      textSpider = new Spider(opts);

      // HEAD requests on external sites and binary files
      headOpts = _.assign({}, opts);
      headOpts.method = 'HEAD';
      headSpider = new Spider(headOpts);

      // let's go! :-)
      textSpider.queue(start, parseResponse);

      /**
       * on OK link
       */
      function parseResponse(doc){
        // check status code
        var code = doc.res.statusCode;
        if (code !== 200 && this.opts.method === 'HEAD') {
          // try again with GET-method
          textSpider.queue(this.opts.url, parseResponse);
          return;
        }
        if (code !== 200) {
          process.stdout.write('x'); // give some feedback
          broken += 1;
          failed.push({u:doc.url, c:code});
          return;
        } else {
          ok += 1;
          process.stdout.write('.'); // give some feedback
        }

        // do not parse binary files
        if (!/text|css|json|xml/i.test(doc.res.headers['content-type'])) {
          return;
        }

        // only crawl links below start (not other domains)
        if (doc.url.search(start) === 0) {

          // all elements with href set
          doc.$('*[href]').each(queueUrl('href'));

          // all elements with src set
          doc.$('*[src]').each(queueUrl('src'));
        }

        /**
         * queueUrl closure
         */
        function queueUrl(type){
          return function(){
            var href = doc.$(this).attr(type);
            // do not add mailto and javascript links
            if (href.search(/^(mailto|javascript)/) === 0) {
              return;
            }
            // do not check #-link explicit
            var url = doc.resolve(href).split('#')[0];
            // already added
            if (url in resources) {
              // add referrer
              resources[url].push(doc.url);
              return;
            }
            // external sites or binaries
            if (url.search(start) !==0 ||
                url.search(/\.(jpg|png|gif|zip)$/) === 0) {
              headSpider.queue(url, parseResponse);
            } else {  // text, e.g., HTML, CSS, etc
              textSpider.queue(url, parseResponse);
            }
            // store referrer
            resources[url] = [doc.url];
          }
        }
      };

      /**
       * on broken link
       */
      function error(err, url) {
          process.stdout.write('!'); // give some feedback
          broken += 1;
          failed.push({u:url, c:err.code});
      }

      /**
       * print results and exit
       */
      function done() {
        // wait until both spiders are done
        if (textSpider.active.length !== 0 || headSpider.active.length !== 0) {
          return
        }

        console.log('\nLink check done');
        console.log('---------------');
        console.log('Links OK:', ok);
        console.log('Links broken:', broken);
        console.log('---------------');

        failed.forEach(function(fail){
          console.log('Code', fail.c, 'for', fail.u, 'in');
          resources[fail.u].forEach(function(ref){
            console.log(' -', ref);
          });
        });

        assert.equal(ok+broken, length(resources));

        if (broken !== 0) {
          // avoid error trace
          process.exit(1);
        } else {
          cb();
        }
        if (webserver) {
          webserver.close();
        }
      }
    } // crawl end
  };
};
<commit_msg>Added 'var' in front of some implicitly defined variables, caused error after switching to es6.<commit_after>var Static = require('node-static');
var http = require('http');
var Spider = require('node-spider');
var assert = require('assert');
var config = require('./config.js');
var _ = require('lodash');

function length(obj) {
  var size = 0, key;
  for (key in obj) {
    if (obj.hasOwnProperty(key)) size++;
  }
  return size;
}

/**
 * Export closure, so that checkLinks can be used in gulp without
 * creating an anonymous function.
 *
 * @module.exports
 * @param {string} start URL where crawler should start looking for links.
 * @return {function} checkLinks Calling checkLinks will start crawling.
 */
module.exports = function(start) {
  /**
  * checkLinks crawls all pages and check that href and src attributes does
  * have a HTTP 200 response. It checks links outside the start domain, but
  * does _not_ crawl pages outside start.
  *
  * @param {function} cb Called when all links have been checked.
  */
  return function checkLinks(cb){
    console.log('Checking all links found at ' + start);
    var webserver;

    if (start.search('http://localhost') === 0) {
      // we need to start a web server
      var files = new Static.Server(config.buildRoot);
      webserver = http.createServer(function (request, response) {
        request.addListener('end', function () {
          files.serve(request, response);
        }).resume();
      });
      webserver.listen(3000, crawl);
    } else {
      crawl();
    }
    function crawl(){
      var resources = {};  // dict of referrers {link: [referrer1, referrer2, ..], link2..}
      resources[start] = ['start'];
      var failed = [];  // list of failed links
      var ok = 0;  // number of OK links
      var broken = 0;  // number of broken links

      var opts = {
        concurrent: 5,
        done: done,
        error: error,
        headers: { 'user-agent': 'codeclub_lesson_builder' },
        timeout: 5000
      };  // spider options

      // text spider for HTML, CSS, etc
      var textSpider = new Spider(opts);

      // HEAD requests on external sites and binary files
      var headOpts = _.assign({}, opts);
      headOpts.method = 'HEAD';
      var headSpider = new Spider(headOpts);

      // let's go! :-)
      textSpider.queue(start, parseResponse);

      /**
       * on OK link
       */
      function parseResponse(doc){
        // check status code
        var code = doc.res.statusCode;
        if (code !== 200 && this.opts.method === 'HEAD') {
          // try again with GET-method
          textSpider.queue(this.opts.url, parseResponse);
          return;
        }
        if (code !== 200) {
          process.stdout.write('x'); // give some feedback
          broken += 1;
          failed.push({u:doc.url, c:code});
          return;
        } else {
          ok += 1;
          process.stdout.write('.'); // give some feedback
        }

        // do not parse binary files
        if (!/text|css|json|xml/i.test(doc.res.headers['content-type'])) {
          return;
        }

        // only crawl links below start (not other domains)
        if (doc.url.search(start) === 0) {

          // all elements with href set
          doc.$('*[href]').each(queueUrl('href'));

          // all elements with src set
          doc.$('*[src]').each(queueUrl('src'));
        }

        /**
         * queueUrl closure
         */
        function queueUrl(type){
          return function(){
            var href = doc.$(this).attr(type);
            // do not add mailto and javascript links
            if (href.search(/^(mailto|javascript)/) === 0) {
              return;
            }
            // do not check #-link explicit
            var url = doc.resolve(href).split('#')[0];
            // already added
            if (url in resources) {
              // add referrer
              resources[url].push(doc.url);
              return;
            }
            // external sites or binaries
            if (url.search(start) !==0 ||
                url.search(/\.(jpg|png|gif|zip)$/) === 0) {
              headSpider.queue(url, parseResponse);
            } else {  // text, e.g., HTML, CSS, etc
              textSpider.queue(url, parseResponse);
            }
            // store referrer
            resources[url] = [doc.url];
          }
        }
      }

      /**
       * on broken link
       */
      function error(err, url) {
          process.stdout.write('!'); // give some feedback
          broken += 1;
          failed.push({u:url, c:err.code});
      }

      /**
       * print results and exit
       */
      function done() {
        // wait until both spiders are done
        if (textSpider.active.length !== 0 || headSpider.active.length !== 0) {
          return
        }

        console.log('\nLink check done');
        console.log('---------------');
        console.log('Links OK:', ok);
        console.log('Links broken:', broken);
        console.log('---------------');

        failed.forEach(function(fail){
          console.log('Code', fail.c, 'for', fail.u, 'in');
          resources[fail.u].forEach(function(ref){
            console.log(' -', ref);
          });
        });

        assert.equal(ok+broken, length(resources));

        if (broken !== 0) {
          // avoid error trace
          process.exit(1);
        } else {
          cb();
        }
        if (webserver) {
          webserver.close();
        }
      }
    } // crawl end
  };
};
<|endoftext|>


<commit_before>// Author: Artem Sapegin, http://sapegin.me, 2015

'use strict';

import 'fetch';

const UNICODE_MINUS = '\u2212';
const RETRY_INTERVAL = 5000;

class WeatherData {
	constructor() {
		this._cities = [];
	}

	subscribe(name, interval, onchange) {
		let cityId = this._cities.length;
		let city = {
			id: cityId,
			name: name,
			interval: interval,
			onchange: onchange
		};
		this._cities.push(city);
		this._fetch(cityId);
	}

	unsubscribe(name) {
		let cityId = this._getIdByName(name);
		let city = this._getCityById(cityId);
		if (city.timer) {
			clearTimeout(city.timer);
		}
		this._cities[city.id] = null;
	}

	_getCityById(cityId) {
		return this._cities[cityId];
	}

	_getIdByName(name) {
			for (let city of this._cities) {
			if (city && city.name === name) {
				return city.id;
			}
		}
	}

	_fetch(cityId) {
		let city = this._getCityById(cityId);
		fetch(this._getApiUrl(city.name))
			.then((res) => {
				return res.json();
			})
			.then((json) => {
				let response = this._parseResponse(json);
				this._emitChange(cityId, response);
				if (!response.error) {
					this._schedule(cityId);
				}
			})
			.catch(() => {
				this._emitError(cityId, 'Data cannot be loaded');
				this._schedule(cityId, RETRY_INTERVAL);
			});
	}

	_schedule(cityId, interval) {
		let city = this._getCityById(cityId);
		city.timer = setTimeout(this._fetch.bind(this, cityId), interval || city.interval);
	}

	_getApiUrl(name) {
		name = encodeURIComponent(name);
		return `http://api.openweathermap.org/data/2.5/weather?units=metric&q=${name}`;
	}

	_parseResponse(json) {
		if (json.cod === '404') {
			return {error: 'City not found.'};
		}

		return {
			temp: this._formatNumber(json.main.temp),
			humidity: json.main.humidity,
			sunrise: json.sys.sunrise,
			sunset: json.sys.sunset,
			windSpeed: json.wind.speed,
			conditions: json.weather[0].main,
			icon: json.weather[0].icon.replace(/[dn]$/, '')
		};
	}

	_formatNumber(number) {
		return String(Math.round(number)).replace(/^\-/, UNICODE_MINUS);
	}

	_emitChange(cityId, data) {
		let city = this._getCityById(cityId);
		if (city && city.onchange) {
			city.onchange(data);
		}
	}

	_emitError(cityId, message) {
		this._emitChange(cityId, {error: message});
	}
}

export default new WeatherData();
<commit_msg>Add APPID to access the openweathermap<commit_after>// Author: Artem Sapegin, http://sapegin.me, 2015

'use strict';

import 'fetch';

const UNICODE_MINUS = '\u2212';
const RETRY_INTERVAL = 5000;
const APPID = 'b1b15e88fa797225412429c1c50c122a';

class WeatherData {
	constructor() {
		this._cities = [];
	}

	subscribe(name, interval, onchange) {
		let cityId = this._cities.length;
		let city = {
			id: cityId,
			name: name,
			interval: interval,
			onchange: onchange
		};
		this._cities.push(city);
		this._fetch(cityId);
	}

	unsubscribe(name) {
		let cityId = this._getIdByName(name);
		let city = this._getCityById(cityId);
		if (city.timer) {
			clearTimeout(city.timer);
		}
		this._cities[city.id] = null;
	}

	_getCityById(cityId) {
		return this._cities[cityId];
	}

	_getIdByName(name) {
			for (let city of this._cities) {
			if (city && city.name === name) {
				return city.id;
			}
		}
	}

	_fetch(cityId) {
		let city = this._getCityById(cityId);
		fetch(this._getApiUrl(city.name))
			.then((res) => {
				return res.json();
			})
			.then((json) => {
				let response = this._parseResponse(json);
				this._emitChange(cityId, response);
				if (!response.error) {
					this._schedule(cityId);
				}
			})
			.catch(() => {
				this._emitError(cityId, 'Data cannot be loaded');
				this._schedule(cityId, RETRY_INTERVAL);
			});
	}

	_schedule(cityId, interval) {
		let city = this._getCityById(cityId);
		city.timer = setTimeout(this._fetch.bind(this, cityId), interval || city.interval);
	}

	_getApiUrl(name) {
		name = encodeURIComponent(name);
		return `http://api.openweathermap.org/data/2.5/weather?units=metric&q=${name}&appid=${APPID}`;
	}

	_parseResponse(json) {
		if (json.cod === '404') {
			return {error: 'City not found.'};
		}

		return {
			temp: this._formatNumber(json.main.temp),
			humidity: json.main.humidity,
			sunrise: json.sys.sunrise,
			sunset: json.sys.sunset,
			windSpeed: json.wind.speed,
			conditions: json.weather[0].main,
			icon: json.weather[0].icon.replace(/[dn]$/, '')
		};
	}

	_formatNumber(number) {
		return String(Math.round(number)).replace(/^\-/, UNICODE_MINUS);
	}

	_emitChange(cityId, data) {
		let city = this._getCityById(cityId);
		if (city && city.onchange) {
			city.onchange(data);
		}
	}

	_emitError(cityId, message) {
		this._emitChange(cityId, {error: message});
	}
}

export default new WeatherData();
<|endoftext|>